This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC PATCH] glibc part of stack protector


Hi!

In http://gcc.gnu.org/ml/gcc-patches/2005-05/msg01193.html
Richard Henderson posted a patch to implement -fstack-protector
in GCC 4+.  It can either use support stuff in libgcc.{a,so},
or in libc.  This patch adds support for that to glibc.
As the kernel doesn't provide a random integer to the programs
in aux vector (yet), the initialization is quite expensive
(open/read/close from /dev/urandom) and especially for the time being,
as not everybody is going to use GCC with -fstack-protector,
all that on every program startup would be done completely needlessly
for all those people, I have made it optional.  The default
is now that __stack_chk_guard will be initialized by the default
0 ... '\n' 255 magic, but if you know you are going to use
-fstack-protector compiled programs extensively,
--enable-stackguard-randomization as configure option is highly
desirable.

Tested on x86-64 (NPTL and LinuxThreads) and ppc64 (NPTL) so far.
Some architectures like Alpha are probably going to always use
__stack_chk_guard variable, but on i386/x86-64/ppc/ppc64/s390/s390x
and likely ia64 it is better to use the thread local area access.

I'm still undecided whether we want to export __stack_chk_guard@@GLIBC_2.4
from ld.so on the architectures that are always going to use
the thread local area access.  The patch below exports it unconditionally,
to export it only for Alpha etc. it would need to avoid the
__stack_chk_guard variable altogether if THREAD_SET_STACK_GUARD
macro is defined.

I will post corresponding GCC patches later today.

