OSDN Git Service

Fix up __uClibc_init() for so that we prevent starting SUID
authorEric Andersen <andersen@codepoet.org>
Wed, 27 Oct 2004 09:44:00 +0000 (09:44 -0000)
committerEric Andersen <andersen@codepoet.org>
Wed, 27 Oct 2004 09:44:00 +0000 (09:44 -0000)
binaries where the standard file descriptors are not opened.
 -Erik

TODO
libc/misc/internals/__uClibc_main.c

diff --git a/TODO b/TODO
index ec9ea01..3265550 100644 (file)
--- a/TODO
+++ b/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
index 937428a..c41f7cc 100644 (file)
 #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;