Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/sys: invalid use of unsafe.Pointer in ioctl arg parameters #44834

Closed
brunnre8 opened this issue Mar 6, 2021 · 20 comments
Closed

x/sys: invalid use of unsafe.Pointer in ioctl arg parameters #44834

brunnre8 opened this issue Mar 6, 2021 · 20 comments
Labels
help wanted NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@brunnre8
Copy link

brunnre8 commented Mar 6, 2021

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)

@gopherbot gopherbot added this to the Unreleased milestone Mar 6, 2021
@ianlancetaylor ianlancetaylor added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Mar 8, 2021
@cuonglm
Copy link
Member

cuonglm commented Apr 30, 2021

This is safe.

  • v will be kept alive through ioctl call.
  • The rule is only applied for pointer must be converted to uintptr, ioctl does uintptr(arg) where arg is an uintptr, not a pointer.

@cuonglm
Copy link
Member

cuonglm commented May 3, 2021

cc @mdempsky

@mdempsky
Copy link
Member

mdempsky commented May 3, 2021

I don't think that code is safe.

The ioctl function 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 to ioctl could potentially grow the stack, and then the arg pointer would be stale pointing to old memory.

@cuonglm
Copy link
Member

cuonglm commented May 3, 2021

I don't think that code is safe.

The ioctl function 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 to ioctl could potentially grow the stack, and then the arg pointer would be stale pointing to old memory.

Hmm, so, whether it violates unsafe pointer rule?

Maybe the right fix is passing in an unsafe.Pointer instead of an uintptr 🤔

@cuonglm
Copy link
Member

cuonglm commented May 3, 2021

Maybe the right fix is passing in an unsafe.Pointer instead of an uintptr 🤔

or using go:nosplit

@mdempsky
Copy link
Member

mdempsky commented May 3, 2021

Maybe the right fix is passing in an unsafe.Pointer instead of an uintptr

