[02/18] Initialize the stack guard earlier when linking statically.
Commit Message
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 do not move apply_irel() up, because applying irels can require
state set up by the DL_SYSDEP_OSCHECK hook on some platforms. This
means, as a consequence, that __pthread_initialize_tcb_internal()
had better not call anything that requires ifuncs. (This is dealt
with in a later patch.)
v2: describe why we don't move apply_irel() up, and the consequences.
* 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
initialization up.
---
csu/libc-start.c | 20 ++++++++++++--------
csu/libc-tls.c | 8 ++++++++
nptl/nptl-init.c | 11 +++++++----
3 files changed, 27 insertions(+), 12 deletions(-)
Comments
these patches that can be merged by themselves (like this one) i think
we should do so sooner so we don't have to keep iterating on 15+ patches.
as things get reviewed, the pending patchset dwindles and we don't go so
crazy.
-mike
On 9 Mar 2016, Mike Frysinger outgrape:
> these patches that can be merged by themselves (like this one) i think
> we should do so sooner so we don't have to keep iterating on 15+ patches.
> as things get reviewed, the pending patchset dwindles and we don't go so
> crazy.
I have no fundamental objection to people doing that, as long as they're
happy with the patches -- but in most cases the patches are useless
deadweight if we don't get stack-protection in the end, so maybe you'd
rather I simply email out only those patches that have changed in each
round (which is easy, I'm tracking that anyway), and then apply the lot
at the end, once you know it's going to be accepted as a whole?
(The only patch here I'd call of truly general utility without
stack-protection is patch 17, the fix for the missing reload of %eax in
the pthread_cond_*wait() x86 assembler implementations.)
@@ -33,6 +33,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. */
@@ -178,6 +179,17 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
}
}
+ /* 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)
{
@@ -195,14 +207,6 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
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);
@@ -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);
}
@@ -296,21 +296,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);