Bug 218625

Summary: [PATCH] Evdev ioctls EVIOCGRAB and EVIOCREVOKE don't work together with cuse
Product: Base System Reporter: Jan Kokemüller <jan.kokemueller>
Component: kernAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed Works As Intended    
Severity: Affects Only Me CC: gonzo, wulf
Priority: --- Keywords: patch
Version: CURRENT   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
patch to change type of EVIOCGRAB and EVIOCREVOKE ioctls to _IO none

Description Jan Kokemüller 2017-04-13 10:45:01 UTC
Created attachment 181752 [details]
patch to change type of EVIOCGRAB and EVIOCREVOKE ioctls to _IO

EVIOCGRAB and EVIOCREVOKE from dev/evdev/input.h are defined as _IOWINT.
Those ioctls don't actually write an integer, though. What matters is the value of the data pointer. Cuse, however, only passes along the value of the data pointer when the length of the ioctl is 0 (see https://github.com/freebsd/freebsd/blob/master/sys/fs/cuse/cuse.c#L1669).

One solution would be to define those two ioctls as _IO (see attached patch). I've tested this with my cuse-based evdev implementation (https://github.com/jiixyj/evdevfbsd).
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2017-04-13 19:06:15 UTC
Notify committer of original file.
Comment 2 Vladimir Kondratyev freebsd_committer freebsd_triage 2017-04-17 12:19:17 UTC
(In reply to Jan Kokemüller from comment #0)
> Cuse, however, only passes along the value of the data
> pointer when the length of the ioctl is 0

Hopefully, this have been fixed with r302381
https://svnweb.freebsd.org/base?view=revision&revision=302381
Comment 3 Jan Kokemüller 2017-04-17 12:48:12 UTC
(In reply to Vladimir Kondratyev from comment #2)

This doesn't fix the issue, sadly.

With the current definition of EVIOCGRAB, when you do something like this on a cuse-based Evdev device:

ioctl(dev->fd, EVIOCGRAB, (void *)1);  /* grab device */
ioctl(dev->fd, EVIOCGRAB, (void *)0);  /* ungrab device */

...both times you get 10000 (CUSE_BUF_MIN_PTR) inside the ioctl handler. So you cannot ungrab a device again. The value 10000 comes from here:
https://github.com/freebsd/freebsd/blob/master/sys/fs/cuse/cuse.c#L1676

I don't know if this is cuse specific behavior, or if FreeBSD in general behaves like this.
Comment 4 Vladimir Kondratyev freebsd_committer freebsd_triage 2017-04-17 13:06:13 UTC
(In reply to Jan Kokemüller from comment #3)
> I don't know if this is cuse specific behavior,
> or if FreeBSD in general behaves like this.

IOWINT ioctl passes int value in internal buffer and provide pointer to that buffer to handler exactly like IOW(NNN, ###, int)

Following is IOWINT->IO convertor from webcamd internals, AFAIR, it is working:

        /*
         * Copy in the _IOWINT parameter and pass it as arg pointer
         * similar to what Linux is doing:
         */
        if ((cmd & IOC_DIRMASK) == IOC_VOID && IOCPARM_LEN(cmd) == sizeof(int)) {
                if (copy_from_user(&iowint, arg, sizeof(iowint)) != 0) {
                        retval = -EFAULT;
                        goto done;
                }
                arg = (void *)(intptr_t)iowint;
        }
Comment 5 Jan Kokemüller 2017-04-17 14:33:43 UTC
Great, this works! Thank you for the hint.