# udev rules for the punktfunk streaming host (mirrors Sunshine's 60-sunshine.rules). # # Grants the `input` group access to /dev/uinput (virtual X-Box-360 gamepads) and /dev/uhid # (virtual DualSense via the kernel hid-playstation driver — LED, adaptive triggers, touchpad, # gyro). `static_node` makes the nodes exist before their modules load. # # Install: # sudo cp scripts/60-punktfunk.rules /etc/udev/rules.d/ # sudo usermod -aG input $USER # then re-login (or reboot) # sudo udevadm control --reload-rules && sudo udevadm trigger KERNEL=="uinput", SUBSYSTEM=="misc", OPTIONS+="static_node=uinput", GROUP="input", MODE="0660", TAG+="uaccess" KERNEL=="uhid", SUBSYSTEM=="misc", OPTIONS+="static_node=uhid", GROUP="input", MODE="0660", TAG+="uaccess" # usbip vhci attach/detach for the virtual Steam Deck controller. Steam Input only # adopts the virtual Deck when it arrives as a USB device (usbip/vhci or raw_gadget); # the UHID fallback has no USB interface and Steam ignores it. The sysfs attach files # are root-only by default while the host runs as a user service — grant the dedicated # `punktfunk` group write when vhci_hcd appears (module autoload: modules-load.d/punktfunk.conf). # # ⚠ This is deliberately NOT the `input` group (2026-08-05 review M-4). Writing `attach` hands the # kernel a caller-supplied socket fd and materialises an arbitrary, fully userspace-emulated USB # device — a root-only kernel primitive. Every packaging scriptlet tells the user to # `usermod -aG input $USER` as step 1, so putting it on `input` handed that primitive to a group # people are routinely told to join: a member could present a HID keyboard and inject keystrokes # into a root TTY or the lock screen, or drive any of hundreds of in-tree USB drivers from # userspace, all without CAP_SYS_ADMIN. The uinput/uhid grants above are already systemwide input # injection, but neither reaches kernel USB enumeration — this one does, so it gets its own group # that nothing else asks users to join. ACTION=="add", SUBSYSTEM=="platform", KERNEL=="vhci_hcd.*", RUN+="/bin/sh -c 'chgrp punktfunk /sys%p/attach /sys%p/detach && chmod 0660 /sys%p/attach /sys%p/detach'" # hidraw access for the VIRTUAL pads this host creates. Steam/SDL drive a DualSense's rich # feedback (adaptive triggers, lightbar, player LEDs) exclusively over hidraw — the kernel has no # evdev API for any of it — and Steam without hidraw demotes a PlayStation pad to a generic evdev # device, losing its rumble handling too. hidraw nodes are root-only by default; the distro's # steam-devices rules + logind's uaccess ACL cover only the active seat session, so a game # launched outside it (a headless/dedicated streaming session) is silently feedback-dead. # GROUP="input" makes access follow the same group the host itself already requires. # KERNELS matches the HID device name (works for UHID devices, which have no USB parent); # the ATTRS pair covers the usbip/gadget Deck, which IS a (virtual) USB device. # DualSense (054C:0CE6) / DualSense Edge (054C:0DF2) / DualShock 4 (054C:09CC) KERNEL=="hidraw*", KERNELS=="*054C:0CE6*", GROUP="input", MODE="0660", TAG+="uaccess" KERNEL=="hidraw*", KERNELS=="*054C:0DF2*", GROUP="input", MODE="0660", TAG+="uaccess" KERNEL=="hidraw*", KERNELS=="*054C:09CC*", GROUP="input", MODE="0660", TAG+="uaccess" # Switch Pro Controller (057E:2009) — SDL's hidapi driver wants hidraw for rumble/LEDs too KERNEL=="hidraw*", KERNELS=="*057E:2009*", GROUP="input", MODE="0660", TAG+="uaccess" # Steam Deck (28DE:1205) / classic Steam Controller (28DE:1102), UHID and usbip/gadget forms KERNEL=="hidraw*", KERNELS=="*28DE:1205*", GROUP="input", MODE="0660", TAG+="uaccess" KERNEL=="hidraw*", KERNELS=="*28DE:1102*", GROUP="input", MODE="0660", TAG+="uaccess" KERNEL=="hidraw*", ATTRS{idVendor}=="28de", ATTRS{idProduct}=="1205", GROUP="input", MODE="0660", TAG+="uaccess" KERNEL=="hidraw*", ATTRS{idVendor}=="28de", ATTRS{idProduct}=="1102", GROUP="input", MODE="0660", TAG+="uaccess"