I think so. The Linux ioctl man page at least says that the third argument is always a pointer. (If there are any ioctls that do actually pass a scalar value directly instead of a pointer, they'll need a separate utility wrapper.)

@ianlancetaylor
Copy link
Contributor

@mdlayher added IoctlSetInt for Linux in https://golang.org/cl/44009 for #20474. That suggests that Linux has some ioctls that don't take a pointer value for the third argument, although off hand I do not know what they are.

@lhl2617
Copy link

lhl2617 commented May 9, 2021

@mdlayher added IoctlSetInt for Linux in https://golang.org/cl/44009 for #20474. That suggests that Linux has some ioctls that don't take a pointer value for the third argument, although off hand I do not know what they are.

From https://man7.org/linux/man-pages/man2/ioctl.2.html:

The third argument is an untyped pointer to memory

From https://docs.oracle.com/cd/E23824_01/html/821-1463/ioctl-2.html

The arg argument represents a third argument that has additional information that is needed by this specific device to perform the requested function. The data type of arg depends upon the particular control request, but it is either an int or a pointer to a device-specific data structure.

It thus seems like IoctlSetInt was made for solaris consistent with the description in #20474. It should never be used for linux.

@lhl2617
Copy link

lhl2617 commented May 9, 2021

Relevant issue: #34684

@gopherbot
Copy link

Change https://golang.org/cl/340915 mentions this issue: unix: generate ioctlNew on Linux with unsafe.Pointer arg

gopherbot pushed a commit to golang/sys that referenced this issue Aug 9, 2021
The existing ioctl stubs for all UNIX-like platforms take a value of type
uintptr for the arg parameter. However, arguments which are cast from
unsafe.Pointer to uintptr technically violate the rules for package unsafe.
unsafe only allows a conversion from unsafe.Pointer to uintptr directly
within a call to Syscall.

ioctl is used on all UNIX-like operating systems and each one will have
to be updated accordingly where pointer arguments are passed to system
calls. To remedy this on Linux, we generate a new function called
ioctlPtr which takes a value of type unsafe.Pointer for arg. More
operating systems can be updated in future CLs by folks who have access
to those systems and can run the appropriate code generator.

Updates golang/go#44834

Change-Id: Ia9424be424b3dba91bb44d3a7a12bfb2179f0d86
Reviewed-on: https://go-review.googlesource.com/c/sys/+/340915
Trust: Matt Layher <mdlayher@gmail.com>
Trust: Bryan C. Mills <bcmills@google.com>
Run-TryBot: Matt Layher <mdlayher@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
@mdlayher mdlayher changed the title x/sys: potential invalid use of unsafe x/sys: invalid use of unsafe.Pointer in ioctl arg parameters Aug 10, 2021
@bcmills
Copy link
Contributor

bcmills commented Feb 7, 2023

@mdempsky, @ianlancetaylor, @mdlayher: was this fixed by CL 340915, or is there more to do here?

@mdlayher
Copy link
Member

mdlayher commented Feb 7, 2023

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.

@thediveo
Copy link

thediveo commented Feb 7, 2023

@mdlayher added IoctlSetInt for Linux in https://golang.org/cl/44009 for #20474. That suggests that Linux has some ioctls that don't take a pointer value for the third argument, although off hand I do not know what they are.

Here we are, FICLONE https://man7.org/linux/man-pages/man2/ioctl_ficlonerange.2.html ... which I didn't knew existed a few moments ago 😁

@gopherbot
Copy link

Change https://go.dev/cl/469315 mentions this issue: unix: add ioctlPtr with unsafe.Pointer arg on other unices

@gopherbot
Copy link

Change https://go.dev/cl/469675 mentions this issue: syscall: avoid passing Go pointers as uintptr in exec tests

gopherbot pushed a commit to golang/sys that referenced this issue Feb 21, 2023
This is a followup for CL 340915 that adds ioctlPtr for all other
UNIX-like platforms.

For golang/go#44834

Change-Id: I0ecf84e53f13e5a8da736b3ba7f643262596d23c
Reviewed-on: https://go-review.googlesource.com/c/sys/+/469315
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Dmitri Goutnik <dgoutnik@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
@gopherbot
Copy link

Change https://go.dev/cl/469835 mentions this issue: unix: add ptracePtr that accepts pointer arg as unsafe.Pointer

gopherbot pushed a commit that referenced this issue Feb 21, 2023
Avoid passing Go pointers as uintptr in exec_unix_test.go by introducing
syscall.IoctlPtr() which accepts arg as unsafe.Pointer.

For #44834
Fixes #58609

Change-Id: I6d0ded023e5f3c9989783aee7075bb88100d9ec2
Reviewed-on: https://go-review.googlesource.com/c/go/+/469675
Run-TryBot: Dmitri Goutnik <dgoutnik@gmail.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
johanbrandhorst pushed a commit to Pryz/go that referenced this issue Feb 22, 2023
Avoid passing Go pointers as uintptr in exec_unix_test.go by introducing
syscall.IoctlPtr() which accepts arg as unsafe.Pointer.

For golang#44834
Fixes golang#58609

Change-Id: I6d0ded023e5f3c9989783aee7075bb88100d9ec2
Reviewed-on: https://go-review.googlesource.com/c/go/+/469675
Run-TryBot: Dmitri Goutnik <dgoutnik@gmail.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
@gopherbot
Copy link

Change https://go.dev/cl/471119 mentions this issue: unix: add ioctlPtr with unsafe.Pointer arg on other unices (cont)

gopherbot pushed a commit to golang/sys that referenced this issue Feb 24, 2023
CL 469315 missed a few conversions, this CL adds them. While
here, also update syscall wrapper generators.

For golang/go#44834

Change-Id: I4418a8c177ee6d1a269c1cc2c806b199dc7ccf0b
Reviewed-on: https://go-review.googlesource.com/c/sys/+/471119
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Run-TryBot: Dmitri Goutnik <dgoutnik@gmail.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
@bcmills
Copy link
Contributor

bcmills commented May 3, 2023

@dmgk, can this issue be closed now, or is there more work remaining for it?

@dmgk
Copy link
Member

dmgk commented May 3, 2023

I believe this is done, closing.

@dmgk dmgk closed this as completed May 3, 2023
@brunnre8
Copy link
Author

brunnre8 commented May 4, 2023

Thanks a lot to everyone involved

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

10 participants