On Mon, Dec 28, 2020 at 05:03:14PM -0700, Thomas Frohwein wrote:

> Hi,
> 
> This is a diff to propose a new device type for USB gamecontrollers,
> 'ujoy'.
> 
> Rationale
> ---------
> 
> Since the tightening of security around USB devices, USB
> gamecontrollers that generally attach to the kitchen-sink uhid device
> don't work out of the box anymore since read permissions are absent. As
> a consequence, USB gamecontrollers don't work out of the box anymore;
> requiring a root user to find what uhid device the controller is
> attached to and chmod +r that one. This poses a barrier to using those
> devices, as well as in my opinion a security risk by enticing users to
> indiscriminately do '# chmod +r /dev/uhid*' in order to not have to
> re-apply permissions on different uhid devices multiple times.
> 
> The proposed solution is inspired by the implementation of fido(4) [1];
> a similarly narrow use case for a certain type of USB devices. It
> creates a device for gamecontrollers that has the minimum required
> permissions, but won't require chmod(1)'ing device files to get the
> controller working.
> 
> Implementation in this Diff
> ---------------------------
> 
> This diff is largely based on reyk's commit for the fido(4) device from
> December 2019 [1]. It creates a ujoy device and attaches USB devices
> identified as HUG_JOYSTICK or HUG_GAME_PAD.
> 
> ujoyopen() is set up such that it only allows read-only access. If it is
> opened with write permissions, it should error with EPERM. Only a
> subset of ioctls is allowed in ujoyioctl(), based on what I could find 
> that is used in devel/sdl2 (USB_GET_DEVICEINFO,USB_GET_REPORT,
> USB_GET_REPORT_DESC,USB_GET_REPORT_ID), as well as FIONBIO and
> FIOASYNC.
> 
> This contains conf.c and MAKEDEV.md bits for the same architectures as
> fido(4). A small man page, as well as updates to other pertinent man
> pages (usb(4), uhidev(4)) are included, again following the example of
> the commits for the fido(4) device.
> 
> Credit to brynet@ who helped me extensively with this diff.
> 
> Testing
> -------
> 
> A simple way to test this without needing to do a full release is
> building a kernel with the diff and booting into it, then creating the
> updated MAKEDEV script with:
> 
> $ cd /usr/src/etc/etc.amd64/
> $ make                                # this will create MAKEDEV in etc.amd64
> $ cd /dev
> # sh /usr/src/etc/etc.amd64/MAKEDEV ujoy
> 
> This creates 2 device ujoy/0 and ujoy/1 by default. The device is
> read-only by default (444).
> 
> Plug in your USB gamecontroller and check in dmesg that it attaches as
> ujoy, not uhid.
> 
> The simplest way to test is with usbhidctl(1):
> 
> $ usbhidctl -f /dev/ujoy/0 -l
> 
> This will loop through printing the state of buttons, sticks etc. until
> exited with Crtl-C.
> 
> Another way to test is with games/sdl-jstest. As the SDL backends use
> /dev/uhid* to find gamecontrollers, the way I tested this is by
> repurposing /dev/uhid0 with mknod(8) (note major 100 is for amd64):
> 
> $ cd /dev
> # rm uhid0
> # mknod -m 444 uhid0 c 100 0
> 
> I put the diff through a release(8) without xenocara on amd64, and it
> built base without problems and /dev/MAKEDEV and the /dev/ujoy directory
> all look correct.
> 
> I have tested usbhidctl and sdl-jstest with an XBox 360 gamepad and the
> Logitech F310 gamepad, the latter both in DInput and XInput mode. All
> of those work as expected.
> 
> Issues/Follow-up Tasks
> ----------------------
> 
> As ujoy devices don't attach to /dev/uhid* anymore, ports that use
> gamecontrollers will need to be patched. This seems to be mostly (if
> not exclusively) sdl/sdl2-based ports, so I anticipate that patching
> these 2 ports will take care of the bulk of the use cases.
> 
> On other OS's, writing to gamecontrollers is used at times for the
> "rumble" functionality of the controller, or setting LEDs (like the
> circle LED on XBox 360 controllers that can reflect what player number
> the gamepad is for). Those have to my knowledge never worked on OpenBSD
> and are not of any immediate interest as far as I can tell.
> 
> ok? comments?

The implementation as such looks fine to me.
But I quickly gave the diff a spin before on amd64 using my PS
controller, and the result is not what I would expect.

With uhid, I can access the controller on /dev/uhid6.  The attach looks
like this:

imac /bsd: uaudio0 at uhub4 port 4 configuration 1 interface 1 "Sony
Interactive Entertainment Wireless Controller" rev 2.00/1.00 addr 6
imac /bsd: uaudio0: class v1, full-speed, sync, channels: 2 play, 1 rec,
4 ctls
imac /bsd: audio1 at uaudio0
imac /bsd: uhidev6 at uhub4 port 4 configuration 1 interface 3 "Sony
Interactive Entertainment Wireless Controller" rev 2.00/1.00 addr 6
imac /bsd: uhidev6: iclass 3/0, 180 report ids
imac /bsd: uhid6 at uhidev6 reportid 1: input=63, output=0, feature=0
imac /bsd: uhid7 at uhidev6 reportid 2: input=0, output=0, feature=36
imac /bsd: uhid8 at uhidev6 reportid 4: input=0, output=0, feature=36
imac /bsd: uhid9 at uhidev6 reportid 5: input=0, output=31, feature=0
imac /bsd: uhid10 at uhidev6 reportid 8: input=0, output=0, feature=3
imac /bsd: uhid11 at uhidev6 reportid 16: input=0, output=0, feature=4
imac /bsd: uhid12 at uhidev6 reportid 17: input=0, output=0, feature=2
imac /bsd: uhid13 at uhidev6 reportid 18: input=0, output=0, feature=15
imac /bsd: uhid14 at uhidev6 reportid 19: input=0, output=0, feature=22
imac /bsd: uhid15 at uhidev6 reportid 20: input=0, output=0, feature=16
imac /bsd: uhid16 at uhidev6 reportid 21: input=0, output=0, feature=44
imac /bsd: uhid17 at uhidev6 reportid 128: input=0, output=0, feature=6
imac /bsd: uhid18 at uhidev6 reportid 129: input=0, output=0, feature=6
imac /bsd: uhid19 at uhidev6 reportid 130: input=0, output=0, feature=5
imac /bsd: uhid20 at uhidev6 reportid 131: input=0, output=0, feature=1
imac /bsd: uhid21 at uhidev6 reportid 132: input=0, output=0, feature=4
imac /bsd: uhid22 at uhidev6 reportid 133: input=0, output=0, feature=6
imac /bsd: uhid23 at uhidev6 reportid 134: input=0, output=0, feature=6
imac /bsd: uhid24 at uhidev6 reportid 135: input=0, output=0, feature=35
imac /bsd: uhid25 at uhidev6 reportid 136: input=0, output=0, feature=34
imac /bsd: uhid26 at uhidev6 reportid 137: input=0, output=0, feature=2
imac /bsd: uhid27 at uhidev6 reportid 144: input=0, output=0, feature=5
imac /bsd: uhid28 at uhidev6 reportid 145: input=0, output=0, feature=3
imac /bsd: uhid29 at uhidev6 reportid 146: input=0, output=0, feature=3
imac /bsd: uhid30 at uhidev6 reportid 147: input=0, output=0, feature=12
imac /bsd: uhid31 at uhidev6 reportid 160: input=0, output=0, feature=6
imac /bsd: uhid32 at uhidev6 reportid 161: input=0, output=0, feature=1
imac /bsd: uhid33 at uhidev6 reportid 162: input=0, output=0, feature=1
imac /bsd: uhid34 at uhidev6 reportid 163: input=0, output=0, feature=48
imac /bsd: uhid35 at uhidev6 reportid 164: input=0, output=0, feature=13
imac /bsd: uhid36 at uhidev6 reportid 165: input=0, output=0, feature=21
imac /bsd: uhid37 at uhidev6 reportid 166: input=0, output=0, feature=21
imac /bsd: uhid38 at uhidev6 reportid 167: input=0, output=0, feature=1
imac /bsd: uhid39 at uhidev6 reportid 168: input=0, output=0, feature=1
imac /bsd: uhid40 at uhidev6 reportid 169: input=0, output=0, feature=8
imac /bsd: uhid41 at uhidev6 reportid 170: input=0, output=0, feature=1
imac /bsd: uhid42 at uhidev6 reportid 171: input=0, output=0, feature=57
imac /bsd: uhid43 at uhidev6 reportid 172: input=0, output=0, feature=57
imac /bsd: uhid44 at uhidev6 reportid 173: input=0, output=0, feature=11
imac /bsd: uhid45 at uhidev6 reportid 174: input=0, output=0, feature=1
imac /bsd: uhid46 at uhidev6 reportid 175: input=0, output=0, feature=2
imac /bsd: uhid47 at uhidev6 reportid 176: input=0, output=0, feature=63
imac /bsd: uhid48 at uhidev6 reportid 177: input=0, output=0, feature=2
imac /bsd: uhid49 at uhidev6 reportid 178: input=0, output=0, feature=2
imac /bsd: uhid50 at uhidev6 reportid 179: input=0, output=0, feature=63
imac /bsd: uhid51 at uhidev6 reportid 180: input=0, output=0, feature=63

ujoy instead attached to previous uhid51, and there it is of no use
obviously.  I still can access the controller through uhid6.  The attach
with ujoy looks like this:

imac /bsd: uaudio0 at uhub4 port 4 configuration 1 interface 1 "Sony
Interactive Entertainment Wireless Controller" rev 2.00/1.00 addr 6
imac /bsd: uaudio0: class v1, full-speed, sync, channels: 2 play, 1 rec,
4 ctls
imac /bsd: audio1 at uaudio0
imac /bsd: uhidev6 at uhub4 port 4 configuration 1 interface 3 "Sony
Interactive Entertainment Wireless Controller" rev 2.00/1.00 addr 6
imac /bsd: uhidev6: iclass 3/0, 180 report ids
imac /bsd: uhid6 at uhidev6 reportid 1: input=63, output=0, feature=0
imac /bsd: uhid7 at uhidev6 reportid 2: input=0, output=0, feature=36
imac /bsd: uhid8 at uhidev6 reportid 4: input=0, output=0, feature=36
imac /bsd: uhid9 at uhidev6 reportid 5: input=0, output=31, feature=0
imac /bsd: uhid10 at uhidev6 reportid 8: input=0, output=0, feature=3
imac /bsd: uhid11 at uhidev6 reportid 16: input=0, output=0, feature=4
imac /bsd: uhid12 at uhidev6 reportid 17: input=0, output=0, feature=2
imac /bsd: uhid13 at uhidev6 reportid 18: input=0, output=0, feature=15
imac /bsd: uhid14 at uhidev6 reportid 19: input=0, output=0, feature=22
imac /bsd: uhid15 at uhidev6 reportid 20: input=0, output=0, feature=16
imac /bsd: uhid16 at uhidev6 reportid 21: input=0, output=0, feature=44
imac /bsd: uhid17 at uhidev6 reportid 128: input=0, output=0, feature=6
imac /bsd: uhid18 at uhidev6 reportid 129: input=0, output=0, feature=6
imac /bsd: uhid19 at uhidev6 reportid 130: input=0, output=0, feature=5
imac /bsd: uhid20 at uhidev6 reportid 131: input=0, output=0, feature=1
imac /bsd: uhid21 at uhidev6 reportid 132: input=0, output=0, feature=4
imac /bsd: uhid22 at uhidev6 reportid 133: input=0, output=0, feature=6
imac /bsd: uhid23 at uhidev6 reportid 134: input=0, output=0, feature=6
imac /bsd: uhid24 at uhidev6 reportid 135: input=0, output=0, feature=35
imac /bsd: uhid25 at uhidev6 reportid 136: input=0, output=0, feature=34
imac /bsd: uhid26 at uhidev6 reportid 137: input=0, output=0, feature=2
imac /bsd: uhid27 at uhidev6 reportid 144: input=0, output=0, feature=5
imac /bsd: uhid28 at uhidev6 reportid 145: input=0, output=0, feature=3
imac /bsd: uhid29 at uhidev6 reportid 146: input=0, output=0, feature=3
imac /bsd: uhid30 at uhidev6 reportid 147: input=0, output=0, feature=12
imac /bsd: uhid31 at uhidev6 reportid 160: input=0, output=0, feature=6
imac /bsd: uhid32 at uhidev6 reportid 161: input=0, output=0, feature=1
imac /bsd: uhid33 at uhidev6 reportid 162: input=0, output=0, feature=1
imac /bsd: uhid34 at uhidev6 reportid 163: input=0, output=0, feature=48
imac /bsd: uhid35 at uhidev6 reportid 164: input=0, output=0, feature=13
imac /bsd: uhid36 at uhidev6 reportid 165: input=0, output=0, feature=21
imac /bsd: uhid37 at uhidev6 reportid 166: input=0, output=0, feature=21
imac /bsd: uhid38 at uhidev6 reportid 167: input=0, output=0, feature=1
imac /bsd: uhid39 at uhidev6 reportid 168: input=0, output=0, feature=1
imac /bsd: uhid40 at uhidev6 reportid 169: input=0, output=0, feature=8
imac /bsd: uhid41 at uhidev6 reportid 170: input=0, output=0, feature=1
imac /bsd: uhid42 at uhidev6 reportid 171: input=0, output=0, feature=57
imac /bsd: uhid43 at uhidev6 reportid 172: input=0, output=0, feature=57
imac /bsd: uhid44 at uhidev6 reportid 173: input=0, output=0, feature=11
imac /bsd: uhid45 at uhidev6 reportid 174: input=0, output=0, feature=1
imac /bsd: uhid46 at uhidev6 reportid 175: input=0, output=0, feature=2
imac /bsd: uhid47 at uhidev6 reportid 176: input=0, output=0, feature=63
imac /bsd: uhid48 at uhidev6 reportid 177: input=0, output=0, feature=2
imac /bsd: uhid49 at uhidev6 reportid 178: input=0, output=0, feature=2
imac /bsd: uhid50 at uhidev6 reportid 179: input=0, output=0, feature=63
imac /bsd: ujoy0 at uhidev6 reportid 180: input=0, output=0, feature=63

I haven't analyzed yet what happens in the code.
I can provide an lsusb of the controller if it's more obvious to you.

Reply via email to