From patchwork Sun Mar 13 15:16:48 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nix X-Patchwork-Id: 11317 Received: (qmail 42933 invoked by alias); 13 Mar 2016 15:17:18 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 42894 invoked by uid 89); 13 Mar 2016 15:17:16 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=1.4 required=5.0 tests=AWL, BAYES_50, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD autolearn=no version=3.3.2 spammy=57, 206, 436, 309 X-HELO: mail.esperi.org.uk From: Nix To: libc-alpha@sourceware.org Subject: [PATCH 03/17 v6] Do not stack-protect ifunc resolvers. Date: Sun, 13 Mar 2016 15:16:48 +0000 Message-Id: <1457882222-22599-4-git-send-email-nix@esperi.org.uk> In-Reply-To: <1457882222-22599-1-git-send-email-nix@esperi.org.uk> References: <1457882222-22599-1-git-send-email-nix@esperi.org.uk> X-DCC-wuwien-Metrics: spindle 1290; Body=1 Fuz1=1 Fuz2=1 From: Nick Alcock 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.) v4: New. v5: Comment fix. v6: Don't check for __attribute__((__optimize__)). * config.h.in (HAVE_CC_NO_STACK_PROTECTOR): New macro. * include/libc-symbols.h (inhibit_stack_protector): New macro. (libc_ifunc): Use it. (libm_ifunc): Likewise. * elf/ifuncdep2.c (foo1_ifunc): Add inhibit_stack_protector. (foo2_ifunc): Likewise. (foo3_ifunc): Likewise. * elf/ifuncmain6pie.c (foo_ifunc): Likewise. * elf/ifuncmain7.c (foo_ifunc): Likewise. * elf/ifuncmod1.c (foo_ifunc): Likewise. (foo_hidden_ifunc): Likewise. (foo_protected_ifunc): Likewise. * elf/ifuncmod5.c (foo_ifunc): Likewise. (foo_hidden_ifunc): Likewise. (foo_protected_ifunc): Likewise. * sysdeps/x86_64/ifuncmod8.c (foo_ifunc): Likewise. * nptl/pt-fork.c (fork_resolve): Likewise. * nptl/pt-longjmp.c (longjmp_resolve): Likewise. * nptl/pt-system.c (system_resolve): Likewise. * nptl/pt-vfork.c (vfork_resolve): Likewise. * rt/clock-compat.c [HAVE_IFUNC] (COMPAT_REDIRECT): Likewise. * sysdeps/generic/ifunc-sel.h (ifunc_sel): Likewise. (ifunc_one): Likewise. * sysdeps/nacl/nacl_interface_query.c [SHARED] (nacl_interface_query_ifunc): Likewise. * sysdeps/powerpc/ifunc-sel.h (ifunc_sel): Likewise. (ifunc_one): Likewise. * sysdeps/unix/make-syscalls.sh: Likewise. * sysdeps/unix/sysv/linux/powerpc/gettimeofday.c (gettimeofday_ifunc): Likewise. * sysdeps/unix/sysv/linux/powerpc/time.c (time_ifunc): Likewise. * sysdeps/unix/sysv/linux/x86/gettimeofday.c (gettimeofday_ifunc): Likewise. * sysdeps/unix/sysv/linux/x86/time.c (time_ifunc): Likewise. * sysdeps/unix/sysv/linux/x86_64/x32/getcpu.c (getcpu_ifunc): Likewise. --- config.h.in | 4 ++++ 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 | 18 ++++++++++++++++-- nptl/pt-fork.c | 1 + nptl/pt-longjmp.c | 1 + nptl/pt-system.c | 1 + nptl/pt-vfork.c | 1 + rt/clock-compat.c | 4 +++- 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/powerpc/gettimeofday.c | 1 + sysdeps/unix/sysv/linux/powerpc/time.c | 1 + sysdeps/unix/sysv/linux/x86/gettimeofday.c | 1 + sysdeps/unix/sysv/linux/x86/time.c | 1 + sysdeps/unix/sysv/linux/x86_64/x32/getcpu.c | 1 + sysdeps/x86_64/ifuncmod8.c | 1 + 23 files changed, 51 insertions(+), 3 deletions(-) diff --git a/config.h.in b/config.h.in index 990d5e1..612e18e 100644 --- a/config.h.in +++ b/config.h.in @@ -43,6 +43,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. */ #undef STACK_PROTECTOR_LEVEL diff --git a/configure.ac b/configure.ac index f690abf..6ad87f5 100644 --- a/configure.ac +++ b/configure.ac @@ -636,6 +636,7 @@ stack_protector= no_stack_protector= if test "$libc_cv_ssp" = yes; then no_stack_protector=-fno-stack-protector + 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 6e66d31..d87d61d 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 8478d4c..04faeb8 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 617a596..1e8f7ea 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 0b61380..f0bf5fb 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 0e65a63..5a95780 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 4548e09..531092c 100644 --- a/include/libc-symbols.h +++ b/include/libc-symbols.h @@ -314,6 +314,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, @@ -716,7 +726,9 @@ for linking") /* Marker used for indirection function symbols. */ #define libc_ifunc(name, expr) \ extern void *name##_ifunc (void) __asm__ (#name); \ - void *name##_ifunc (void) \ + void * \ + inhibit_stack_protector \ + name##_ifunc (void) \ { \ INIT_ARCH (); \ __typeof (name) *res = expr; \ @@ -728,7 +740,9 @@ for linking") which will, if necessary, initialize the data first. */ #define libm_ifunc(name, expr) \ extern void *name##_ifunc (void) __asm__ (#name); \ - void *name##_ifunc (void) \ + void * \ + inhibit_stack_protector \ + name##_ifunc (void) \ { \ __typeof (name) *res = expr; \ return res; \ diff --git a/nptl/pt-fork.c b/nptl/pt-fork.c index b65d6b4..4178af8 100644 --- a/nptl/pt-fork.c +++ b/nptl/pt-fork.c @@ -34,6 +34,7 @@ static __typeof (fork) * __attribute__ ((used)) +inhibit_stack_protector fork_resolve (void) { return &__libc_fork; diff --git a/nptl/pt-longjmp.c b/nptl/pt-longjmp.c index a1cc286..8a33cb4 100644 --- a/nptl/pt-longjmp.c +++ b/nptl/pt-longjmp.c @@ -34,6 +34,7 @@ static __typeof (longjmp) * __attribute__ ((used)) +inhibit_stack_protector longjmp_resolve (void) { return &__libc_longjmp; diff --git a/nptl/pt-system.c b/nptl/pt-system.c index 56f2a89..a481ab3 100644 --- a/nptl/pt-system.c +++ b/nptl/pt-system.c @@ -34,6 +34,7 @@ static __typeof (system) * __attribute__ ((used)) +inhibit_stack_protector system_resolve (void) { return &__libc_system; diff --git a/nptl/pt-vfork.c b/nptl/pt-vfork.c index 8f4be0c..8f3c2c0 100644 --- a/nptl/pt-vfork.c +++ b/nptl/pt-vfork.c @@ -48,6 +48,7 @@ extern __typeof (vfork) __libc_vfork; /* Defined in libc. */ static __typeof (vfork) * __attribute__ ((used)) +inhibit_stack_protector vfork_resolve (void) { return &__libc_vfork; diff --git a/rt/clock-compat.c b/rt/clock-compat.c index dc69e4a..b0fdd8b 100644 --- a/rt/clock-compat.c +++ b/rt/clock-compat.c @@ -30,7 +30,9 @@ #if HAVE_IFUNC # define COMPAT_REDIRECT(name, proto, arglist) \ __typeof (name) *name##_ifunc (void) asm (#name); \ - __typeof (name) *name##_ifunc (void) \ + __typeof (name) * \ + inhibit_stack_protector \ + name##_ifunc (void) \ { \ return &__##name; \ } \ diff --git a/sysdeps/generic/ifunc-sel.h b/sysdeps/generic/ifunc-sel.h index 6a27b69..1fff405 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 adf1dd4..dbaa88b 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 526d8ed..598b125 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"); @@ -30,6 +31,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 58d165e..123553c 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/powerpc/gettimeofday.c b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c index 25a4e7c..a8b6cfa 100644 --- a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c +++ b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c @@ -33,6 +33,7 @@ __gettimeofday_syscall (struct timeval *tv, struct timezone *tz) } void * +inhibit_stack_protector gettimeofday_ifunc (void) { PREPARE_VERSION (linux2615, "LINUX_2.6.15", 123718565); diff --git a/sysdeps/unix/sysv/linux/powerpc/time.c b/sysdeps/unix/sysv/linux/powerpc/time.c index 7973419..4b89b38 100644 --- a/sysdeps/unix/sysv/linux/powerpc/time.c +++ b/sysdeps/unix/sysv/linux/powerpc/time.c @@ -43,6 +43,7 @@ time_syscall (time_t *t) } void * +inhibit_stack_protector time_ifunc (void) { PREPARE_VERSION (linux2615, "LINUX_2.6.15", 123718565); diff --git a/sysdeps/unix/sysv/linux/x86/gettimeofday.c b/sysdeps/unix/sysv/linux/x86/gettimeofday.c index 36f7c26..e05ad53 100644 --- a/sysdeps/unix/sysv/linux/x86/gettimeofday.c +++ b/sysdeps/unix/sysv/linux/x86/gettimeofday.c @@ -32,6 +32,7 @@ __gettimeofday_syscall (struct timeval *tv, struct timezone *tz) void *gettimeofday_ifunc (void) __asm__ ("__gettimeofday"); void * +inhibit_stack_protector gettimeofday_ifunc (void) { PREPARE_VERSION_KNOWN (linux26, LINUX_2_6); diff --git a/sysdeps/unix/sysv/linux/x86/time.c b/sysdeps/unix/sysv/linux/x86/time.c index f5f7f91..c5bd8dc 100644 --- a/sysdeps/unix/sysv/linux/x86/time.c +++ b/sysdeps/unix/sysv/linux/x86/time.c @@ -33,6 +33,7 @@ __time_syscall (time_t *t) void *time_ifunc (void) __asm__ ("time"); void * +inhibit_stack_protector time_ifunc (void) { PREPARE_VERSION_KNOWN (linux26, LINUX_2_6); diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/getcpu.c b/sysdeps/unix/sysv/linux/x86_64/x32/getcpu.c index cbac4b3..8436f9d 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 c004367..7c06562 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);