Open R1kaB3rN opened 2 months ago
This is an interesting proposal but it comes with quite a big challenge. The reason it runs as a root daemon is the need to hide the original input devices from userspace apps to avoid duplicated input. The way we do this is by inserting a device specific udev rule into /run/udev that sets the original device's sysfs file descriptors to root only, then re-triggering udev on that device. This accomplishes two things:
1.) Blocks userspace applications from seeing the original device as they no longer have read permission for the device. 2.) It breaks IOCTL for applications that have already authenticated on the file descriptor.
breaking IOCTL is very important as there is no built-in way for us to inform IOCTL that permissions have changed. You can verify this yourself by opening a 777 permissions file as a regular user, then in a nother terminal changing the permissions to 400. You will still be able to write to the file until you close it.
The only other way that we've found to do both things is to move the file descriptors to /dev/input/.hidden and both approaches require root access to do so. Anything that alters or moves device nodes requires some sort of privilege escalation. Unfortunately polkit, sudoers, and gksudo are explicitly disabled by both bwrap and firejail, as SUID will fail, by design, from inside the jail no matter what.
One possibility might be to run a second nested jail inside the flatpak jail to filter the device nodes to only the ones provided by InputPlumber. I have no idea how difficult that would be or if it is even possible since running the jail also requires SUID, at least for firejail. I don't remember if bwrap uses SUID to start a jail.
Currently the only way I know how to do something similar to what you want without installing to the system is using systemd-ext packaging.
To expand on this, these are the different patterns we know about to hide the source input device from applications:
/run/udev
to block source input device (requires root). As mentioned, this is what we currently do in InputPlumber./dev/input/event0
) to another path to prevent applications from finding the device (requires root). This is what we used to do, but in some cases, applications would open the file descriptor before we could actually move the device, causing the app to read inputs from both the source device and the virtual input device.bwrap
(or similar sandbox) and only expose the virtual input devices that InputPlumber creates (no root required). This would theoretically work with all input implementations, but would also require launcher coordination so games are launched in a sandbox, and a secondary process would be responsible for exposing the virtual devices to the game's sandbox. I have tried doing this in the past, but could never get it to work correctly. My past attempts were trying to use bwrap
to create a fake /dev
directory that we could bind mount into the sandbox to selectively expose input devices, but I think the games just wouldn't see any input devices.We're open to other ideas if there's another technique we could use. Not the best solution, but one option could be to check if the InputPlumber service is available, and if not, the launcher could recommend to the user that they install InputPlumber through their package manager (or systemd extension).
Would a patch to upstream kernel be a solution to support this use case?
Description
I'm interested in making InputPlumber available for clients through umu-launcher to fill in the gap of users unable to have their game controllers work, with the goal of the service being started by the client or umu-launcher at game launch in an unprivileged context.
Problem
InputPlumber requires to be started and enabled as a privileged user to fulfill all of its tasks properly, making it both inaccessible for Flatpak applications and inconvenient as it would require clients to prompt their users for elevated privileges in the non-Flatpak case. Attempting to execute the
inputplumber
binary unprivileged results in:Due to this limitation, clients cannot simply run the binary like gamescope-dbus. As a result, users of popular launchers (e.g., Heroic Games Launcher) continue to depend on other clients or use other means to have control over their input devices (e.g., Steam Deck users adding a client app as a non-Steam game in Steam. In other cases, users may revert to using an old version of Wine due to their input devices being incorrectly mapped when running games through Proton.
Being able to run InputPlumber as an unprivileged user would avoid any manual intervention from the user or dependency on external apps to control their input devices.
Proposal
Support running InputPlumber as an unprivileged user or at least a subset of InputPlumber's feature set in that case. After bringing this up to @ShadowApex, they said it should theoretically be possible as long as there are polkits in place. However, the policies would need to be created and installed as the root user, making this only doable for distribution packages. I'm wondering if there's another way or if this feature is just impossible to support given the current design?
Any thoughts/suggestions on this are appreciated.