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

Reply via email to