SDL
SDL copied to clipboard
KMS/DRM backend leaves me stuck with no input, forced to hard-reset machine
I compiled https://github.com/libsdl-org/SDL/commit/32f909f7e36a270d3b761bf15d320906ecd31eb1 hoping to be able to test out the KMS/DRM driver. configure-output.txt config.log.txt
Then I launched my test program with SDL_VIDEODRIVER=kmsdrm on a TTY. While it rendered fine, even with an accelerated SDL_Renderer if desired, none of keyboards and mouse/touchpad worked (it was a laptop with desktop peripherals attached, I tested both external and internal input devices). I was essentially stuck in the application with no way to interact with it or leave, while its animated opening scene rendered fine with no lag. Inside the regular GNOME 3 desktop, I can interact with it just fine.
@ell1e That's because you need to modify certain dev nodes permissions (nodes creates by udev) so normal users can access these. So create something like /etc/udev/rules.d/99-evdev.rules with this content:
KERNEL=="event*", NAME="input/%k", MODE="666"
And now you can reboot or do:
sudo udevadm control --reload-rules
sudo chmod 666 /dev/input/event*
And ready you go. Happy KMSDRM-ing!
Is that safe? Why aren't these accessible by default if it is? Is there a way to limit it to just that process? Seems a bit like ripping the apartment door out instead of giving one specific friend a spare key, my apologies if I'm misunderstanding what this does.
Edit: also, wouldn't it make sense if SDL somehow tested this and didn't enable KMS video mode if these things are not accessible? Because an initialization error would be tons better than what happens currently, which is I get just stuck in the program with zero explanation as to why.
@ell1e I get your point, but I don't think modifying these udev rules is a risk. It's also required for RetroArch to operate directly on KMSDRM with udev input, so every distro you see around RetroArch (such as Lakka, EmuELEC, and a LOOONG etc) must have these permissions set so users can access the udev nodes. Even LibreELEC (KODI distro) must have this setup for normal user to access the udev nodes.
After all, all you're doing is allow local users to access the same inputs they already have access to on a TTY, using the udev interface from within programs. Pretty much harmless I think.
Why does Raspberry Pi OS (Debian in general) have this set by default? No idea. And about SDL2 detecting you have no access to udev nodes... well, it's not SDL2 problem really.
RetroArch and multimedia center distros are made for gaming and single user kiosk mode, not as a secure generic multiuser system. So these are a poor indication for secure defaults, IMHO. Does it for example enable keyloggers/circumvent the security of improved technology like Flatpak+Wayland, maybe? That would be a good reason to not apply these udev rules, and to not just blindly recommend doing so.
And about SDL2 detecting you have no access to udev nodes... well, it's not SDL2 problem really.
I don't understand, isn't it SDL2 trying to access these nodes to process the input? (And failing, hence there is none?)
I will leave this conversation here. Maybe someone with more knowledge and interest on security concerns can help. Good luck!
Sorry, I suppose I derailed it a bit. To focus on the relevant, isn't there a way SDL2 could detect this situation or is that technically not reliably possible in some distro independent way? I think e.g. an error when creating the SDL_Window with the KMS backend with incorrect input permission would be more useful than just going ahead, if that is at all feasible. This would prevent users from getting stuck, since the average app would print an error and leave a clue something still needs setting up.
Input device permissions are restrictive by default to prevent things like keyloggers from being able to open input devices and snoop on key presses - think something like a non-root attacker connected via SSH reading the keyboard device and getting key events from a root user at the console.
I think it should be feasible to implement the safety that you mention. Perhaps if SDL fails to open any input device, we could fail the KMSDRM backend init (with an override like we did with SDL_HINT_KMSDRM_REQUIRE_DRM_MASTER).
I think it should be feasible to implement the safety that you mention. Perhaps if SDL fails to open any input device, we could fail the KMSDRM backend init (with an override like we did with SDL_HINT_KMSDRM_REQUIRE_DRM_MASTER).
I like the idea of a hint, SDL_HINT_KMSDRM_REQUIRE_INPUT_ACCESS maybe? Might maybe default to "1", and any non-interactive thing (that is fine with trapping the user without input, like maybe some endless advertisement animation thing or something) could then set it to "0".
Is that safe? Why aren't these accessible by default if it is? Is there a way to limit it to just that process? Seems a bit like ripping the apartment door out instead of giving one specific friend a spare key, my apologies if I'm misunderstanding what this does.
Usually the input group is given (via udev rules) access to the input system:
SUBSYSTEM=="input", GROUP="input", MODE="0660"
Isn't this similar to how the user being part of the video group grants them access to the /dev/dri/card* so they're able to use KMSDRM ?
Fwiw, my system has both input and video groups, and my user is in neither. KMSDRM worked on the TTY anyway. Don't ask me why, I'm pretty new to this KMSDRM thing! But input devices then don't.
@ell1e Maybe the permissions on the /dev/dri/card* are enough for your regular user to initialize DSM and use it.
If you change the permissions on /dev/input/event* so the SDL program user has RW access the them, do you still experience the issue ?
Maybe the permissions on the /dev/dri/card* are enough
Doesn't look like they are which is fascinating:
$ ls -la /dev/dri
total 0
drwxr-xr-x. 3 root root 100 Oct 5 15:14 .
drwxr-xr-x. 20 root root 4400 Oct 9 22:22 ..
drwxr-xr-x. 2 root root 80 Oct 5 15:14 by-path
crw-rw----+ 1 root video 226, 0 Oct 5 15:14 card0
crw-rw-rw-. 1 root render 226, 128 Oct 5 15:14 renderD128
edit: seems like it works somehow through this renderD128 thing. And when I'm inside gnome-shell SDL2 says there is no KMSDRM available, so I guess there is some sort of exclusivity access to ensure a rogue app can't just render on top of everything unasked...? So I guess that's fine security-wise then, or what do I know
If you change the permissions [...] do you still experience the issue ?
Running the program as root fixes it. So it's for sure the input permission issue. I think if SDL2 detected that it'd be a great safety check to not get trapped.
Just add your user to the input group (as well as the video and eventually render groups)
@substring my apologies, but your comment does seem to kind of miss the points brought up. In any case, the only really actionable thing for SDL2 is a better error message instead of leaving people stuck with no input, if possible.
AFAIK, SDL doesn't directly check/read the input devices when using KMSDRM, but relies on udev to enumerate and receive events from them (but see also #4727). Not sure what's the consensus (from the point of view of how udev is packaged)
The input subsystem (in this case, when using KMSDRM) supports hotpluging, so SDL can start without any input device attached and then add them as they become available. I don't think SDL would be able to distinguish between no access to input devices because of permissions and no input device is currently available, but may be added later. At best, a warning can be added so that the user is aware that no devices are available when the the subsystem is initialized, but I think it's better left for the caller to decide whether they want any warning to be issued if no input devices are available on startup or just outright stop.
@substring my apologies, but your comment does seem to kind of miss the points brought up. In any case, the only really actionable thing for SDL2 is a better error message instead of leaving people stuck with no input, if possible.
Your point is very true, but it won't still solve your problem. @cmitu shed some light on the SDL2 internals regarding udev and devices permissions, and as you've guessed: all in all it's an OS permission problem that can't be solved at SDL2 level. If SDL2 shouldn't start if no inputs are available, that's a very arguable topic.
As I've faced your problem in the past, what I've suggested works. Going the udev rule is a more complex way to achieve the same goal.
So what about a hint SDL_HINT_KMSDRM_REQUIRE_INPUT_DEVICE? If set to "1" and the SDL input system was initialized, the KMS video driver would require 1+ input devices on SDL_CreateWindow, or fail window creation. Does that sound like a useful suggestion?
Fwiw, @ what I've suggested works: nobody really disputed that.
Does that sound like a useful suggestion?
As a casual SDL consumer, not really. I can think of cases when a maintainer/deployer might want to force this check (i.e. input should be present) regardless of whether the application has a check for input, but overall I don't think this type of hint would be that useful to warrant its addition in SDL.
As a casual SDL consumer
Not sure what you mean by that (like, non-developer end user?). I was thinking of setting it inside the application via SDL_SetHintWithPriority with SDL_HINT_DEFAULT, any other use doesn't really make sense to me either. So this suggestion was made with the idea of app developers like me using it, since I happen to know my app doesn't really do anything useful without input other than trapping you. And users could still override it if that is really what they want for whatever reason.
As a casual SDL consumer (i.e. pygame committer), I'd say it's even a pitfall that sometimes with KMSDRM (or Rpi backend) and udev/evdev, there is no way to receive pygame.QUIT events (which are wrapping SDL_QuitEvent). Alt+F4 is just Alt+F4, and there is no window frame with an [x] to click on. This also leaves unsuspecting users forced to hard-reset their machine if they don't have SSH set up!
Properly solving this would probably require the use of something like seatd, to get access to the input devices in the same way that a Wayland compositor would, without requiring the user to be in the input group.
SDL 2.0 is now in maintenance mode, and all inactive issues are being closed. If this issue is impacting you, please feel free to reopen it with additional information.
Unless SDL3 implemented a mode where it stops launch when no input is detected with some sort of warning and an SDL2 hint to override that, maybe that would be still worth considering? For SDL3, of course.
Sure, I'll throw this in the 3.x milestone.
FYI, you can set the environment variable SDL_INPUT_LINUX_KEEP_KBD=1 to keep console input. You won't get input into the application, but at least you'll be able to Ctrl-C out of it.
With the latest change, if we can't open the keyboard device we won't touch the console so you will still be able to hit Ctrl-C to stop your application.
VT switching is not implemented yet, but will be tracked in https://github.com/libsdl-org/SDL/issues/3844.
Why do you prefer this over to just propagate the initialization error? While this may help in certain situations, it may not be obvious for an user that he needs to hit ^C. This doesn't allow the software to try some other (than sdl) back-end. My software has a tty back-end as a fall-back, but with that solution it won't be activated. Also I think this may not work reliably, depending on whether an app handles SIGINT on its own?
And the main question: what is the reason to run an app when it failed to initialize input subsystem? No matter can you shut it down or not, it just doesn't work.
I'm glad there's a way to get out of the app at all, at least! However, if there's ever time for that at all, I would also prefer a more visible error, e.g. a subsystem initialize failure. For apps that are meant to work without input but aren't written to ignore and suppress this error as needed, I think an SDL hint would be best (which defaults to off, and once enabled will silence this error like it behaves now).
We don't require a keyboard and mouse on any other platform, so it seems odd to fail KMSDRM for that. You might have a kiosk application or use a touchscreen or controllers, or have some other use case that may not require a keyboard.
Maybe the distinction here should be "We failed to open the mouse and keyboard"?
https://wiki.libsdl.org/SDL2/SDL_INIT_EVENTS As can be seen, this is undocumented. I assumed this flag implies mouse and keyboard. If not - how about documenting it, and perhaps to add another flags to require mouse and keyboard?