go: x/sys: invalid use of unsafe.Pointer in ioctl arg parameters
From the documentation of unsafe.Pointer:
(4) Conversion of a Pointer to a uintptr when calling syscall.Syscall.
The Syscall functions in package syscall pass their uintptr arguments directly to the operating system, which then may, depending on the details of the call, reinterpret some of them as pointers. That is, the system call implementation is implicitly converting certain arguments back from uintptr to pointer.
If a pointer argument must be converted to uintptr for use as an argument, that conversion must appear in the call expression itself
Now, as far as I can tell this forces packages to adhere to exactly that.
The code in x/sys clearly violates that rule.
in unix/ioctl.go there’s
// IoctlSetPointerInt performs an ioctl operation which sets an
// integer value on fd, using the specified request number. The ioctl
// argument is called with a pointer to the integer value, rather than
// passing the integer value directly.
func IoctlSetPointerInt(fd int, req uint, value int) error {
v := int32(value)
return ioctl(fd, req, uintptr(unsafe.Pointer(&v)))
}
and the declaration of ioctl in zsyskall_linux.go:
func ioctl(fd int, req uint, arg uintptr) (err error) {
_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
if e1 != 0 {
err = errnoErr(e1)
}
return
}
I’ve asked on the mailing list if that’s valid usage of unsafe, @ianlancetaylor wasn’t sure and told me to open an issue here for further discussion. (https://groups.google.com/g/golang-nuts/c/Ocpy8CKs7ZI/m/3ym8gnuBFgAJ)
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 1
- Comments: 20 (11 by maintainers)
Commits related to this issue
- unix: generate ioctlPtr on Linux with unsafe.Pointer arg The existing ioctl stubs for all UNIX-like platforms take a value of type uintptr for the arg parameter. However, arguments which are cast fro... — committed to golang/sys by mdlayher 3 years ago
- unix: add ioctlPtr with unsafe.Pointer arg on other unices This is a followup for CL 340915 that adds ioctlPtr for all other UNIX-like platforms. For golang/go#44834 Change-Id: I0ecf84e53f13e5a8da7... — committed to golang/sys by dmgk a year ago
- syscall: introduce IoctlPtr for exec_unix tests Avoid passing Go pointers as uintptr in exec_unix_test.go by introducing syscall.IoctlPtr() which accepts arg as unsafe.Pointer. For #44834 Fixes #586... — committed to golang/go by dmgk a year ago
- syscall: introduce IoctlPtr for exec_unix tests Avoid passing Go pointers as uintptr in exec_unix_test.go by introducing syscall.IoctlPtr() which accepts arg as unsafe.Pointer. For #44834 Fixes #586... — committed to Pryz/go by dmgk a year ago
- unix: add ioctlPtr with unsafe.Pointer arg on other unices (cont) CL 469315 missed a few conversions, this CL adds them. While here, also update syscall wrapper generators. For golang/go#44834 Chan... — committed to golang/sys by dmgk a year ago
I don’t think that code is safe.
The
ioctlfunction does not have any pragmas to mark it as a syscall function, so the compiler won’t know to do anything special for it. So the call toioctlcould potentially grow the stack, and then theargpointer would be stale pointing to old memory.I believe this is done, closing.
I believe the reason I didn’t close this before was because I only fixed it for Linux. Similar changes would have to be made for *BSD and etc.
Hmm, so, whether it violates unsafe pointer rule?
Maybe the right fix is passing in an unsafe.Pointer instead of an uintptr 🤔