Hi,
since the Xorg setuid bit was removed, I looked a little bit into what
it would take to run it without root privs. I have a proof of concept
put together, and things seem to work (on an X220 amd64 + modesetting
driver, inteldrm; login on ttyC0 and running xinit). Testing the waters
here to see if anyone else is interested :)
First, we need Xorg to attempt xf86OpenConsole even when we're not uid
0. That will call xf86OpenWScons (through xf86ConsTab), which opens the
console device and does wscons ioctls on it -- succeeding if the user
running X has logged in on that console.
diff --git a/xserver/hw/xfree86/common/xf86Init.c
b/xserver/hw/xfree86/common/xf86Init.c
index 2a04da045..b814eb412 100644
--- a/xserver/hw/xfree86/common/xf86Init.c
+++ b/xserver/hw/xfree86/common/xf86Init.c
@@ -967,9 +967,13 @@ OsVendorInit(void)
#endif
#endif
#if defined(X_PRIVSEP)
- if (!beenHere && !xf86KeepPriv && geteuid() == 0) {
- xf86PrivilegedInit();
- xf86DropPriv();
+ if (!beenHere) {
+ if(!xf86KeepPriv && geteuid() == 0) {
+ xf86PrivilegedInit();
+ xf86DropPriv();
+ } else {
+ xf86OpenConsole();
+ }
}
#endif
Next, we need the user logging in on ttyC0 to be able to access
/dev/pci0 and /dev/ttyC4:
diff --git a/etc/etc.amd64/fbtab b/etc/etc.amd64/fbtab
index 79cfb535c9f..b746b7684f7 100644
--- a/etc/etc.amd64/fbtab
+++ b/etc/etc.amd64/fbtab
@@ -1 +1 @@
-/dev/ttyC0 0600
/dev/console:/dev/wskbd:/dev/wskbd0:/dev/wsmouse:/dev/wsmouse0:/dev/ttyCcfg:/dev/drm0
+/dev/ttyC0 0600
/dev/console:/dev/wskbd:/dev/wskbd0:/dev/wsmouse:/dev/wsmouse0:/dev/ttyCcfg:/dev/drm0:/dev/pci0:/dev/ttyC4
Finally, there's a check in drm_drv.c that only allows superuser to
become a master on /dev/drm0 and fails the open for other users. I
removed the superuser check; filesystem permissions should prevent
anyone except the user logging in on ttyC0 from accessing this device
anyway. I haven't studied what exactly being the master allows here and
if there's possible privilege escalation hiding there; my reading of
drm_do_ioctl is that ioctls marked DRM_ROOT_ONLY will still fail, so I
admit I don't really know what the check was there for...
Still, this allows running X without any user processes as root (and
unbreaks xinit/startx) - is there any potential here? :)
diff --git a/sys/dev/pci/drm/drm_drv.c b/sys/dev/pci/drm/drm_drv.c
index e09380e3257..be9773b0671 100644
--- a/sys/dev/pci/drm/drm_drv.c
+++ b/sys/dev/pci/drm/drm_drv.c
@@ -745,14 +745,10 @@ drmopen(dev_t kdev, int flags, int fmt, struct proc *p)
}
mutex_lock(&dev->struct_mutex);
- /* first opener automatically becomes master if root */
- if (SPLAY_EMPTY(&dev->files) && !DRM_SUSER(p)) {
- mutex_unlock(&dev->struct_mutex);
- ret = EPERM;
- goto free_priv;
- }
-
+ /* first opener automatically becomes master */
file_priv->is_master = SPLAY_EMPTY(&dev->files);
+ if (!file_priv->authenticated)
+ file_priv->authenticated = file_priv->is_master;
SPLAY_INSERT(drm_file_tree, &dev->files, file_priv);
mutex_unlock(&dev->struct_mutex);
--
Lauri Tirkkonen | lotheac @ IRCnet