Page MenuHomeFreeBSD

linuxkpi ioctl handler: restore the user data pointer
ClosedPublic

Authored by kib on Tue, Jun 16, 10:16 PM.
Tags
None
Referenced Files
F162588575: D57612.diff
Tue, Jul 14, 8:13 PM
Unknown Object (File)
Mon, Jul 6, 6:22 AM
Unknown Object (File)
Sun, Jul 5, 9:17 PM
Unknown Object (File)
Sun, Jul 5, 2:35 PM
Unknown Object (File)
Sun, Jul 5, 6:46 AM
Unknown Object (File)
Sat, Jul 4, 6:08 AM
Unknown Object (File)
Fri, Jul 3, 1:36 PM
Unknown Object (File)
Fri, Jul 3, 12:38 PM

Details

Summary
instead of trying to hack around it with LINUX_IOCTL_MIN_PTR.  Since
linux file ioctl methods expect the user address in the data argument,
this should work for all ioctls, including the variable-length cases
like ibcore.

Only do it for the FreeBSD ABI, where we know how to reliably access the
original syscall arguments.

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

kib requested review of this revision.Tue, Jun 16, 10:16 PM

Hi, I think this is a good change overall. I actually tried to solve the same problem before in D55328, but I ended up abandoning it because my use case no longer required it.

However, I see a couple of issues with this revision:

  • For IOC_IN, sys_ioctl does one copyin, but your patch bypasses it, so there is the cost of two copyin operations. (It's not a performance bottleneck, so I think maybe it's ok.)
  • For IOC_OUT: sys_ioctl always performs a final copyout after the driver returns. If you give the driver the raw user-space pointer, then whatever the driver writes directly to userspace will be overwritten by that final copyout from the kernel buffer.

Hi, I think this is a good change overall. I actually tried to solve the same problem before in D55328, but I ended up abandoning it because my use case no longer required it.

However, I see a couple of issues with this revision:

  • For IOC_IN, sys_ioctl does one copyin, but your patch bypasses it, so there is the cost of two copyin operations. (It's not a performance bottleneck, so I think maybe it's ok.)

Yes it does not matter.

  • For IOC_OUT: sys_ioctl always performs a final copyout after the driver returns. If you give the driver the raw user-space pointer, then whatever the driver writes directly to userspace will be overwritten by that final copyout from the kernel buffer.

Right, we discussed this internally and then decided that it does not matter for RDMA_VERBS_IOCTL, but it must be worked around for the generic case.

Copy-in the user data to make sys_generic.c ioctl code copy-out identical content, for OUT ioctls.

sys/compat/linuxkpi/common/src/linux_compat.c
1002

Did you mean error1 == 0 here?

kib marked an inline comment as done.

Fix thinko.

I verified the changes by running these test applications:
ibv_rc_pingpong; ibv_uc_pingpong; ibv_ud_pingpong; ibv_srq_pingpong; ibv_xsrq_pingpong
All are passing.

This revision is now accepted and ready to land.Tue, Jun 23, 11:35 AM
sys/compat/linuxkpi/common/src/linux_compat.c
956

Should we make sure that this is a userspace thread before accessing td->td_sa? I am wondering if it's possible for a kernel thread to invoke fo_ioctl without coming from userspace.

1003

Can't you just copyin() directly to task->bsd_ioctl_data?

error1 is not returned to the caller.

kib marked 2 inline comments as done.Tue, Jun 23, 2:01 PM
kib added inline comments.
sys/compat/linuxkpi/common/src/linux_compat.c
1003

I wanted to make the copying to bsd_ioctl_data more 'atomic'. If copyin failed, which could happen in theory for variadic ioctls, I do not want to touch bsd_ioctl_data. Doing copyin directly to it causes partial coping.

Yes, error1 is intentionally not propagated anywhere.

kib marked an inline comment as done.

Check for !TDP_KTHREAD.

Additionally we could check that the vmspace is usermode, e.g. by checking the flag, but I believe that TDP_KTHREAD is good enough.

This revision now requires review to proceed.Tue, Jun 23, 2:10 PM
sys/compat/linuxkpi/common/src/linux_compat.c
939–951

This comment is confusing now. I'd write something more verbose:

/*
 * Background: Linux kernel code expects to operate on userspace addresses, but FreeBSD's kern_ioctl() will generally provide a kernel address. For the native process ABI, where we know how to find the original address, we reach directly into the system call args to get it. Then, if the Linux driver copied out to that address, we copy the whole block back into the kernel buffer allocated by kern_ioctl() so that kern_ioctl() itself doesn't clobber the driver's data.
*
* Otherwise, fall back to the LINUX_IOCTL_MIN_PTR hack.
*/
1003

I think the comment should explain this.

kib marked 2 inline comments as done.

Rewrite comments.

markj added inline comments.
sys/compat/linuxkpi/common/src/linux_compat.c
1000
1001
This revision is now accepted and ready to land.Tue, Jun 23, 8:35 PM
kib marked 2 inline comments as done.Tue, Jun 23, 9:02 PM