From 5853eed77b485b3f47d6239bc0262c7b0a055a6b Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Wed, 27 Oct 2004 09:44:00 +0000 Subject: Fix up __uClibc_init() for so that we prevent starting SUID binaries where the standard file descriptors are not opened. -Erik --- TODO | 4 -- libc/misc/internals/__uClibc_main.c | 83 +++++++++++++++++++++++++++++-------- 2 files changed, 66 insertions(+), 21 deletions(-) diff --git a/TODO b/TODO index ec9ea0182..326555076 100644 --- 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 diff --git a/libc/misc/internals/__uClibc_main.c b/libc/misc/internals/__uClibc_main.c index 937428a9e..c41f7ccf2 100644 --- a/libc/misc/internals/__uClibc_main.c +++ b/libc/misc/internals/__uClibc_main.c @@ -18,6 +18,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #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; -- cgit v1.2.3