summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2011-08-23 09:37:39 -0400
committerRich Felker <dalias@aerifal.cx>2011-08-23 09:37:39 -0400
commitdf0b5a49406763aa4719dfad561a5de8924ecd59 (patch)
tree0d5dc42698f2b710dd27156554b10230ba21256b /src
parentc0f344160d22d889460573d003cf349626a38184 (diff)
downloadmusl-df0b5a49406763aa4719dfad561a5de8924ecd59.tar.gz
security hardening: ensure suid programs have valid stdin/out/err
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!)
Diffstat (limited to 'src')
-rw-r--r--src/env/__environ.c7
-rw-r--r--src/env/__init_security.c26
-rw-r--r--src/env/__libc_start_main.c18
-rw-r--r--src/internal/libc.h6
4 files changed, 42 insertions, 15 deletions
diff --git a/src/env/__environ.c b/src/env/__environ.c
index d7bd5e50..0a2786fd 100644
--- a/src/env/__environ.c
+++ b/src/env/__environ.c
@@ -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
index 00000000..5fd12ecb
--- /dev/null
+++ b/src/env/__init_security.c
@@ -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;
+}
diff --git a/src/env/__libc_start_main.c b/src/env/__libc_start_main.c
index 70af77b5..f31222b2 100644
--- a/src/env/__libc_start_main.c
+++ b/src/env/__libc_start_main.c
@@ -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);
diff --git a/src/internal/libc.h b/src/internal/libc.h
index 115cd865..d985902c 100644
--- a/src/internal/libc.h
+++ b/src/internal/libc.h
@@ -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;
};