From de6591238b478bc86b8cf5af01a484114e399213 Mon Sep 17 00:00:00 2001 From: Nick Alcock Date: Mon, 26 Dec 2016 10:08:41 +0100 Subject: [PATCH] Do not stack-protect ifunc resolvers [BZ #7065] When dynamically linking, ifunc resolvers are called before TLS is initialized, so they cannot be safely stack-protected. We avoid disabling stack-protection on large numbers of files by using __attribute__ ((__optimize__ ("-fno-stack-protector"))) to turn it off just for the resolvers themselves. (We provide the attribute even when statically linking, because we will later use it elsewhere too.) --- ChangeLog | 25 +++++++++++++++++++++ config.h.in | 4 ++++ configure | 2 ++ configure.ac | 1 + elf/ifuncdep2.c | 3 +++ elf/ifuncmain6pie.c | 1 + elf/ifuncmain7.c | 1 + elf/ifuncmod1.c | 3 +++ elf/ifuncmod5.c | 3 +++ include/libc-symbols.h | 12 +++++++++- sysdeps/generic/ifunc-sel.h | 2 ++ sysdeps/nacl/nacl_interface_query.c | 1 + sysdeps/powerpc/ifunc-sel.h | 2 ++ sysdeps/unix/make-syscalls.sh | 1 + sysdeps/unix/sysv/linux/x86_64/x32/getcpu.c | 1 + sysdeps/x86_64/ifuncmod8.c | 1 + 16 files changed, 62 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index f17669931b..395a14ba4d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2016-12-26 Nick Alcock + + [BZ #7065] + * configure.ac (HAVE_CC_NO_STACK_PROTECTOR): Define. + * config.h.in (HAVE_CC_NO_STACK_PROTECTOR): New macro. + * include/libc-symbols.h (inhibit_stack_protector): New macro. + (__ifunc_resolver): Use it. + * elf/ifuncdep2.c (foo1_ifunc, foo2_ifunc, foo3_ifunc): Apply + inhibit_stack_protector. + * elf/ifuncmain6pie.c (foo_ifunc): Likewise. + * elf/ifuncmain7.c (foo_ifunc): Likewise. + * elf/ifuncmod1.c (foo_ifunc, foo_hidden_ifunc) + (foo_protected_ifunc): Likewise. + * elf/ifuncmod5.c (foo_ifunc, foo_hidden_ifunc) + (foo_protected_ifunc): Likewise. + * sysdeps/generic/ifunc-sel.h (ifunc_sel, ifunc_one): Likewise. + * sysdeps/nacl/nacl_interface_query.c + (nacl_interface_query_ifunc): Likewise. + * sysdeps/powerpc/ifunc-sel.h (ifunc_sel, ifunc_one): Likewise. + * sysdeps/unix/sysv/linux/x86_64/x32/getcpu.c (getcpu_ifunc): + Likewise. + * sysdeps/x86_64/ifuncmod8.c (foo_ifunc): Likewise. + * sysdeps/unix/make-syscalls.sh: Apply inhibit_stack_protector to + the generated vDSO syscall resolver. + 2016-12-26 Nick Alcock Florian Weimer diff --git a/config.h.in b/config.h.in index d96ce0f8cf..82f95a6dbd 100644 --- a/config.h.in +++ b/config.h.in @@ -48,6 +48,10 @@ /* Define if compiler accepts -ftree-loop-distribute-patterns. */ #undef HAVE_CC_INHIBIT_LOOP_TO_LIBCALL +/* Define if compiler accepts -fno-stack-protector in an + __attribute__ ((__optimize__)). */ +#undef HAVE_CC_NO_STACK_PROTECTOR + /* The level of stack protection in use for glibc as a whole. May be overridden on a file-by-file basis. */ #ifndef STACK_PROTECTOR_LEVEL diff --git a/configure b/configure index 8c69f09232..b3007953ea 100755 --- a/configure +++ b/configure @@ -3994,6 +3994,8 @@ stack_protector= no_stack_protector= if test "$libc_cv_ssp" = yes; then no_stack_protector="-fno-stack-protector -DSTACK_PROTECTOR_LEVEL=0" + $as_echo "#define HAVE_CC_NO_STACK_PROTECTOR 1" >>confdefs.h + fi if test "$enable_stack_protector" = yes && test "$libc_cv_ssp" = yes; then diff --git a/configure.ac b/configure.ac index c159768984..f5fa1aaefa 100644 --- a/configure.ac +++ b/configure.ac @@ -653,6 +653,7 @@ stack_protector= no_stack_protector= if test "$libc_cv_ssp" = yes; then no_stack_protector="-fno-stack-protector -DSTACK_PROTECTOR_LEVEL=0" + AC_DEFINE(HAVE_CC_NO_STACK_PROTECTOR) fi if test "$enable_stack_protector" = yes && test "$libc_cv_ssp" = yes; then diff --git a/elf/ifuncdep2.c b/elf/ifuncdep2.c index 6e66d318a6..d87d61d5be 100644 --- a/elf/ifuncdep2.c +++ b/elf/ifuncdep2.c @@ -32,6 +32,7 @@ void * foo1_ifunc (void) __asm__ ("foo1"); __asm__(".type foo1, %gnu_indirect_function"); void * +inhibit_stack_protector foo1_ifunc (void) { return ifunc_sel (one, minus_one, zero); @@ -41,6 +42,7 @@ void * foo2_ifunc (void) __asm__ ("foo2"); __asm__(".type foo2, %gnu_indirect_function"); void * +inhibit_stack_protector foo2_ifunc (void) { return ifunc_sel (minus_one, one, zero); @@ -50,6 +52,7 @@ void * foo3_ifunc (void) __asm__ ("foo3"); __asm__(".type foo3, %gnu_indirect_function"); void * +inhibit_stack_protector foo3_ifunc (void) { return ifunc_sel (one, zero, minus_one); diff --git a/elf/ifuncmain6pie.c b/elf/ifuncmain6pie.c index 8478d4c408..04faeb86ef 100644 --- a/elf/ifuncmain6pie.c +++ b/elf/ifuncmain6pie.c @@ -21,6 +21,7 @@ void * foo_ifunc (void) __asm__ ("foo"); __asm__(".type foo, %gnu_indirect_function"); void * +inhibit_stack_protector foo_ifunc (void) { return ifunc_one (one); diff --git a/elf/ifuncmain7.c b/elf/ifuncmain7.c index 617a596d5e..1e8f7ea38e 100644 --- a/elf/ifuncmain7.c +++ b/elf/ifuncmain7.c @@ -20,6 +20,7 @@ __asm__(".type foo, %gnu_indirect_function"); static void * __attribute__ ((used)) +inhibit_stack_protector foo_ifunc (void) { return ifunc_one (one); diff --git a/elf/ifuncmod1.c b/elf/ifuncmod1.c index 0b6138056d..f0bf5fb45f 100644 --- a/elf/ifuncmod1.c +++ b/elf/ifuncmod1.c @@ -36,6 +36,7 @@ void * foo_ifunc (void) __asm__ ("foo"); __asm__(".type foo, %gnu_indirect_function"); void * +inhibit_stack_protector foo_ifunc (void) { return ifunc_sel (one, minus_one, zero); @@ -45,6 +46,7 @@ void * foo_hidden_ifunc (void) __asm__ ("foo_hidden"); __asm__(".type foo_hidden, %gnu_indirect_function"); void * +inhibit_stack_protector foo_hidden_ifunc (void) { return ifunc_sel (minus_one, one, zero); @@ -54,6 +56,7 @@ void * foo_protected_ifunc (void) __asm__ ("foo_protected"); __asm__(".type foo_protected, %gnu_indirect_function"); void * +inhibit_stack_protector foo_protected_ifunc (void) { return ifunc_sel (one, zero, minus_one); diff --git a/elf/ifuncmod5.c b/elf/ifuncmod5.c index 0e65a63691..5a957800e8 100644 --- a/elf/ifuncmod5.c +++ b/elf/ifuncmod5.c @@ -31,6 +31,7 @@ void * foo_ifunc (void) __asm__ ("foo"); __asm__(".type foo, %gnu_indirect_function"); void * +inhibit_stack_protector foo_ifunc (void) { return ifunc_sel (one, minus_one, zero); @@ -40,6 +41,7 @@ void * foo_hidden_ifunc (void) __asm__ ("foo_hidden"); __asm__(".type foo_hidden, %gnu_indirect_function"); void * +inhibit_stack_protector foo_hidden_ifunc (void) { return ifunc_sel (minus_one, one, zero); @@ -49,6 +51,7 @@ void * foo_protected_ifunc (void) __asm__ ("foo_protected"); __asm__(".type foo_protected, %gnu_indirect_function"); void * +inhibit_stack_protector foo_protected_ifunc (void) { return ifunc_sel (one, zero, minus_one); diff --git a/include/libc-symbols.h b/include/libc-symbols.h index 4238d7930b..d981e67343 100644 --- a/include/libc-symbols.h +++ b/include/libc-symbols.h @@ -336,6 +336,16 @@ for linking") #define attribute_relro __attribute__ ((section (".data.rel.ro"))) + +/* Used to disable stack protection in sensitive places, like ifunc + resolvers and early static TLS init. */ +#ifdef HAVE_CC_NO_STACK_PROTECTOR +# define inhibit_stack_protector \ + __attribute__ ((__optimize__ ("-fno-stack-protector"))) +#else +# define inhibit_stack_protector +#endif + /* The following macros are used for PLT bypassing within libc.so (and if needed other libraries similarly). First of all, you need to have the function prototyped somewhere, @@ -737,7 +747,7 @@ for linking") /* Helper / base macros for indirect function symbols. */ #define __ifunc_resolver(type_name, name, expr, arg, init, classifier) \ - classifier void *name##_ifunc (arg) \ + classifier inhibit_stack_protector void *name##_ifunc (arg) \ { \ init (); \ __typeof (type_name) *res = expr; \ diff --git a/sysdeps/generic/ifunc-sel.h b/sysdeps/generic/ifunc-sel.h index 6a27b69c5b..1fff4059cc 100644 --- a/sysdeps/generic/ifunc-sel.h +++ b/sysdeps/generic/ifunc-sel.h @@ -5,6 +5,7 @@ extern int global; static inline void * +inhibit_stack_protector ifunc_sel (int (*f1) (void), int (*f2) (void), int (*f3) (void)) { switch (global) @@ -19,6 +20,7 @@ ifunc_sel (int (*f1) (void), int (*f2) (void), int (*f3) (void)) } static inline void * +inhibit_stack_protector ifunc_one (int (*f1) (void)) { return f1; diff --git a/sysdeps/nacl/nacl_interface_query.c b/sysdeps/nacl/nacl_interface_query.c index adf1dd4c02..dbaa88b037 100644 --- a/sysdeps/nacl/nacl_interface_query.c +++ b/sysdeps/nacl/nacl_interface_query.c @@ -29,6 +29,7 @@ extern TYPE_nacl_irt_query nacl_interface_query_ifunc (void) asm ("nacl_interface_query"); TYPE_nacl_irt_query +inhibit_stack_protector nacl_interface_query_ifunc (void) { return &__nacl_irt_query; diff --git a/sysdeps/powerpc/ifunc-sel.h b/sysdeps/powerpc/ifunc-sel.h index ac589bd3c0..bdb00bf2c6 100644 --- a/sysdeps/powerpc/ifunc-sel.h +++ b/sysdeps/powerpc/ifunc-sel.h @@ -5,6 +5,7 @@ extern int global; static inline void * +inhibit_stack_protector ifunc_sel (int (*f1) (void), int (*f2) (void), int (*f3) (void)) { register void *ret __asm__ ("r3"); @@ -32,6 +33,7 @@ ifunc_sel (int (*f1) (void), int (*f2) (void), int (*f3) (void)) } static inline void * +inhibit_stack_protector ifunc_one (int (*f1) (void)) { register void *ret __asm__ ("r3"); diff --git a/sysdeps/unix/make-syscalls.sh b/sysdeps/unix/make-syscalls.sh index 58d165e015..123553c1d9 100644 --- a/sysdeps/unix/make-syscalls.sh +++ b/sysdeps/unix/make-syscalls.sh @@ -287,6 +287,7 @@ while read file srcfile caller syscall args strong weak; do (echo '#include '; \\ echo 'extern void *${strong}_ifunc (void) __asm ("${strong}");'; \\ echo 'void *'; \\ + echo 'inhibit_stack_protector'; \\ echo '${strong}_ifunc (void)'; \\ echo '{'; \\ echo ' PREPARE_VERSION_KNOWN (symver, ${vdso_symver});'; \\ diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/getcpu.c b/sysdeps/unix/sysv/linux/x86_64/x32/getcpu.c index cbac4b3273..8436f9db93 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/getcpu.c +++ b/sysdeps/unix/sysv/linux/x86_64/x32/getcpu.c @@ -21,6 +21,7 @@ void *getcpu_ifunc (void) __asm__ ("__getcpu"); void * +inhibit_stack_protector getcpu_ifunc (void) { PREPARE_VERSION (linux26, "LINUX_2.6", 61765110); diff --git a/sysdeps/x86_64/ifuncmod8.c b/sysdeps/x86_64/ifuncmod8.c index c00436799c..7c065622be 100644 --- a/sysdeps/x86_64/ifuncmod8.c +++ b/sysdeps/x86_64/ifuncmod8.c @@ -28,6 +28,7 @@ foo_impl (float x) } void * +inhibit_stack_protector foo_ifunc (void) { __m128i xmm = _mm_set1_epi32 (-1);