Browse Source

Fix up __uClibc_init() for so that we prevent starting SUID
binaries where the standard file descriptors are not opened.
-Erik

Eric Andersen 19 years ago
parent
commit
5853eed77b
2 changed files with 66 additions and 21 deletions
  1. 0 4
      TODO
  2. 66 17
      libc/misc/internals/__uClibc_main.c

+ 0 - 4
TODO

@@ -1,9 +1,5 @@
 TODO list for the uClibc 0.9.27 release:
 -------------------------------------------------
-    *) Fix use of __secure in __uClibc_init() for so that we prevent
-	starting staticly linked SUID binaries where the standard file
-	descriptors are not opened.  For dynamically linked binaries,
-	ldso does this for us.
     *) Audit header files.  Remove prototypes for all functions that
 	are not supported -- especially needed for the libm headers.
     *) Audit header files.  When options are disabled, also disable

+ 66 - 17
libc/misc/internals/__uClibc_main.c

@@ -18,6 +18,12 @@
 #include <string.h>
 #include <elf.h>
 #include <bits/uClibc_page.h>
+#include <paths.h>
+#include <unistd.h>
+#include <asm/errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
 #ifdef __UCLIBC_PROPOLICE__
 extern void __guard_setup(void);
 #endif
@@ -46,19 +52,58 @@ extern void weak_function __pthread_initialize_minimal(void);
  * Note: Apparently we must initialize __environ to ensure that the weak
  * environ symbol is also included.
  */
+char **__environ = 0;
+weak_alias(__environ, environ);
 
 size_t __pagesize = 0;
-char **__environ = 0;
 const char *__progname = 0;
-weak_alias(__environ, environ);
 
-/* FIXME */
-#if 0
-extern int _dl_secure;
-int __secure = 0;
-weak_alias(__secure, _dl_secure);
+
+#ifndef O_NOFOLLOW
+# define O_NOFOLLOW	0
 #endif
 
+extern int __libc_fcntl(int fd, int cmd, ...);
+extern int __libc_open(const char *file, int flags, ...);
+
+static void __check_one_fd(int fd, int mode)
+{
+    /* Check if the specified fd is already open */
+    if (unlikely(__libc_fcntl(fd, F_GETFD)==-1 && *(__errno_location())==EBADF))
+    {
+	/* The descriptor is probably not open, so try to use /dev/null */
+	struct stat st;
+	int nullfd = __libc_open(_PATH_DEVNULL, mode);
+	/* /dev/null is major=1 minor=3.  Make absolutely certain
+	 * that is in fact the device that we have opened and not
+	 * some other wierd file... */
+	if ( (nullfd!=fd) || fstat(fd, &st) || !S_ISCHR(st.st_mode) ||
+		(st.st_rdev != makedev(1, 3)))
+	{
+	    /* Somebody is trying some trickery here... */
+	    while (1) {
+		abort();
+	    }
+	}
+    }
+}
+
+static int __check_suid(void)
+{
+    uid_t uid, euid;
+    gid_t gid, egid;
+
+    uid  = getuid();
+    euid = geteuid();
+    gid  = getgid();
+    egid = getegid();
+
+    if(uid == euid && gid == egid) {
+	return 0;
+    }
+    return 1;
+}
+
 
 /* __uClibc_init completely initialize uClibc so it is ready to use.
  *
@@ -94,16 +139,6 @@ void __uClibc_init(void)
 	__pthread_initialize_minimal();
 #endif
 
-    /* FIXME */
-#if 0
-    /* Some security at this point.  Prevent starting a SUID binary
-     * where the standard file descriptors are not opened.  We have
-     * to do this only for statically linked applications since
-     * otherwise the dynamic loader did the work already.  */
-    if (unlikely (__secure!=NULL))
-	__libc_check_standard_fds ();
-#endif
-
 #ifdef __UCLIBC_HAS_LOCALE__
     /* Initialize the global locale structure. */
     if (likely(_locale_init!=NULL))
@@ -161,7 +196,21 @@ __uClibc_start_main(int argc, char **argv, char **envp,
 	}
 	aux_dat += 2;
     }
+
+    /* Make certain getpagesize() gives the correct answer */
     __pagesize = (auxvt[AT_PAGESZ].a_un.a_val)? auxvt[AT_PAGESZ].a_un.a_val : PAGE_SIZE;
+
+    /* Prevent starting SUID binaries where the stdin. stdout, and
+     * stderr file descriptors are not already opened. */
+    if ((auxvt[AT_UID].a_un.a_val==-1 && __check_suid()) ||
+	    (auxvt[AT_UID].a_un.a_val != -1 &&
+	    (auxvt[AT_UID].a_un.a_val != auxvt[AT_EUID].a_un.a_val ||
+	     auxvt[AT_GID].a_un.a_val != auxvt[AT_EGID].a_un.a_val)))
+    {
+	__check_one_fd (STDIN_FILENO, O_RDONLY | O_NOFOLLOW);
+	__check_one_fd (STDOUT_FILENO, O_RDWR | O_NOFOLLOW);
+	__check_one_fd (STDERR_FILENO, O_RDWR | O_NOFOLLOW);
+    }
 #endif
 
     __progname = *argv;