On 12/17/2011 12:45 AM, Keith Packard wrote:
> On Fri, 16 Dec 2011 12:09:14 -0500, Adam Jackson <[email protected]> wrote:
> 
>> Reviewed-by: Adam Jackson <[email protected]>
> 
> Thanks for the review, Adam. Of course, with the changes to the
> function detection logic in configure.ac, the original patch no longer
> applies to master.
> 
> If someone could rebase this to master, I'd like to get this merged now.
Updated patch attached.

Antoine
>From 99ade3fda128bc6363735c289eb1c877d39ddecc Mon Sep 17 00:00:00 2001
From: Antoine Martin <[email protected]>
Date: Sat, 17 Dec 2011 01:36:51 +0700
Subject: [PATCH xserver] xserver: check for elevated privileges not uid=0

This allows us to run the server as a normal user whilst still
being able to use the -modulepath, -logfile and -config switches
We define a xf86PrivsElevated which will do the checks and cache
the result in case it is called more than once.
Also renamed the paths #defines to match their new meaning.
Original discussion which led to this patch can be found here:
http://lists.freedesktop.org/archives/xorg-devel/2011-September/025853.html

Signed-off-by: Antoine Martin <[email protected]>
Tested-by: Michal Suchanek <hramrach at centrum.cz>
Reviewed-by: Jamey Sharp <jamey at minilop.net>
Reviewed-by: Adam Jackson <[email protected]> 
---
 configure.ac                   |    2 +-
 hw/xfree86/common/xf86Config.c |   28 +++++++-------
 hw/xfree86/common/xf86Init.c   |   78 +++++++++++++++++++++++++++++++++++-----
 hw/xfree86/common/xf86Priv.h   |    1 +
 include/xorg-config.h.in       |    6 +++
 5 files changed, 91 insertions(+), 24 deletions(-)

