summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2004-10-27 09:44:00 +0000
committerEric Andersen <andersen@codepoet.org>2004-10-27 09:44:00 +0000
commit5853eed77b485b3f47d6239bc0262c7b0a055a6b (patch)
treed81a8339468436c78d65c6ede5a32f6208148990 /libc
parentb33b788f8978551f4232328d76c3ddc6e5a5c582 (diff)
Fix up __uClibc_init() for so that we prevent starting SUID
binaries where the standard file descriptors are not opened. -Erik
Diffstat (limited to 'libc')
-rw-r--r--libc/misc/internals/__uClibc_main.c83
1 files changed, 66 insertions, 17 deletions
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 <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;