2005-06-24  Jakub Jelinek  <jakub@redhat.com>

	* 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.
	* configure: Rebuilt.
	* 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.
	* elf/Versions (ld): Export __stack_chk_guard@@GLIBC_2.4.
	(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.
	* 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
	tracesof 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.
nptl/
	* sysdeps/i386/tls.h (tcbhead_t): Add stack_guard field.
	(THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
	* sysdeps/x86_64/tls.h (tcbhead_t): Add sysinfo and stack_guard
	fields.
	(THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
	* sysdeps/s390/tls.h (tcbhead_t): Add stack_guard
	field.  Put in sysinfo field unconditionally.
	(THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
	* sysdeps/powerpc/tls.h (tcbhead_t): Add stack_guard field.
	(THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
	* sysdeps/sparc/tls.h (tcbhead_t): Add sysinfo and stack_guard
	fields.
	(THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
	* pthread_create.c (__pthread_create_2_1): Use
	THREAD_COPY_STACK_GUARD macro.
	* Makefile: Add rules to build and run tst-stackguard1{,-static}
	tests.
	* tst-stackguard1.c: New file.
	* tst-stackguard1-static.c: New file.
linuxthreads/
	* pthread.c (__pthread_initialize_manager): Use
	THREAD_COPY_STACK_GUARD macro.
	* manager.c (pthread_handle_create): Likewise.
	* descr.h (struct _pthread_descr_struct): Add p_header.stack_guard
	field.  Put in p_header.sysinfo field unconditionally.
	* sysdeps/i386/tls.h (tcbhead_t): Add stack_guard field.  Put
	in sysinfo field unconditionally.
	(THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
	* sysdeps/x86_64/tls.h: Include stdint.h.
	(tcbhead_t): Add sysinfo and stack_guard fields.
	(THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
	* sysdeps/s390/tls.h: Include stdint.h.
	(tcbhead_t): Add sysinfo and stack_guard fields.
	(THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
	* sysdeps/powerpc/tls.h: Include stdint.h.
	(tcbhead_t): Add in stack_guard field.
	(THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
	(NONTLS_INIT_TP): Fix for current TLS ABI.
	* sysdeps/sparc/tls.h: Include stdint.h.
	(tcbhead_t): Add sysinfo and stack_guard fields.
	(THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
	* Makefile: Add rules to build and run tst-stackguard1{,-static}
	tests.
	* tst-stackguard1.c: New file.
	* tst-stackguard1-static.c: New file.

--- libc/elf/Makefile.jj	2005-04-27 14:03:47.000000000 +0200
+++ libc/elf/Makefile	2005-06-23 18:43:55.000000000 +0200
@@ -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 l
 	 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)order2m
 $(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"
--- libc/elf/tst-stackguard1.c.jj	2005-06-23 17:03:19.000000000 +0200
+++ libc/elf/tst-stackguard1.c	2005-06-23 18:45:31.000000000 +0200
@@ -0,0 +1,216 @@
+/* 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 con_failure, stack_chk_guard_copy_set;
+static int fds[2];
+
+static void __attribute__ ((constructor))
+con (void)
+{
+  stack_chk_guard_copy = __stack_chk_guard;
+  if (stack_chk_guard_copy != STACK_CHK_GUARD)
+    con_failure = true;
+  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 (con_failure)
+    {
+      puts ("STACK_CHK_GUARD != __stack_chk_guard in the constructor");
+      return 1;
+    }
+
+  if (stack_chk_guard_copy != __stack_chk_guard)
+    {
+      puts ("__stack_chk_guard changed between constructor and do_test");
+      return 1;
+    }
+
+  if (__stack_chk_guard != STACK_CHK_GUARD)
+    {
+      puts ("STACK_CHK_GUARD != __stack_chk_guard in 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);
+	    }
+
+	  if (__stack_chk_guard != STACK_CHK_GUARD)
+	    {
+	      puts ("STACK_CHK_GUARD != __stack_chk_guard 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"
--- libc/elf/rtld.c.jj	2005-06-23 12:15:47.000000000 +0200
+++ libc/elf/rtld.c	2005-06-23 14:19:23.000000000 +0200
@@ -80,6 +80,8 @@ char **_dl_argv attribute_relro = NULL;
 #endif
 INTDEF(_dl_argv)
 
+uintptr_t __stack_chk_guard attribute_relro;
+
 /* Nonzero if we were run directly.  */
 unsigned int _dl_skip_args attribute_relro attribute_hidden;
 
@@ -1398,9 +1400,6 @@ ld.so does not support TLS, but program 
 	     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 +1806,16 @@ ERROR: ld.so: object '%s' cannot be load
      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.  */
+  __stack_chk_guard = _dl_setup_stack_chk_guard ();
+#ifdef THREAD_SET_STACK_GUARD
+  THREAD_SET_STACK_GUARD (__stack_chk_guard);
+#endif
+
   if (__builtin_expect (mode, normal) != normal)
     {
       /* We were run just to list the shared libraries.  It is
@@ -2230,29 +2235,26 @@ ERROR: ld.so: object '%s' cannot be load
 #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);
-
-      /* 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);
-	}
+  /* 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);
     }
-  else
+#else
+  NONTLS_INIT_TP;
 #endif
-    NONTLS_INIT_TP;
 
 #ifdef SHARED
   /* Auditing checkpoint: we have added all objects.  */
--- libc/elf/Versions.jj	2005-05-03 21:50:14.000000000 +0200
+++ libc/elf/Versions	2005-06-23 12:22:09.000000000 +0200
@@ -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;
--- libc/elf/tst-stackguard1-static.c.jj	2005-06-23 18:41:42.000000000 +0200
+++ libc/elf/tst-stackguard1-static.c	2005-06-23 18:45:33.000000000 +0200
@@ -0,0 +1 @@
+#include "tst-stackguard1.c"
--- libc/elf/stackguard-macros.h.jj	2005-06-23 16:58:17.000000000 +0200
+++ libc/elf/stackguard-macros.h	2005-06-23 16:58:11.000000000 +0200
@@ -0,0 +1,31 @@
+#include <stdint.h>
+
+extern uintptr_t __stack_chk_guard;
+#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
+# define STACK_CHK_GUARD __stack_chk_guard
+#endif
+
--- libc/sysdeps/unix/sysv/linux/dl-osinfo.h.jj	2005-06-06 11:41:17.000000000 +0200
+++ libc/sysdeps/unix/sysv/linux/dl-osinfo.h	2005-06-23 16:08:51.000000000 +0200
@@ -23,6 +23,7 @@
 #include <sys/utsname.h>
 #include "kernel-features.h"
 #include <dl-sysdep.h>
+#include <stdint.h>
 
 #ifndef MIN
 # define MIN(a,b) (((a)<(b))?(a):(b))
@@ -157,3 +158,24 @@ _dl_discover_osversion (void)
     else if (__LINUX_KERNEL_VERSION > 0)				      \
       FATAL ("FATAL: cannot determine kernel version\n");		      \
   } while (0)
+
+static inline uintptr_t __attribute__ ((always_inline))
+_dl_setup_stack_chk_guard (void)
+{
+  uintptr_t ret;
+#ifdef ENABLE_STACKGUARD_RANDOMIZE
+  int fd = __open ("/dev/urandom", O_RDONLY);
+  if (fd >= 0)
+    {
+      ssize_t reslen = __read (fd, &ret, sizeof (ret));
+      __close (fd);
+      if (reslen == (ssize_t) sizeof (ret))
+	return ret;
+    }
+#endif
+  ret = 0;
+  unsigned char *p = (unsigned char *) &ret;
+  p[sizeof (ret) - 1] = 255;
+  p[sizeof (ret) - 2] = '\n';
+  return ret;
+}
--- libc/sysdeps/generic/libc-start.c.jj	2005-02-21 17:20:16.000000000 +0100
+++ libc/sysdeps/generic/libc-start.c	2005-06-23 16:34:49.000000000 +0200
@@ -35,6 +35,7 @@ extern void __pthread_initialize_minimal
      __attribute__ ((weak))
 # endif
      ;
+uintptr_t __stack_chk_guard attribute_relro;
 #endif
 
 #ifdef HAVE_PTR_NTHREADS
@@ -152,6 +153,14 @@ LIBC_START_MAIN (int (*main) (int, char 
     __pthread_initialize_minimal ();
 #endif
 
+# ifndef SHARED
+  /* Set up the stack checker's canary.  */
+  __stack_chk_guard = _dl_setup_stack_chk_guard ();
+#  ifdef THREAD_SET_STACK_GUARD
+  THREAD_SET_STACK_GUARD (__stack_chk_guard);
+#  endif
+#endif
+
   /* Register the destructor of the dynamic linker if there is any.  */
   if (__builtin_expect (rtld_fini != NULL, 1))
     __cxa_atexit ((void (*) (void *)) rtld_fini, NULL, NULL);
--- libc/sysdeps/generic/libc-tls.c.jj	2005-02-25 14:45:06.000000000 +0100
+++ libc/sysdeps/generic/libc-tls.c	2005-06-23 16:28:55.000000000 +0200
@@ -133,17 +133,6 @@ __libc_setup_tls (size_t tcbsize, size_t
 	  break;
 	}
 
-#ifdef TLS_INIT_TP_EXPENSIVE
-  if (memsz == 0 && tcbsize <= TLS_INIT_TCB_SIZE)
-    {
-      /* We do not need a TLS block and no thread descriptor.  */
-# ifdef NONTLS_INIT_TP
-      NONTLS_INIT_TP;
-# endif
-      return;
-    }
-#endif
-
   /* We have to set up the TCB block which also (possibly) contains
      'errno'.  Therefore we avoid 'malloc' which might touch 'errno'.
      Instead we use 'sbrk' which would only uses 'errno' if it fails.
--- libc/sysdeps/generic/dl-osinfo.h.jj	2005-05-03 21:50:44.000000000 +0200
+++ libc/sysdeps/generic/dl-osinfo.h	2005-06-23 18:28:55.000000000 +0200
@@ -1 +1,12 @@
-/* Nothing needed in general.  */
+#include <stdint.h>
+
+static inline uintptr_t __attribute__ ((always_inline))
+_dl_setup_stack_chk_guard (void)
+{
+  uintptr_t ret = 0;
+  unsigned char *p = (unsigned char *) &ret;
+  p[sizeof (ret) - 1] = 255;
+  p[sizeof (ret) - 2] = '\n';
+  p[0] = 0;
+  return ret;
+}
--- libc/nptl/Makefile.jj	2005-04-27 14:03:51.000000000 +0200
+++ libc/nptl/Makefile	2005-06-23 19:16:08.000000000 +0200
@@ -269,7 +269,8 @@ tests += tst-cancelx2 tst-cancelx3 tst-c
 	 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
 		    $(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,noexecsta
 
 $(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:
--- libc/nptl/sysdeps/s390/tls.h.jj	2005-05-23 18:22:04.000000000 +0200
+++ libc/nptl/sysdeps/s390/tls.h	2005-06-23 12:22:09.000000000 +0200
@@ -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 */
--- libc/nptl/sysdeps/powerpc/tls.h.jj	2005-05-03 21:50:31.000000000 +0200
+++ libc/nptl/sysdeps/powerpc/tls.h	2005-06-23 12:22:09.000000000 +0200
@@ -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__
 
 /* 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__
 
 /* 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__
 # 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
--- libc/nptl/sysdeps/sparc/tls.h.jj	2005-05-23 18:22:05.000000000 +0200
+++ libc/nptl/sysdeps/sparc/tls.h	2005-06-23 12:22:09.000000000 +0200
@@ -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 _
 #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 */
--- libc/nptl/sysdeps/i386/tls.h.jj	2005-05-23 18:22:02.000000000 +0200
+++ libc/nptl/sysdeps/i386/tls.h	2005-06-23 12:22:14.000000000 +0200
@@ -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 */
--- libc/nptl/sysdeps/x86_64/tls.h.jj	2005-05-23 18:22:11.000000000 +0200
+++ libc/nptl/sysdeps/x86_64/tls.h	2005-06-23 12:22:14.000000000 +0200
@@ -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 */
--- libc/nptl/tst-stackguard1.c.jj	2005-06-23 17:03:19.000000000 +0200
+++ libc/nptl/tst-stackguard1.c	2005-06-23 19:13:27.000000000 +0200
@@ -0,0 +1,252 @@
+/* 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 con_failure, stack_chk_guard_copy_set;
+static int fds[2];
+
+static void __attribute__ ((constructor))
+con (void)
+{
+  stack_chk_guard_copy = __stack_chk_guard;
+  if (stack_chk_guard_copy != STACK_CHK_GUARD)
+    con_failure = true;
+  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;
+    }
+
+  if (__stack_chk_guard != STACK_CHK_GUARD)
+    {
+      puts ("STACK_CHK_GUARD != __stack_chk_guard 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 (con_failure)
+    {
+      puts ("STACK_CHK_GUARD != __stack_chk_guard in the constructor");
+      return 1;
+    }
+
+  if (stack_chk_guard_copy != __stack_chk_guard)
+    {
+      puts ("__stack_chk_guard changed between constructor and do_test");
+      return 1;
+    }
+
+  if (__stack_chk_guard != STACK_CHK_GUARD)
+    {
+      puts ("STACK_CHK_GUARD != __stack_chk_guard in 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);
+	    }
+
+	  if (__stack_chk_guard != STACK_CHK_GUARD)
+	    {
+	      puts ("STACK_CHK_GUARD != __stack_chk_guard 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"
--- libc/nptl/pthread_create.c.jj	2005-05-03 21:50:28.000000000 +0200
+++ libc/nptl/pthread_create.c	2005-06-23 12:22:14.000000000 +0200
@@ -399,6 +399,11 @@ __pthread_create_2_1 (newthread, attr, s
   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)
--- libc/nptl/tst-stackguard1-static.c.jj	2005-06-23 18:41:42.000000000 +0200
+++ libc/nptl/tst-stackguard1-static.c	2005-06-23 19:15:12.000000000 +0200
@@ -0,0 +1 @@
+#include "tst-stackguard1.c"
--- libc/debug/Makefile.jj	2005-05-03 21:50:13.000000000 +0200
+++ libc/debug/Makefile	2005-06-23 12:56:11.000000000 +0200
@@ -31,9 +31,9 @@ routines  = backtrace backtracesyms back
 	    printf_chk fprintf_chk vprintf_chk vfprintf_chk \
 	    gets_chk chk_fail readonly-area fgets_chk fgets_u_chk \
 	    read_chk pread_chk pread64_chk recv_chk recvfrom_chk \
-	    readlink_chk getwd_chk getcwd_chk \
+	    readlink_chk getwd_chk getcwd_chk stack_chk_fail \
 	    $(static-only-routines)
-static-only-routines := warning-nop
+static-only-routines := warning-nop stack_chk_fail_local
 
 CFLAGS-backtrace.c = -fno-omit-frame-pointer
 CFLAGS-sprintf_chk.c = -D_IO_MTSAFE_IO
--- libc/debug/stack_chk_fail_local.c.jj	2005-06-23 12:52:34.000000000 +0200
+++ libc/debug/stack_chk_fail_local.c	2005-06-23 12:55:57.000000000 +0200
@@ -0,0 +1,30 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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 <sys/cdefs.h>
+
+extern void __stack_chk_fail (void) __attribute__ ((noreturn));
+
+/* On some architectures, this helps needless PIC pointer setup
+   that would be needed just for the __stack_chk_fail call.  */
+
+void __attribute__ ((noreturn)) attribute_hidden
+__stack_chk_fail_local (void)
+{
+  __stack_chk_fail ();
+}
--- libc/debug/stack_chk_fail.c.jj	2005-06-23 12:22:14.000000000 +0200
+++ libc/debug/stack_chk_fail.c	2005-06-23 12:22:14.000000000 +0200
@@ -0,0 +1,33 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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 <stdio.h>
+#include <stdlib.h>
+
+
+extern char **__libc_argv attribute_hidden;
+
+void
+__attribute__ ((noreturn))
+__stack_chk_fail (void)
+{
+  /* The loop is added only to keep gcc happy.  */
+  while (1)
+    __libc_message (1, "*** buffer overflow detected ***: %s terminated\n",
+		    __libc_argv[0] ?: "<unknown>");
+}
--- libc/debug/Versions.jj	2005-05-03 21:50:13.000000000 +0200
+++ libc/debug/Versions	2005-06-23 12:22:53.000000000 +0200
@@ -23,5 +23,7 @@ libc {
     __read_chk; __pread_chk; __pread64_chk;
     __readlink_chk; __getcwd_chk; __getwd_chk;
     __recv_chk; __recvfrom_chk;
+
+    __stack_chk_fail;
   }
 }
--- libc/config.h.in.jj	2005-06-22 18:34:09.000000000 +0200
+++ libc/config.h.in	2005-06-23 13:25:00.000000000 +0200
@@ -223,6 +223,9 @@
 /* Define if your assembler and linker support R_PPC_REL16* relocs.  */
 #undef HAVE_ASM_PPC_REL16
 
+/* Define if __stack_chk_guard canary should be randomized at program startup.  */
+#undef ENABLE_STACKGUARD_RANDOMIZE
+
 /*
  */
 
--- libc/Versions.def.jj	2005-05-03 21:50:05.000000000 +0200
+++ libc/Versions.def	2005-06-23 14:02:50.000000000 +0200
@@ -102,6 +102,7 @@ ld {
   GLIBC_2.0
   GLIBC_2.1
   GLIBC_2.3
+  GLIBC_2.4
   GLIBC_PRIVATE
 }
 libthread_db {
--- libc/linuxthreads/Makefile.jj	2005-02-08 17:17:06.000000000 +0100
+++ libc/linuxthreads/Makefile	2005-06-23 19:19:09.000000000 +0200
@@ -117,13 +117,14 @@ test-srcs = tst-signal
 tests-reverse += tst-cancel5
 
 ifeq ($(build-static),yes)
-tests += tststatic tst-static-locale tst-cancel-static
-tests-static += tststatic tst-static-locale tst-cancel-static
+tests += tststatic tst-static-locale tst-cancel-static tst-stackguard1-static
+tests-static += tststatic tst-static-locale tst-cancel-static \
+		tst-stackguard1-static
 endif
 
 ifeq (yes,$(build-shared))
 tests-nodelete-yes = unload
-tests += tst-tls1 tst-_res1
+tests += tst-tls1 tst-_res1 tst-stackguard1
 endif
 
 modules-names = tst-_res1mod1 tst-_res1mod2 \
@@ -343,3 +344,6 @@ $(objpfx)tst-cancel-wrappers.out: tst-ca
 generated += tst-signal.out tst-cancel-wrappers.out
 endif
 endif
+
+tst-stackguard1-ARGS = --command "$(built-program-cmd) --child"
+tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child"
--- libc/linuxthreads/sysdeps/s390/tls.h.jj	2005-05-03 21:50:22.000000000 +0200
+++ libc/linuxthreads/sysdeps/s390/tls.h	2005-06-23 12:22:14.000000000 +0200
@@ -25,6 +25,7 @@
 # include <pt-machine.h>
 # include <stdbool.h>
 # include <stddef.h>
+# include <stdint.h>
 
 /* Type for the dtv.  */
 typedef union dtv
@@ -44,6 +45,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__ */
@@ -122,9 +125,16 @@ typedef struct
 #  define THREAD_DTV() \
   (((tcbhead_t *) __builtin_thread_pointer ())->dtv)
 
+/* Set the stack guard field in TCB head.  */
+#  define THREAD_SET_STACK_GUARD(value) \
+  THREAD_SETMEM (THREAD_SELF, p_header.data.stack_guard, value)
+#  define THREAD_COPY_STACK_GUARD(descr) \
+  ((descr)->p_header.data.stack_guard					      \
+   = THREAD_GETMEM (THREAD_SELF, p_header.data.stack_guard))
+
 # endif /* __ASSEMBLER__ */
 
-#else	/* HAVE_TLS_SUPPORT && (FLOATING_STACKS || !IS_IN_libpthread) */
+#else	/* HAVE_TLS_SUPPORT */
 
 # ifndef __ASSEMBLER__
 
@@ -140,6 +150,6 @@ typedef struct
 
 # endif /* __ASSEMBLER__ */
 
-#endif	/* HAVE_TLS_SUPPORT && (FLOATING_STACKS || !IS_IN_libpthread) */
+#endif	/* HAVE_TLS_SUPPORT */
 
 #endif	/* tls.h */
--- libc/linuxthreads/sysdeps/powerpc/tls.h.jj	2005-05-03 21:50:21.000000000 +0200
+++ libc/linuxthreads/sysdeps/powerpc/tls.h	2005-06-23 12:22:14.000000000 +0200
@@ -25,6 +25,7 @@
 # include <pt-machine.h>
 # include <stdbool.h>
 # include <stddef.h>
+# include <stdint.h>
 
 /* Type for the dtv.  */
 typedef union dtv
@@ -48,11 +49,11 @@ typedef union dtv
 
 # ifndef __ASSEMBLER__
 
-/* 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;
 
@@ -79,7 +80,7 @@ typedef struct
    assume that the pthread_descr is allocated immediately ahead of the
    TCB.  This implies that the pthread_descr address is
    TP - (TLS_PRE_TCB_SIZE + 0x7000).  */
-#define TLS_TCB_OFFSET		0x7000
+#  define TLS_TCB_OFFSET	0x7000
 
 /* The DTV is allocated at the TP; the TCB is placed elsewhere.  */
 /* This is not really true for powerpc64.  We are following alpha
@@ -138,6 +139,16 @@ typedef struct
    different value to mean unset l_tls_offset.  */
 #  define NO_TLS_OFFSET	-1
 
+/* 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)
+
 # endif /* __ASSEMBLER__ */
 
 #elif !defined __ASSEMBLER__
@@ -148,16 +159,16 @@ typedef struct
    single-threaded and multi-threaded code.  */
 typedef struct
 {
-  void *tcb;			/* Never used.  */
-  dtv_t *dtv;			/* Never used.  */
-  void *self;			/* Used only if multithreaded, and rarely.  */
-  int multiple_threads;		/* Only this member is really used.  */
+  uintptr_t stack_guard;
+  int multiple_threads;
 } tcbhead_t;
 
 #define NONTLS_INIT_TP							\
   do {									\
     static const tcbhead_t nontls_init_tp = { .multiple_threads = 0 };	\
-    __thread_self = (__typeof (__thread_self)) &nontls_init_tp;		\
+    char *addr;								\
+    __asm ("" : "r" (addr) : "0" (&nontls_init_tp[1]));			\
+    __thread_self = (__typeof (__thread_self)) (addr + TLS_TCB_OFFSET);	\
   } while (0)
 
 #endif /* HAVE_TLS_SUPPORT */
--- libc/linuxthreads/sysdeps/sparc/tls.h.jj	2005-05-03 21:50:23.000000000 +0200
+++ libc/linuxthreads/sysdeps/sparc/tls.h	2005-06-23 12:22:14.000000000 +0200
@@ -25,6 +25,7 @@
 # include <pt-machine.h>
 # include <stdbool.h>
 # include <stddef.h>
+# include <stdint.h>
 
 /* Type for the dtv.  */
 typedef union dtv
@@ -44,6 +45,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__ */
@@ -99,6 +102,13 @@ typedef struct
 #  define THREAD_DTV() \
   (((tcbhead_t *) __thread_self)->dtv)
 
+/* Set the stack guard field in TCB head.  */
+#  define THREAD_SET_STACK_GUARD(value) \
+  THREAD_SETMEM (THREAD_SELF, p_header.data.stack_guard, value)
+#  define THREAD_COPY_STACK_GUARD(descr) \
+  ((descr)->p_header.data.stack_guard					      \
+   = THREAD_GETMEM (THREAD_SELF, p_header.data.stack_guard))
+
 # endif
 
 #else
--- libc/linuxthreads/sysdeps/i386/tls.h.jj	2005-05-03 21:50:21.000000000 +0200
+++ libc/linuxthreads/sysdeps/i386/tls.h	2005-06-23 12:22:14.000000000 +0200
@@ -47,9 +47,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;
 
 #else /* __ASSEMBLER__ */
@@ -224,6 +223,13 @@ TLS_DO_MODIFY_LDT_KERNEL_CHECK(						   
   ({ struct _pthread_descr_struct *__descr;				      \
      THREAD_GETMEM (__descr, p_header.data.dtvp); })
 
+/* Set the stack guard field in TCB head.  */
+# define THREAD_SET_STACK_GUARD(value) \
+  THREAD_SETMEM (THREAD_SELF, p_header.data.stack_guard, value)
+# define THREAD_COPY_STACK_GUARD(descr) \
+  ((descr)->p_header.data.stack_guard					      \
+   = THREAD_GETMEM (THREAD_SELF, p_header.data.stack_guard))
+
 # endif	/* HAVE_TLS_SUPPORT && (FLOATING_STACKS || !IS_IN_libpthread) */
 #endif /* __ASSEMBLER__ */
 
--- libc/linuxthreads/sysdeps/x86_64/tls.h.jj	2005-05-03 21:50:25.000000000 +0200
+++ libc/linuxthreads/sysdeps/x86_64/tls.h	2005-06-23 12:22:14.000000000 +0200
@@ -25,6 +25,7 @@
 # include <pt-machine.h>
 # include <stdbool.h>
 # include <stddef.h>
+# include <stdint.h>
 
 /* Type for the dtv.  */
 typedef union dtv
@@ -45,6 +46,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__ */
@@ -128,6 +131,13 @@ typedef struct
   ({ struct _pthread_descr_struct *__descr;				      \
      THREAD_GETMEM (__descr, p_header.data.dtvp); })
 
+/* Set the stack guard field in TCB head.  */
+#  define THREAD_SET_STACK_GUARD(value) \
+  THREAD_SETMEM (THREAD_SELF, p_header.data.stack_guard, value)
+#  define THREAD_COPY_STACK_GUARD(descr) \
+  ((descr)->p_header.data.stack_guard					      \
+   = THREAD_GETMEM (THREAD_SELF, p_header.data.stack_guard))
+
 # endif	/* HAVE_TLS_SUPPORT */
 #endif /* __ASSEMBLER__ */
 
--- libc/linuxthreads/pthread.c.jj	2005-01-19 14:12:43.000000000 +0100
+++ libc/linuxthreads/pthread.c	2005-06-23 23:01:11.000000000 +0200
@@ -696,6 +696,11 @@ int __pthread_initialize_manager(void)
   mgr = &__pthread_manager_thread;
 #endif
 
+  /* Copy the stack guard canary.  */
+#ifdef THREAD_COPY_STACK_GUARD
+  THREAD_COPY_STACK_GUARD (mgr);
+#endif
+
   __pthread_manager_request = manager_pipe[1]; /* writing end */
   __pthread_manager_reader = manager_pipe[0]; /* reading end */
 
--- libc/linuxthreads/manager.c.jj	2005-05-03 21:50:20.000000000 +0200
+++ libc/linuxthreads/manager.c	2005-06-23 12:22:14.000000000 +0200
@@ -698,6 +698,12 @@ static int pthread_handle_create(pthread
   new_thread->p_start_args.start_routine = start_routine;
   new_thread->p_start_args.arg = arg;
   new_thread->p_start_args.mask = *mask;
+
+  /* Copy the stack guard canary.  */
+#ifdef THREAD_COPY_STACK_GUARD
+  THREAD_COPY_STACK_GUARD (new_thread);
+#endif
+
   /* Make the new thread ID available already now.  If any of the later
      functions fail we return an error value and the caller must not use
      the stored thread ID.  */
--- libc/linuxthreads/tst-stackguard1.c.jj	2005-06-23 17:03:19.000000000 +0200
+++ libc/linuxthreads/tst-stackguard1.c	2005-06-23 19:13:27.000000000 +0200
@@ -0,0 +1,252 @@
+/* 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 con_failure, stack_chk_guard_copy_set;
+static int fds[2];
+
+static void __attribute__ ((constructor))
+con (void)
+{
+  stack_chk_guard_copy = __stack_chk_guard;
+  if (stack_chk_guard_copy != STACK_CHK_GUARD)
+    con_failure = true;
+  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;
+    }
+
+  if (__stack_chk_guard != STACK_CHK_GUARD)
+    {
+      puts ("STACK_CHK_GUARD != __stack_chk_guard 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 (con_failure)
+    {
+      puts ("STACK_CHK_GUARD != __stack_chk_guard in the constructor");
+      return 1;
+    }
+
+  if (stack_chk_guard_copy != __stack_chk_guard)
+    {
+      puts ("__stack_chk_guard changed between constructor and do_test");
+      return 1;
+    }
+
+  if (__stack_chk_guard != STACK_CHK_GUARD)
+    {
+      puts ("STACK_CHK_GUARD != __stack_chk_guard in 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);
+	    }
+
+	  if (__stack_chk_guard != STACK_CHK_GUARD)
+	    {
+	      puts ("STACK_CHK_GUARD != __stack_chk_guard 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"
--- libc/linuxthreads/descr.h.jj	2005-05-03 21:50:20.000000000 +0200
+++ libc/linuxthreads/descr.h	2005-06-23 12:22:14.000000000 +0200
@@ -120,9 +120,8 @@ struct _pthread_descr_struct
       union dtv *dtvp;
       pthread_descr self;	/* Pointer to this structure */
       int multiple_threads;
-# ifdef NEED_DL_SYSINFO
       uintptr_t sysinfo;
-# endif
+      uintptr_t stack_guard;
     } data;
     void *__padding[16];
   } p_header;
--- libc/linuxthreads/tst-stackguard1-static.c.jj	2005-06-23 18:41:42.000000000 +0200
+++ libc/linuxthreads/tst-stackguard1-static.c	2005-06-23 19:15:12.000000000 +0200
@@ -0,0 +1 @@
+#include "tst-stackguard1.c"
--- libc/configure.in.jj	2005-06-22 18:34:10.000000000 +0200
+++ libc/configure.in	2005-06-23 13:22:56.000000000 +0200
@@ -174,6 +174,15 @@ else
 fi
 AC_SUBST(oldest_abi)
 
+AC_ARG_ENABLE([stackguard-randomization],
+	      AC_HELP_STRING([--enable-stackguard-randomization],
+			     [initialize __stack_chk_guard canary with a random number at program start]),
+	      [enable_stackguard_randomize=$enableval],
+	      [enable_stackguard_randomize=no])
+if test "$enable_stackguard_randomize" = yes; then
+  AC_DEFINE(ENABLE_STACKGUARD_RANDOMIZE)
+fi
+
 dnl Generic infrastructure for drop-in additions to libc.
 AC_ARG_ENABLE([add-ons],
               AC_HELP_STRING([--enable-add-ons@<:@=DIRS...@:>@],
--- libc/configure.jj	2005-06-22 18:34:09.000000000 +0200
+++ libc/configure	2005-06-23 13:23:16.000000000 +0200
@@ -873,6 +873,9 @@ Optional Features:
                           objects [default=yes if supported]
   --enable-oldest-abi=ABI configure the oldest ABI supported [e.g. 2.2]
                           [default=glibc default]
+  --enable-stackguard-randomization
+                          initialize __stack_chk_guard canary with a random
+                          number at program start
   --enable-add-ons[=DIRS...]
                           configure and build add-ons in DIR1,DIR2,... search
                           for add-ons if no parameter given
@@ -1597,6 +1600,20 @@ _ACEOF
 fi
 
 
+# Check whether --enable-stackguard-randomization or --disable-stackguard-randomization was given.
+if test "${enable_stackguard_randomization+set}" = set; then
+  enableval="$enable_stackguard_randomization"
+  enable_stackguard_randomize=$enableval
+else
+  enable_stackguard_randomize=no
+fi;
+if test "$enable_stackguard_randomize" = yes; then
+  cat >>confdefs.h <<\_ACEOF
+#define ENABLE_STACKGUARD_RANDOMIZE 1
+_ACEOF
+
+fi
+
 # Check whether --enable-add-ons or --disable-add-ons was given.
 if test "${enable_add_ons+set}" = set; then
   enableval="$enable_add_ons"


	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]