security hardening: ensure suid programs have valid stdin/out/err
authorRich Felker <dalias@aerifal.cx>
Tue, 23 Aug 2011 13:37:39 +0000 (09:37 -0400)
committerRich Felker <dalias@aerifal.cx>
Tue, 23 Aug 2011 13:37:39 +0000 (09:37 -0400)
this behavior (opening fds 0-2 for a suid program) is explicitly
allowed (but not required) by POSIX to protect badly-written suid
programs from clobbering files they later open.

this commit does add some cost in startup code, but the availability
of auxv and the security flag will be useful elsewhere in the future.
in particular auxv is needed for static-linked vdso support, which is
still waiting to be committed (sorry nik!)

arch/i386/atomic.h
arch/x86_64/atomic.h
src/env/__environ.c
src/env/__init_security.c [new file with mode: 0644]
src/env/__libc_start_main.c
src/internal/libc.h

index 66059af9a45b90a5ff418eed6eb6d203776acd4a..77b0b3b73759721c9a1ccc7668ba356cde92100e 100644 (file)
@@ -119,5 +119,10 @@ static inline void a_spin()
        __asm__ __volatile__( "pause" : : : "memory" );
 }
 
+static inline void a_crash()
+{
+       __asm__ __volatile__( "hlt" : : : "memory" );
+}
+
 
 #endif
index 3235db16bbc57f93972827b0fdf57c923522d1a3..0d3da6f8780c43562a84b88f0d3fa65322c36325 100644 (file)
@@ -118,5 +118,10 @@ static inline void a_spin()
        __asm__ __volatile__( "pause" : : : "memory" );
 }
 
+static inline void a_crash()
+{
+       __asm__ __volatile__( "hlt" : : : "memory" );
+}
+
 
 #endif
index d7bd5e506a3e4c56f99d22d00a82c4af79914c0d..0a2786fdeb3f7a037ea95ad8ae2397e1a7c3be28 100644 (file)
@@ -1,7 +1,6 @@
 #include "libc.h"
 
 #undef environ
-char **___environ = 0;
-weak_alias(___environ, __environ);
-weak_alias(___environ, _environ);
-weak_alias(___environ, environ);
+char **__environ = 0;
+weak_alias(__environ, _environ);
+weak_alias(__environ, environ);
diff --git a/src/env/__init_security.c b/src/env/__init_security.c
new file mode 100644 (file)
index 0000000..5fd12ec
--- /dev/null
@@ -0,0 +1,26 @@
+#include <stddef.h>
+#include <elf.h>
+#include <poll.h>
+#include <fcntl.h>
+#include "syscall.h"
+#include "libc.h"
+#include "atomic.h"
+
+#define AUX_CNT 24
+
+void __init_security(size_t *auxv)
+{
+       size_t i, aux[AUX_CNT] = { 0 };
+       struct pollfd pfd[3] = { {.fd=0}, {.fd=1}, {.fd=2} };
+
+       for (; auxv[0]; auxv+=2) if (auxv[0]<AUX_CNT) aux[auxv[0]] = auxv[1];
+       if (aux[AT_UID]==aux[AT_EUID] && aux[AT_GID]==aux[AT_EGID]
+               && !aux[AT_SECURE]) return;
+
+       __syscall(SYS_poll, pfd, 3, 0);
+       for (i=0; i<3; i++)
+               if (pfd[i].revents&POLLNVAL)
+                       if (__syscall(SYS_open, "/dev/null", O_RDWR)<0)
+                               a_crash();
+       libc.secure = 1;
+}
index 70af77b57d311c8b886718f7a71c1ce0c5f53027..f31222b226b7e31b2b3d02a72880afd13e721244 100644 (file)
@@ -1,21 +1,21 @@
 #include "libc.h"
 
-/* Any use of __environ/environ will override this symbol. */
-char **__dummy_environ = (void *)-1;
-weak_alias(__dummy_environ, ___environ);
+void __init_security(size_t *);
 
 int __libc_start_main(
        int (*main)(int, char **, char **), int argc, char **argv,
        int (*init)(int, char **, char **), void (*fini)(void),
        void (*ldso_fini)(void))
 {
-       /* Save the environment if it may be used by libc/application */
-       char **envp = argv+argc+1;
-       if (___environ != (void *)-1) ___environ = envp;
+       char **envp = argv+argc+1, **auxv = envp;
 
-       /* Avoid writing 0 and triggering unnecessary COW */
-       if (ldso_fini) libc.ldso_fini = ldso_fini;
-       if (fini) libc.fini = fini;
+       __environ = envp;
+       do auxv++; while (*auxv);
+       libc.auxv = (void *)++auxv;
+       libc.ldso_fini = ldso_fini;
+       libc.fini = fini;
+
+       __init_security((void *)auxv);
 
        /* Execute constructors (static) linked into the application */
        if (init) init(argc, argv, envp);
index 115cd8653b78246cb5835e408a19c95f4f21ef8e..d985902c6389a82403e04640341e620426808899 100644 (file)
@@ -7,13 +7,15 @@
 struct __libc {
        void *main_thread;
        int threaded;
-       int canceldisable;
+       int secure;
+       size_t *auxv;
        int (*atexit)(void (*)(void));
        void (*fini)(void);
        void (*ldso_fini)(void);
        volatile int threads_minus_1;
-       int ofl_lock;
+       int canceldisable;
        FILE *ofl_head;
+       int ofl_lock;
 };