about summary refs log tree commit diff
path: root/nptl
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
parent2f37117b013f77df863b198c3408555c49596174 (diff)
downloadglibc-35f1e82763326f196fd068e92343643d8ed54ee3.tar.gz
glibc-35f1e82763326f196fd068e92343643d8ed54ee3.tar.xz
glibc-35f1e82763326f196fd068e92343643d8ed54ee3.zip
* 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')
-rw-r--r--nptl/Makefile9
-rw-r--r--nptl/pthread_create.c5
-rw-r--r--nptl/sysdeps/i386/tls.h9
-rw-r--r--nptl/sysdeps/powerpc/tls.h22
-rw-r--r--nptl/sysdeps/s390/tls.h10
-rw-r--r--nptl/sysdeps/sparc/tls.h9
-rw-r--r--nptl/sysdeps/x86_64/tls.h9
-rw-r--r--nptl/tst-stackguard1-static.c1
-rw-r--r--nptl/tst-stackguard1.c226
9 files changed, 290 insertions, 10 deletions
diff --git a/nptl/Makefile b/nptl/Makefile
index 4c3cf941d1..71361c4ba9 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -269,7 +269,8 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \
 	 tst-oncex3 tst-oncex4
 endif
 ifeq ($(build-shared),yes)
-tests += tst-atfork2 tst-tls3 tst-tls4 tst-tls5 tst-_res1 tst-fini1
+tests += tst-atfork2 tst-tls3 tst-tls4 tst-tls5 tst-_res1 tst-fini1 \
+	 tst-stackguard1
 tests-nolibpthread += tst-fini1
 ifeq ($(have-z-execstack),yes)
 tests += tst-execstack
@@ -337,7 +338,8 @@ link-libc-static := $(common-objpfx)libc.a $(static-gnulib) \
 		    $(common-objpfx)libc.a
 
 ifeq ($(build-static),yes)
-tests-static += tst-locale1 tst-locale2
+tests-static += tst-locale1 tst-locale2 tst-stackguard1-static
+tests += tst-stackguard1-static
 xtests-static += tst-setuid1-static
 endif
 # These tests are linked with libc before libpthread
@@ -586,6 +588,9 @@ LDFLAGS-tst-execstack = -Wl,-z,noexecstack
 
 $(objpfx)tst-fini1mod.so: $(shared-thread-library)
 
+tst-stackguard1-ARGS = --command "$(built-program-cmd) --child"
+tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child"
+
 # The tests here better do not run in parallel
 ifneq ($(filter %tests,$(MAKECMDGOALS)),)
 .NOTPARALLEL:
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index 18f1c034c7..122778bddf 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -399,6 +399,11 @@ __pthread_create_2_1 (newthread, attr, start_routine, arg)
   pd->schedpolicy = self->schedpolicy;
   pd->schedparam = self->schedparam;
 
+  /* Copy the stack guard canary.  */
+#ifdef THREAD_COPY_STACK_GUARD
+  THREAD_COPY_STACK_GUARD (pd);
+#endif
+
   /* Determine scheduling parameters for the thread.  */
   if (attr != NULL
       && __builtin_expect ((iattr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0, 0)
diff --git a/nptl/sysdeps/i386/tls.h b/nptl/sysdeps/i386/tls.h
index c0331140f4..65566ff7a7 100644
--- a/nptl/sysdeps/i386/tls.h
+++ b/nptl/sysdeps/i386/tls.h
@@ -49,6 +49,7 @@ typedef struct
   void *self;		/* Pointer to the thread descriptor.  */
   int multiple_threads;
   uintptr_t sysinfo;
+  uintptr_t stack_guard;
 } tcbhead_t;
 
 # define TLS_MULTIPLE_THREADS_IN_TCB 1
@@ -416,6 +417,14 @@ union user_desc_init
      __res; })
 
 
