summaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2005-06-26 18:14:26 +0000
committerUlrich Drepper <drepper@redhat.com>2005-06-26 18:14:26 +0000
commit35f1e82763326f196fd068e92343643d8ed54ee3 (patch)
tree74c6d155ca2e7c32503231b8ce186a0752bc924b /elf
parent2f37117b013f77df863b198c3408555c49596174 (diff)
downloadglibc-35f1e82763326f196fd068e92343643d8ed54ee3.tar.gz
* Versions.def (ld): Add GLIBC_2.4.
* configure.in: Add --enable-stackguard-randomization option. (ENABLE_STACKGUARD_RANDOMIZE): New define. * config.h.in (ENABLE_STACKGUARD_RANDOMIZE): Add. * sysdeps/unix/sysv/linux/dl-osinfo.h: Include stdint.h. (_dl_setup_stack_chk_guard): New inline function. * sysdeps/generic/dl-osinfo.h: Include stdint.h. (_dl_setup_stack_chk_guard): New inline function. * elf/rtld.c (__stack_chk_guard): New variable. (dl_main): Remove all traces of TLS_INIT_TP_EXPENSIVE. Set __stack_chk_guard to _dl_setup_stack_chk_guard (), use THREAD_SET_STACK_GUARD if defined. * elf/Versions (ld): Export __stack_chk_guard@@GLIBC_2.4. * sysdeps/generic/libc-start.c (__stack_chk_guard): New variable. (__libc_start_main): Set __stack_chk_guard to _dl_setup_stack_chk_guard (), use THREAD_SET_STACK_GUARD if defined. * sysdeps/generic/libc-tls.c (__libc_setup_tls): Remove all traces of TLS_INIT_TP_EXPENSIVE. * debug/Versions (libc): Export __stack_chk_fail@@GLIBC_2.4. * debug/Makefile (routines): Add stack_chk_fail. (static-only-routines): Add stack_chk_fail_local. * debug/stack_chk_fail_local.c: New file. * debug/stack_chk_fail.c: New file. * elf/Makefile: Add rules to build and run tst-stackguard1{,-static} tests. * elf/tst-stackguard1.c: New file. * elf/tst-stackguard1-static.c: New file. * elf/stackguard-macros.h: New file.
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile11
-rw-r--r--elf/Versions4
-rw-r--r--elf/rtld.c54
-rw-r--r--elf/stackguard-macros.h30
-rw-r--r--elf/tst-stackguard1-static.c1
-rw-r--r--elf/tst-stackguard1.c196
6 files changed, 270 insertions, 26 deletions
diff --git a/elf/Makefile b/elf/Makefile
index d988baca3b..c43eb02f5b 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -87,7 +87,8 @@ distribute := rtld-Rules \
unload3mod1.c unload3mod2.c unload3mod3.c unload3mod4.c \
unload4mod1.c unload4mod2.c unload4mod3.c unload4mod4.c \
unload6mod1.c unload6mod2.c unload6mod3.c tst-auditmod1.c \
- order2mod1.c order2mod2.c order2mod3.c order2mod4.c
+ order2mod1.c order2mod2.c order2mod3.c order2mod4.c \
+ tst-stackguard1.c tst-stackguard1-static.c
CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables
@@ -140,7 +141,7 @@ ifeq (yes,$(have-initfini-array))
tests += tst-array1 tst-array2 tst-array3 tst-array4
endif
ifeq (yes,$(build-static))
-tests-static = tst-tls1-static tst-tls2-static
+tests-static = tst-tls1-static tst-tls2-static tst-stackguard1-static
ifeq (yesyesyes,$(build-static)$(build-shared)$(elf))
tests-static += tst-tls9-static
tst-tls9-static-ENV = \
@@ -162,7 +163,8 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 tst-align \
tst-align2 $(tests-execstack-$(have-z-execstack)) tst-dlmodcount \
tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
- unload3 unload4 unload5 unload6 tst-audit1 tst-global1 order2
+ unload3 unload4 unload5 unload6 tst-audit1 tst-global1 order2 \
+ tst-stackguard1
# reldep9
test-srcs = tst-pathopt
tests-vis-yes = vismain
@@ -843,3 +845,6 @@ $(objpfx)order2mod1.so: $(objpfx)order2mod4.so
$(objpfx)order2mod4.so: $(objpfx)order2mod3.so
$(objpfx)order2mod2.so: $(objpfx)order2mod3.so
order2mod2.so-no-z-defs = yes
+
+tst-stackguard1-ARGS = --command "$(built-program-cmd) --child"
+tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child"
diff --git a/elf/Versions b/elf/Versions
index aaacf3e4ea..9c53f1615e 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -43,6 +43,10 @@ ld {
# runtime interface to TLS
__tls_get_addr;
}
+ GLIBC_2.4 {
+ # stack canary
+ __stack_chk_guard;
+ }
GLIBC_PRIVATE {
# Those are in the dynamic linker, but used by libc.so.
__libc_enable_secure;
diff --git a/elf/rtld.c b/elf/rtld.c
index bd171e977d..21365af2ba 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -80,6 +80,12 @@ char **_dl_argv attribute_relro = NULL;
#endif
INTDEF(_dl_argv)
+#ifndef THREAD_SET_STACK_GUARD
+/* Only exported for architectures that don't store the stack guard canary
+ in thread local area. */
+uintptr_t __stack_chk_guard attribute_relro;
+#endif
+
/* Nonzero if we were run directly. */
unsigned int _dl_skip_args attribute_relro attribute_hidden;
@@ -1398,9 +1404,6 @@ ld.so does not support TLS, but program uses it!\n");
always allocate the static block, we never defer it even if
no DF_STATIC_TLS bit is set. The reason is that we know
glibc will use the static model. */
-# ifndef TLS_INIT_TP_EXPENSIVE
-# define TLS_INIT_TP_EXPENSIVE 0
-# endif
/* Since we start using the auditing DSOs right away we need to
initialize the data structures now. */
@@ -1807,10 +1810,18 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
used. Trying to do it lazily is too hairy to try when there could be
multiple threads (from a non-TLS-using libpthread). */
bool was_tls_init_tp_called = tls_init_tp_called;
- if (tcbp == NULL && (!TLS_INIT_TP_EXPENSIVE || GL(dl_tls_max_dtv_idx) > 0))
+ if (tcbp == NULL)
tcbp = init_tls ();
#endif
+ /* Set up the stack checker's canary. */
+ uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard ();
+#ifdef THREAD_SET_STACK_GUARD
+ THREAD_SET_STACK_GUARD (stack_chk_guard);
+#else
+ __stack_chk_guard = stack_chk_guard;
+#endif
+
if (__builtin_expect (mode, normal) != normal)
{
/* We were run just to list the shared libraries. It is
@@ -2230,29 +2241,26 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
#endif
#ifdef USE_TLS
- if (GL(dl_tls_max_dtv_idx) > 0 || USE___THREAD || !TLS_INIT_TP_EXPENSIVE)
- {
- if (!was_tls_init_tp_called && GL(dl_tls_max_dtv_idx) > 0)
- ++GL(dl_tls_generation);
+ if (!was_tls_init_tp_called && GL(dl_tls_max_dtv_idx) > 0)
+ ++GL(dl_tls_generation);
- /* Now that we have completed relocation, the initializer data
- for the TLS blocks has its final values and we can copy them
- into the main thread's TLS area, which we allocated above. */
- _dl_allocate_tls_init (tcbp);
+ /* Now that we have completed relocation, the initializer data
+ for the TLS blocks has its final values and we can copy them
+ into the main thread's TLS area, which we allocated above. */
+ _dl_allocate_tls_init (tcbp);
- /* And finally install it for the main thread. If ld.so itself uses
- TLS we know the thread pointer was initialized earlier. */
- if (! tls_init_tp_called)
- {
- const char *lossage = TLS_INIT_TP (tcbp, USE___THREAD);
- if (__builtin_expect (lossage != NULL, 0))
- _dl_fatal_printf ("cannot set up thread-local storage: %s\n",
- lossage);
- }
+ /* And finally install it for the main thread. If ld.so itself uses
+ TLS we know the thread pointer was initialized earlier. */
+ if (! tls_init_tp_called)
+ {
+ const char *lossage = TLS_INIT_TP (tcbp, USE___THREAD);
+ if (__builtin_expect (lossage != NULL, 0))
+ _dl_fatal_printf ("cannot set up thread-local storage: %s\n",
+ lossage);
}
- else
+#else
+ NONTLS_INIT_TP;
#endif
- NONTLS_INIT_TP;
#ifdef SHARED
/* Auditing checkpoint: we have added all objects. */
diff --git a/elf/stackguard-macros.h b/elf/stackguard-macros.h
new file mode 100644
index 0000000000..0fbf4d2c0b
--- /dev/null
+++ b/elf/stackguard-macros.h
@@ -0,0 +1,30 @@
+#include <stdint.h>
+
+#ifdef __i386__
+# define STACK_CHK_GUARD \
+ ({ uintptr_t x; asm ("movl %%gs:0x14, %0" : "=r" (x)); x; })
+#elif defined __x86_64__
+# define STACK_CHK_GUARD \
+ ({ uintptr_t x; asm ("movq %%fs:0x28, %0" : "=r" (x)); x; })
+#elif defined __powerpc64__
+# define STACK_CHK_GUARD \
+ ({ uintptr_t x; asm ("ld %0,-28688(13)" : "=r" (x)); x; })
+#elif defined __powerpc__
+# define STACK_CHK_GUARD \
+ ({ uintptr_t x; asm ("lwz %0,-28680(2)" : "=r" (x)); x; })
+#elif defined __sparc__ && defined __arch64__
+# define STACK_CHK_GUARD \
+ ({ uintptr_t x; asm ("ldx [%%g7+0x28], %0" : "=r" (x)); x; })
+#elif defined __sparc__
+# define STACK_CHK_GUARD \
+ ({ uintptr_t x; asm ("ld [%%g7+0x14], %0" : "=r" (x)); x; })
+#elif defined __s390x__
+# define STACK_CHK_GUARD \
+ ({ uintptr_t x; asm ("ear %0,%a0; sllg %0,%0,32; ear %0,%a1; lg %0,0x28(%0)" : "=r" (x)); x; })
+#elif defined __s390__
+# define STACK_CHK_GUARD \
+ ({ uintptr_t x; asm ("ear %0,%%a0; l %0,0x14(%0)" : "=r" (x)); x; })
+#else
+extern uintptr_t __stack_chk_guard;
+# define STACK_CHK_GUARD __stack_chk_guard
+#endif
diff --git a/elf/tst-stackguard1-static.c b/elf/tst-stackguard1-static.c
new file mode 100644
index 0000000000..db1e21554d
--- /dev/null
+++ b/elf/tst-stackguard1-static.c
@@ -0,0 +1 @@
+#include "tst-stackguard1.c"
diff --git a/elf/tst-stackguard1.c b/elf/tst-stackguard1.c
new file mode 100644
index 0000000000..480f9297d0
--- /dev/null
+++ b/elf/tst-stackguard1.c
@@ -0,0 +1,196 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2005.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <stackguard-macros.h>
+#include <unistd.h>
+
+static const char *command;
+static bool child;
+static uintptr_t stack_chk_guard_copy;
+static bool stack_chk_guard_copy_set;
+static int fds[2];
+
+static void __attribute__ ((constructor))
+con (void)
+{
+ stack_chk_guard_copy = STACK_CHK_GUARD;
+ stack_chk_guard_copy_set = true;
+}
+
+static int
+uintptr_t_cmp (const void *a, const void *b)
+{
+ if (*(uintptr_t *) a < *(uintptr_t *) b)
+ return 1;
+ if (*(uintptr_t *) a > *(uintptr_t *) b)
+ return -1;
+ return 0;
+}
+
+static int
+do_test (void)
+{
+ if (!stack_chk_guard_copy_set)
+ {
+ puts ("constructor has not been run");
+ return 1;
+ }
+
+ if (stack_chk_guard_copy != STACK_CHK_GUARD)
+ {
+ puts ("STACK_CHK_GUARD changed between constructor and do_test");
+ return 1;
+ }
+
+ if (child)
+ {
+ write (2, &stack_chk_guard_copy, sizeof (stack_chk_guard_copy));
+ return 0;
+ }
+
+ if (command == NULL)
+ {
+ puts ("missing --command or --child argument");
+ return 1;
+ }
+
+#define N 16
+ uintptr_t child_stack_chk_guards[N + 1];
+ child_stack_chk_guards[N] = stack_chk_guard_copy;
+ int i;
+ for (i = 0; i < N; ++i)
+ {
+ if (pipe (fds) < 0)
+ {
+ printf ("couldn't create pipe: %m\n");
+ return 1;
+ }
+
+ pid_t pid = fork ();
+ if (pid < 0)
+ {
+ printf ("fork failed: %m\n");
+ return 1;
+ }
+
+ if (!pid)
+ {
+ if (stack_chk_guard_copy != STACK_CHK_GUARD)
+ {
+ puts ("STACK_CHK_GUARD changed after fork");
+ exit (1);
+ }
+
+ close (fds[0]);
+ close (2);
+ dup2 (fds[1], 2);
+ close (fds[1]);
+
+ system (command);
+ exit (0);
+ }
+
+ close (fds[1]);
+
+ if (TEMP_FAILURE_RETRY (read (fds[0], &child_stack_chk_guards[i],
+ sizeof (uintptr_t))) != sizeof (uintptr_t))
+ {
+ puts ("could not read stack_chk_guard value from child");
+ return 1;
+ }
+
+ close (fds[0]);
+
+ pid_t termpid;
+ int status;
+ termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
+ if (termpid == -1)
+ {
+ printf ("waitpid failed: %m\n");
+ return 1;
+ }
+ else if (termpid != pid)
+ {
+ printf ("waitpid returned %ld != %ld\n",
+ (long int) termpid, (long int) pid);
+ return 1;
+ }
+ else if (!WIFEXITED (status) || WEXITSTATUS (status))
+ {
+ puts ("child hasn't exited with exit status 0");
+ return 1;
+ }
+ }
+
+ qsort (child_stack_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp);
+
+ uintptr_t default_guard = 0;
+ unsigned char *p = (unsigned char *) &default_guard;
+ p[sizeof (uintptr_t) - 1] = 255;
+ p[sizeof (uintptr_t) - 2] = '\n';
+ p[0] = 0;
+
+ /* Test if the stack guard canaries are either randomized,
+ or equal to the default stack guard canary value.
+ Even with randomized stack guards it might happen
+ that the random number generator generates the same
+ values, but if that happens in more than half from
+ the 16 runs, something is very wrong. */
+ int ndifferences = 0;
+ int ndefaults = 0;
+ for (i = 0; i < N; ++i)
+ {
+ if (child_stack_chk_guards[i] != child_stack_chk_guards[i+1])
+ ndifferences++;
+ else if (child_stack_chk_guards[i] == default_guard)
+ ndefaults++;
+ }
+
+ printf ("differences %d defaults %d\n", ndifferences, ndefaults);
+
+ if (ndifferences < N / 2 && ndefaults < N / 2)
+ {
+ puts ("stack guard canaries are not randomized enough");
+ puts ("nor equal to the default canary value");
+ return 1;
+ }
+
+ return 0;
+}
+
+#define OPT_COMMAND 10000
+#define OPT_CHILD 10001
+#define CMDLINE_OPTIONS \
+ { "command", required_argument, NULL, OPT_COMMAND }, \
+ { "child", no_argument, NULL, OPT_CHILD },
+#define CMDLINE_PROCESS \
+ case OPT_COMMAND: \
+ command = optarg; \
+ break; \
+ case OPT_CHILD: \
+ child = true; \
+ break;
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"