[02/15] Initialize the stack guard earlier when linking statically.

Message ID 20161219111528.14969-3-nix@esperi.org.uk
State Superseded
Headers

Commit Message

Nix Dec. 19, 2016, 11:15 a.m. UTC
  From: Nick Alcock <nick.alcock@oracle.com>

The address of the stack canary is stored in a per-thread variable,
which means that we must ensure that the TLS area is intialized before
calling any -fstack-protector'ed functions.  For dynamically linked
applications, we ensure this (in a later patch) by disabling
-fstack-protector for the whole dynamic linker, but for static
applications the AT_ENTRY address is called directly by the kernel, so
we must deal with the problem differently.

So split out the part of pthread initialization that sets up the TCB
(and, more generally, the TLS area) into a separate function (twice --
there is one implementation in libpthread.a, and another outside it for
programs that do not link with libpthread), then call it at
initialization time.  Call that, and move the stack guard initialization
above the DL_SYSDEP_OSCHECK hook, which if set will probably call
functions which are stack-protected (it does on Linux and NaCL too).
We also move apply_irel() up, so that we can still safely call functions
that require ifuncs while in __pthread_initialize_tcb_internal()
(though if stack-protection is enabled we still have to avoid calling
functions that are not stack-protected at this stage).

v2: describe why we don't move apply_irel() up, and the consequences.
v6: We can safely move apply_irel() up now.

	* nptl/nptl-init.c (__pthread_initialize_tcb_internal): New
	function, split out from...
	(__pthread_initialize_minimal_internal): ... here.
	* csu/libc-start.c (LIBC_START_MAIN): Call it.  Move stack canary
	and apply_irel() initialization up.
---
 csu/libc-start.c | 26 +++++++++++++++-----------
 csu/libc-tls.c   |  8 ++++++++
 nptl/nptl-init.c | 11 +++++++----
 3 files changed, 30 insertions(+), 15 deletions(-)
  

Comments

Florian Weimer Dec. 21, 2016, 2:16 p.m. UTC | #1
On 12/19/2016 12:15 PM, Nix wrote:
> From: Nick Alcock <nick.alcock@oracle.com>
>
> The address of the stack canary is stored in a per-thread variable,
> which means that we must ensure that the TLS area is intialized before
> calling any -fstack-protector'ed functions.  For dynamically linked
> applications, we ensure this (in a later patch) by disabling
> -fstack-protector for the whole dynamic linker, but for static
> applications the AT_ENTRY address is called directly by the kernel, so
> we must deal with the problem differently.
>
> So split out the part of pthread initialization that sets up the TCB
> (and, more generally, the TLS area) into a separate function (twice --
> there is one implementation in libpthread.a, and another outside it for
> programs that do not link with libpthread), then call it at
> initialization time.  Call that, and move the stack guard initialization
> above the DL_SYSDEP_OSCHECK hook, which if set will probably call
> functions which are stack-protected (it does on Linux and NaCL too).
> We also move apply_irel() up, so that we can still safely call functions
> that require ifuncs while in __pthread_initialize_tcb_internal()
> (though if stack-protection is enabled we still have to avoid calling
> functions that are not stack-protected at this stage).

I'm changing this to call __libc_setup_tls directly.  This functions is 
in csu/ and thus automatically exempted from stack protection.  There is 
no need to go indirectly through a definition in nptl/.

(The old approach stems from the days where TLS was optional.)

Florian
  

Patch

diff --git a/csu/libc-start.c b/csu/libc-start.c
index 99c040a..0bd4385 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -30,6 +30,7 @@  extern int __libc_multiple_libcs;
 #ifndef SHARED
 # include <dl-osinfo.h>
 extern void __pthread_initialize_minimal (void);
+extern void __pthread_initialize_tcb_internal (void);
 # ifndef THREAD_SET_STACK_GUARD
 /* Only exported for architectures that don't store the stack guard canary
    in thread local area.  */
@@ -175,6 +176,20 @@  LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
         }
     }
 
+  /* Perform IREL{,A} relocations.  */
+  apply_irel ();
+
+  /* The stack guard goes into the TCB.  */
+  __pthread_initialize_tcb_internal ();
+
+  /* Set up the stack checker's canary.  */
+  uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
+# ifdef THREAD_SET_STACK_GUARD
+  THREAD_SET_STACK_GUARD (stack_chk_guard);
+# else
+  __stack_chk_guard = stack_chk_guard;
+# endif
+
 # ifdef DL_SYSDEP_OSCHECK
   if (!__libc_multiple_libcs)
     {
@@ -184,22 +199,11 @@  LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
     }
 # endif
 
-  /* Perform IREL{,A} relocations.  */
-  apply_irel ();
-
   /* Initialize the thread library at least a bit since the libgcc
      functions are using thread functions if these are available and
      we need to setup errno.  */
   __pthread_initialize_minimal ();
 
-  /* Set up the stack checker's canary.  */
-  uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
-# ifdef THREAD_SET_STACK_GUARD
-  THREAD_SET_STACK_GUARD (stack_chk_guard);
-# else
-  __stack_chk_guard = stack_chk_guard;
-# endif
-
   /* Set up the pointer guard value.  */
   uintptr_t pointer_chk_guard = _dl_setup_pointer_guard (_dl_random,
 							 stack_chk_guard);
diff --git a/csu/libc-tls.c b/csu/libc-tls.c
index 235ac79..b92c567 100644
--- a/csu/libc-tls.c
+++ b/csu/libc-tls.c
@@ -241,5 +241,13 @@  void
 __attribute__ ((weak))
 __pthread_initialize_minimal (void)
 {
+}
+
+/* This is the minimal initialization function used when libpthread is
+   not used.  */
+void
+__attribute__ ((weak))
+__pthread_initialize_tcb_internal (void)
+{
   __libc_setup_tls (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN);
 }
diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c
index 48fab50..dea335d 100644
--- a/nptl/nptl-init.c
+++ b/nptl/nptl-init.c
@@ -285,21 +285,24 @@  extern void **__libc_dl_error_tsd (void) __attribute__ ((const));
 /* This can be set by the debugger before initialization is complete.  */
 static bool __nptl_initial_report_events __attribute_used__;
 
+#ifndef SHARED
 void
-__pthread_initialize_minimal_internal (void)
+__pthread_initialize_tcb_internal (void)
 {
-#ifndef SHARED
   /* Unlike in the dynamically linked case the dynamic linker has not
      taken care of initializing the TLS data structures.  */
   __libc_setup_tls (TLS_TCB_SIZE, TLS_TCB_ALIGN);
 
-  /* We must prevent gcc from being clever and move any of the
+  /* We must prevent gcc from being clever after inlining and moving any of the
      following code ahead of the __libc_setup_tls call.  This function
      will initialize the thread register which is subsequently
      used.  */
   __asm __volatile ("");
+}
 #endif
-
+void
+__pthread_initialize_minimal_internal (void)
+{
   /* Minimal initialization of the thread descriptor.  */
   struct pthread *pd = THREAD_SELF;
   __pthread_initialize_pids (pd);