+/* Set the stack guard field in TCB head.  */
+#define THREAD_SET_STACK_GUARD(value) \
+  THREAD_SETMEM (THREAD_SELF, header.stack_guard, value)
+#define THREAD_COPY_STACK_GUARD(descr) \
+  ((descr)->header.stack_guard						      \
+   = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
+
+
 #endif /* __ASSEMBLER__ */
 
 #endif	/* tls.h */
diff --git a/nptl/sysdeps/powerpc/tls.h b/nptl/sysdeps/powerpc/tls.h
index a7f69074e9..b2322b09bd 100644
--- a/nptl/sysdeps/powerpc/tls.h
+++ b/nptl/sysdeps/powerpc/tls.h
@@ -65,11 +65,11 @@ typedef union dtv
 /* Get the thread descriptor definition.  */
 # include <nptl/descr.h>
 
-/* This layout is actually wholly private and not affected by the ABI.
-   Nor does it overlap the pthread data structure, so we need nothing
-   extra here at all.  */
+/* The stack_guard is accessed directly by GCC -fstack-protector code,
+   so it is a part of public ABI.  The dtv field is private.  */
 typedef struct
 {
+  uintptr_t stack_guard;
   dtv_t *dtv;
 } tcbhead_t;
 
@@ -127,7 +127,7 @@ register void *__thread_register __asm__ ("r13");
 
 /* Return the address of the dtv for the current thread.  */
 # define THREAD_DTV() \
-     (((tcbhead_t *) (__thread_register - TLS_TCB_OFFSET))[-1].dtv)
+    (((tcbhead_t *) (__thread_register - TLS_TCB_OFFSET))[-1].dtv)
 
 /* Return the thread descriptor for the current thread.  */
 # define THREAD_SELF \
@@ -136,9 +136,9 @@ register void *__thread_register __asm__ ("r13");
 
 /* Magic for libthread_db to know how to do THREAD_SELF.  */
 # define DB_THREAD_SELF							      \
-  REGISTER (32, 32, PT_THREAD_POINTER * 4,					      \
+  REGISTER (32, 32, PT_THREAD_POINTER * 4,				      \
 	    - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)			      \
-  REGISTER (64, 64, PT_THREAD_POINTER * 8,					      \
+  REGISTER (64, 64, PT_THREAD_POINTER * 8,				      \
 	    - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
 
 /* Read member of the thread descriptor directly.  */
@@ -156,6 +156,16 @@ register void *__thread_register __asm__ ("r13");
 # define THREAD_SETMEM_NC(descr, member, idx, value) \
     ((void)(descr), (THREAD_SELF)->member[idx] = (value))
 
+/* Set the stack guard field in TCB head.  */
+# define THREAD_SET_STACK_GUARD(value) \
+    (((tcbhead_t *) ((char *) __thread_register				      \
+		     - TLS_TCB_OFFSET))[-1].stack_guard = (value))
+# define THREAD_COPY_STACK_GUARD(descr) \
+    (((tcbhead_t *) ((char *) (descr)					      \
+		     + TLS_PRE_TCB_SIZE))[-1].stack_guard		      \
+     = ((tcbhead_t *) ((char *) __thread_register			      \
+		       - TLS_TCB_OFFSET))[-1].stack_guard)
+
 /* l_tls_offset == 0 is perfectly valid on PPC, so we have to use some
    different value to mean unset l_tls_offset.  */
 # define NO_TLS_OFFSET		-1
diff --git a/nptl/sysdeps/s390/tls.h b/nptl/sysdeps/s390/tls.h
index 060dde39df..f90b35b1e5 100644
--- a/nptl/sysdeps/s390/tls.h
+++ b/nptl/sysdeps/s390/tls.h
@@ -48,9 +48,8 @@ typedef struct
   dtv_t *dtv;
   void *self;		/* Pointer to the thread descriptor.  */
   int multiple_threads;
-# ifdef NEED_DL_SYSINFO
   uintptr_t sysinfo;
-# endif
+  uintptr_t stack_guard;
 } tcbhead_t;
 
 # ifndef __s390x__
@@ -158,6 +157,13 @@ typedef struct
 #define THREAD_SETMEM_NC(descr, member, idx, value) \
   descr->member[idx] = (value)
 
+/* Set the stack guard field in TCB head.  */
+#define THREAD_SET_STACK_GUARD(value) \
+  THREAD_SETMEM (THREAD_SELF, header.stack_guard, value)
+#define THREAD_COPY_STACK_GUARD(descr) \
+  ((descr)->header.stack_guard						      \
+   = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
+
 #endif /* __ASSEMBLER__ */
 
 #endif	/* tls.h */
diff --git a/nptl/sysdeps/sparc/tls.h b/nptl/sysdeps/sparc/tls.h
index 54b54859d9..ddc4848554 100644
--- a/nptl/sysdeps/sparc/tls.h
+++ b/nptl/sysdeps/sparc/tls.h
@@ -46,6 +46,8 @@ typedef struct
   dtv_t *dtv;
   void *self;
   int multiple_threads;
+  uintptr_t sysinfo;
+  uintptr_t stack_guard;
 } tcbhead_t;
 
 #else /* __ASSEMBLER__ */
@@ -126,6 +128,13 @@ register struct pthread *__thread_self __asm__("%g7");
 #define THREAD_SETMEM_NC(descr, member, idx, value) \
   descr->member[idx] = (value)
 
+/* Set the stack guard field in TCB head.  */
+#define THREAD_SET_STACK_GUARD(value) \
+  THREAD_SETMEM (THREAD_SELF, header.stack_guard, value)
+# define THREAD_COPY_STACK_GUARD(descr) \
+  ((descr)->header.stack_guard \
+   = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
+
 #endif /* !ASSEMBLER */
 
 #endif	/* tls.h */
diff --git a/nptl/sysdeps/x86_64/tls.h b/nptl/sysdeps/x86_64/tls.h
index 3fc9b384aa..516827b8e1 100644
--- a/nptl/sysdeps/x86_64/tls.h
+++ b/nptl/sysdeps/x86_64/tls.h
@@ -47,6 +47,8 @@ typedef struct
   dtv_t *dtv;
   void *self;		/* Pointer to the thread descriptor.  */
   int multiple_threads;
+  uintptr_t sysinfo;
+  uintptr_t stack_guard;
 } tcbhead_t;
 
 #else /* __ASSEMBLER__ */
@@ -320,6 +322,13 @@ typedef struct
      __res; })
 
 
+/* Set the stack guard field in TCB head.  */
+# define THREAD_SET_STACK_GUARD(value) \
+    THREAD_SETMEM (THREAD_SELF, header.stack_guard, value)
+# define THREAD_COPY_STACK_GUARD(descr) \
+    ((descr)->header.stack_guard					      \
+     = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
+
 #endif /* __ASSEMBLER__ */
 
 #endif	/* tls.h */
diff --git a/nptl/tst-stackguard1-static.c b/nptl/tst-stackguard1-static.c
new file mode 100644
index 0000000000..db1e21554d
--- /dev/null
+++ b/nptl/tst-stackguard1-static.c
@@ -0,0 +1 @@
+#include "tst-stackguard1.c"
diff --git a/nptl/tst-stackguard1.c b/nptl/tst-stackguard1.c
new file mode 100644
index 0000000000..15c30aeb6b
--- /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"