diff --git a/configure.ac b/configure.ac
index 27bf6ab..518eb06 100644
--- a/configure.ac
+++ b/configure.ac
@@ -212,7 +212,7 @@ AC_CHECK_FUNC([dlopen], [],
 AC_SUBST(DLOPEN_LIBS)
 
 dnl Checks for library functions.
-AC_CHECK_FUNCS([backtrace ffs \
+AC_CHECK_FUNCS([backtrace ffs geteuid getuid issetugid getresuid \
        getdtablesize getifaddrs getpeereid getpeerucred getzoneid \
        mmap shmctl64 strncasecmp vasprintf vsnprintf walkcontext])
 AC_REPLACE_FUNCS([strcasecmp strcasestr strlcat strlcpy strndup])
diff --git a/hw/xfree86/common/xf86Config.c b/hw/xfree86/common/xf86Config.c
index 569695c..f51be7e 100644
--- a/hw/xfree86/common/xf86Config.c
+++ b/hw/xfree86/common/xf86Config.c
@@ -72,8 +72,8 @@
  * These paths define the way the config file search is done.  The escape
  * sequences are documented in parser/scan.c.
  */
-#ifndef ROOT_CONFIGPATH
-#define ROOT_CONFIGPATH        "%A," "%R," \
+#ifndef ALL_CONFIGPATH
+#define ALL_CONFIGPATH "%A," "%R," \
                        "/etc/X11/%R," "%P/etc/X11/%R," \
                        "%E," "%F," \
                        "/etc/X11/%F," "%P/etc/X11/%F," \
@@ -83,8 +83,8 @@
                        "%P/lib/X11/%X.%H," \
                        "%P/lib/X11/%X"
 #endif
-#ifndef USER_CONFIGPATH
-#define USER_CONFIGPATH        "/etc/X11/%S," "%P/etc/X11/%S," \
+#ifndef RESTRICTED_CONFIGPATH
+#define RESTRICTED_CONFIGPATH  "/etc/X11/%S," "%P/etc/X11/%S," \
                        "/etc/X11/%G," "%P/etc/X11/%G," \
                        "/etc/X11/%X," "/etc/%X," \
                        "%P/etc/X11/%X.%H," \
@@ -92,14 +92,14 @@
                        "%P/lib/X11/%X.%H," \
                        "%P/lib/X11/%X"
 #endif
-#ifndef ROOT_CONFIGDIRPATH
-#define ROOT_CONFIGDIRPATH     "%A," "%R," \
+#ifndef ALL_CONFIGDIRPATH
+#define ALL_CONFIGDIRPATH      "%A," "%R," \
                                "/etc/X11/%R," "%C/X11/%R," \
                                "/etc/X11/%X," "%C/X11/%X"
 #endif
-#ifndef USER_CONFIGDIRPATH
-#define USER_CONFIGDIRPATH     "/etc/X11/%R," "%C/X11/%R," \
-                               "/etc/X11/%X," "%C/X11/%X"
+#ifndef RESTRICTED_CONFIGDIRPATH
+#define RESTRICTED_CONFIGDIRPATH       "/etc/X11/%R," "%C/X11/%R," \
+                                       "/etc/X11/%X," "%C/X11/%X"
 #endif
 #ifndef SYS_CONFIGDIRPATH
 #define SYS_CONFIGDIRPATH      "/usr/share/X11/%X," "%D/X11/%X"
@@ -2310,12 +2310,12 @@ xf86HandleConfigFile(Bool autoconfig)
        MessageType filefrom = X_DEFAULT;
        MessageType dirfrom = X_DEFAULT;
 
-       if (getuid() == 0) {
-           filesearch = ROOT_CONFIGPATH;
-           dirsearch = ROOT_CONFIGDIRPATH;
+       if (!xf86PrivsElevated()) {
+           filesearch = ALL_CONFIGPATH;
+           dirsearch = ALL_CONFIGDIRPATH;
        } else {
-           filesearch = USER_CONFIGPATH;
-           dirsearch = USER_CONFIGDIRPATH;
+           filesearch = RESTRICTED_CONFIGPATH;
+           dirsearch = RESTRICTED_CONFIGDIRPATH;
        }
 
        if (xf86ConfigFile)
diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c
index c1e48ee..5263b5f 100644
--- a/hw/xfree86/common/xf86Init.c
+++ b/hw/xfree86/common/xf86Init.c
@@ -238,6 +238,65 @@ xf86PrintMarkers(void)
   LogPrintMarkers();
 }
 
+Bool xf86PrivsElevated(void)
+{
+  static Bool privsTested = FALSE;
+  static Bool privsElevated = TRUE;
+
+  if (!privsTested) {
+#if defined(WIN32)
+    privsElevated = FALSE;
+#else
+    if ((getuid() != geteuid()) || (getgid() != getegid())) {
+      privsElevated = TRUE;
+    } else {
+#if defined(HAVE_ISSETUGID)
+      privsElevated = issetugid();
+#elif defined(HAVE_GETRESUID)
+      uid_t ruid, euid, suid;
+      gid_t rgid, egid, sgid;
+
+      if ((getresuid(&ruid, &euid, &suid) == 0) &&
+          (getresgid(&rgid, &egid, &sgid) == 0)) {
+        privsElevated = (euid != suid) || (egid != sgid);
+      }
+      else {
+        printf("Failed getresuid or getresgid");
+        /* Something went wrong, make defensive assumption */
+        privsElevated = TRUE;
+      }
+#else
+      if (getuid()==0) {
+        /* running as root: uid==euid==0 */
+        privsElevated = FALSE;
+      }
+      else {
+        /*
+         * If there are saved ID's the process might still be privileged
+         * even though the above test succeeded. If issetugid() and
+         * getresgid() aren't available, test this by trying to set
+         * euid to 0.
+         */
+        unsigned int oldeuid;
+        oldeuid = geteuid();
+
+        if (seteuid(0) != 0) {
+          privsElevated = FALSE;
+        } else {
+          if (seteuid(oldeuid) != 0) {
+            FatalError("Failed to drop privileges.  Exiting\n");
+          }
+          privsElevated = TRUE;
+        }
+      }
+#endif
+    }
+#endif
+    privsTested = TRUE;
+  }
+  return privsElevated;
+}
+
 static Bool
 xf86CreateRootWindow(WindowPtr pWin)
 {
@@ -872,7 +931,7 @@ OsVendorInit(void)
 
 #ifdef O_NONBLOCK
   if (!beenHere) {
-    if (geteuid() == 0 && getuid() != geteuid())
+    if (xf86PrivsElevated())
     {
       int status;
 
@@ -1043,10 +1102,11 @@ ddxProcessArgument(int argc, char **argv, int i)
       FatalError("Required argument to %s not specified\n", argv[i]);  \
     }
 
-  /* First the options that are only allowed for root */
+  /* First the options that are not allowed with elevated privileges */
   if (!strcmp(argv[i], "-modulepath") || !strcmp(argv[i], "-logfile")) {
-    if ( (geteuid() == 0) && (getuid() != 0) ) {
-      FatalError("The '%s' option can only be used by root.\n", argv[i]);
+    if (xf86PrivsElevated()) {
+      FatalError("The '%s' option cannot be used with "
+                 "elevated privileges.\n", argv[i]);
     }
     else if (!strcmp(argv[i], "-modulepath"))
     {
@@ -1074,9 +1134,9 @@ ddxProcessArgument(int argc, char **argv, int i)
   if (!strcmp(argv[i], "-config") || !strcmp(argv[i], "-xf86config"))
   {
     CHECK_FOR_REQUIRED_ARGUMENT();
-    if (getuid() != 0 && !xf86PathIsSafe(argv[i + 1])) {
+    if (xf86PrivsElevated() && !xf86PathIsSafe(argv[i + 1])) {
       FatalError("\nInvalid argument for %s\n"
-         "\tFor non-root users, the file specified with %s must be\n"
+         "\tWith elevated privileges, the file specified with %s must be\n"
          "\ta relative path and must not contain any \"..\" elements.\n"
          "\tUsing default "__XCONFIGFILE__" search path.\n\n",
          argv[i], argv[i]);
@@ -1087,9 +1147,9 @@ ddxProcessArgument(int argc, char **argv, int i)
   if (!strcmp(argv[i], "-configdir"))
   {
     CHECK_FOR_REQUIRED_ARGUMENT();
-    if (getuid() != 0 && !xf86PathIsSafe(argv[i + 1])) {
+    if (xf86PrivsElevated() && !xf86PathIsSafe(argv[i + 1])) {
       FatalError("\nInvalid argument for %s\n"
-         "\tFor non-root users, the file specified with %s must be\n"
+         "\tWith elevated privileges, the file specified with %s must be\n"
          "\ta relative path and must not contain any \"..\" elements.\n"
          "\tUsing default "__XCONFIGDIR__" search path.\n\n",
          argv[i], argv[i]);
@@ -1375,7 +1435,7 @@ ddxUseMsg(void)
   ErrorF("\n");
   ErrorF("\n");
   ErrorF("Device Dependent Usage\n");
-  if (getuid() == 0 || geteuid() != 0)
+  if (!xf86PrivsElevated())
   {
     ErrorF("-modulepath paths      specify the module search path\n");
     ErrorF("-logfile file          specify a log file name\n");
diff --git a/hw/xfree86/common/xf86Priv.h b/hw/xfree86/common/xf86Priv.h
index e0b1809..255407b 100644
--- a/hw/xfree86/common/xf86Priv.h
+++ b/hw/xfree86/common/xf86Priv.h
@@ -145,6 +145,7 @@ extern _X_EXPORT Bool xf86LoadModules(char **list, pointer 
*optlist);
 extern _X_EXPORT int xf86SetVerbosity(int verb);
 extern _X_EXPORT int xf86SetLogVerbosity(int verb);
 extern _X_EXPORT Bool xf86CallDriverProbe( struct _DriverRec * drv, Bool 
detect_only );
+extern _X_EXPORT Bool xf86PrivsElevated(void);
 
 #endif /* _NO_XF86_PROTOTYPES */
 
diff --git a/include/xorg-config.h.in b/include/xorg-config.h.in
index 6b9230f..2cc416a 100644
--- a/include/xorg-config.h.in
+++ b/include/xorg-config.h.in
@@ -130,4 +130,10 @@
 /* Use libpciaccess */
 #undef XSERVER_LIBPCIACCESS
 
+/* Have setugid */
+#undef HAVE_ISSETUGID
+
+/* Have getresuid */
+#undef HAVE_GETRESUID
+
 #endif /* _XORG_CONFIG_H_ */
-- 
1.7.7.4

_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to