The last few months I've been working on making Xorg run without root rights. Xorg has traditionally always been suid root because it needed direct hardware access. With the advent of kms all hardware access is done by the kernel, so the primary reason for the X server running with root rights is no longer relevant.
Yet the current xserver still need root rights for 3 reasons:1. Access to /dev/input/event* and /dev/dri/card*
Wayland needs this to, so a while ago systemd-logind has grown an API
to allow a process inside a session to become the session controller
, and get filedescriptors for these device nodes over dbus.
Some people may think that this is overkill and that simply opening up the permissions on the device nodes would be enough, but that is not true. For /dev/input/event* nodes we want a manager process to revoke the access of a session becoming inactive, so that it cannot stick around and snoop input events destined for another session. And for /dev/dri/card* nodes root rights are necessary to become the drm master.2. Setting up a session and a tty, ie VT_SETMODE VTPROCESS
Since creating a new session requires root rights this is left to the process starting the X server, usually the display manager. When the X server is started from a text login on a virtual terminal using startx, it simply takes over the existing session on that vt. As for VT_SETMODE VTPROCESS that will work as a normal user too as long as that user owns the tty (and setting tty ownership is part of setting up a proper session).3. Logging to /var/log/Xorg.#.log
Xorg 1.16 will log to ~/.local/share/xorg/Xorg.#.log when started as non root.Driver changes
With systemd-logind now managing device node access, we also need a bunch of driver changes as many Xorg drivers used to directly open device nodes themselves. Xorg 1.16 introduces server-managed fds, when:
- the X server is compiled with systemd-logind support; and
- systemd-logind is available; and
- the driver used supports server-managed fds
Then the server will manage the filedescriptor for the relevant /dev/... device node, and pass it into the driver at init time. The necessary driver changes are quite minimal, see this video driver example
and this input driver example
For switching away (vt-leave) from the VT on which the X server is running, the X server will keep using the VT_PROCESS VT mode, so everything can be shutdown safely before the VT switch happens. For server-managed fds the server will do a DRM_DROP_MASTER for video devices, and close the fd for input devices.
When switching back to the X server VT, systemd-logind will pass in new fds for input devices and call DRM_SET_MASTER for video devices asynchronously from the VT enter. So when systemd-logind is used the VT enter sequence is a bit differently, the VT enter signal the X server receives is ignored. Instead the X server waits till systemd-logind has signalled it is the drm master again for all the server-managed video device nodes. Filedescriptors received before the server is drm master again are cached, and the input devices are activated immediately after the video nodes are, fds received after this are activated immediately.User-space modesetting (UMS) compatibility
When the Xorg binary is no longer suid root, UMS drivers will not work. To solve this there is a new suid-wrapper called Xorg.wrap which is suid root, when installed this wrapper will get called in stead of the real X server, and it will check if there are KMS capable cards in the system, if KMS capable cards are found it will drop all
elevated rights and execute the X server as a normal user. If no KMS capable cards are found it will execute the X server with root rights, allowing old UMS drivers, such as the proprietary drivers for some cards, or the vesa driver to work.
Use of this wrapper is optional and security concious users who have a KMS capable system will be able to do "yum remove xorg-x11-server-wrapper", or their distro's equivalent.