aboutsummaryrefslogtreecommitdiff
path: root/nptl/tst-stackguard1.c
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 /nptl/tst-stackguard1.c
parent2f37117b013f77df863b198c3408555c49596174 (diff)
downloadglibc-35f1e82763326f196fd068e92343643d8ed54ee3.zip
glibc-35f1e82763326f196fd068e92343643d8ed54ee3.tar.gz
glibc-35f1e82763326f196fd068e92343643d8ed54ee3.tar.bz2
* 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 'nptl/tst-stackguard1.c')
-rw-r--r--nptl/tst-stackguard1.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/nptl/tst-stackguard1.c b/nptl/tst-stackguard1.c
new file mode 100644
index 0000000..15c30ae
--- /dev/null
+++ b/nptl/tst-stackguard1.c
@@ -0,0 +1,226 @@
+/* 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 <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <elf/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 void *
+tf (void *arg)
+{
+ if (stack_chk_guard_copy != STACK_CHK_GUARD)
+ {
+ puts ("STACK_CHK_GUARD changed in thread");
+ return (void *) 1L;
+ }
+ return NULL;
+}
+
+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)
+ {
+ int i;
+ pthread_t th[4];
+ void *ret;
+ for (i = 0; i < 4; ++i)
+ if (pthread_create (&th[i], NULL, tf, NULL))
+ {
+ puts ("thread creation failed");
+ return 1;
+ }
+ for (i = 0; i < 4; ++i)
+ if (pthread_join (th[i], &ret))
+ {
+ puts ("thread join failed");
+ return 1;
+ }
+ else if (ret != NULL)
+ return 1;
+
+ 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"