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.)
This commit is contained in:
Nick Alcock 2016-12-26 10:08:41 +01:00 committed by Florian Weimer
parent 003a27e819
commit de6591238b
16 changed files with 62 additions and 1 deletions

View File

@ -1,3 +1,28 @@
2016-12-26 Nick Alcock <nick.alcock@oracle.com>
[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 <nick.alcock@oracle.com> 2016-12-26 Nick Alcock <nick.alcock@oracle.com>
Florian Weimer <fweimer@redhat.com> Florian Weimer <fweimer@redhat.com>

View File

@ -48,6 +48,10 @@
/* Define if compiler accepts -ftree-loop-distribute-patterns. */ /* Define if compiler accepts -ftree-loop-distribute-patterns. */
#undef HAVE_CC_INHIBIT_LOOP_TO_LIBCALL #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. /* The level of stack protection in use for glibc as a whole.
May be overridden on a file-by-file basis. */ May be overridden on a file-by-file basis. */
#ifndef STACK_PROTECTOR_LEVEL #ifndef STACK_PROTECTOR_LEVEL

2
configure vendored
View File

@ -3994,6 +3994,8 @@ stack_protector=
no_stack_protector= no_stack_protector=
if test "$libc_cv_ssp" = yes; then if test "$libc_cv_ssp" = yes; then
no_stack_protector="-fno-stack-protector -DSTACK_PROTECTOR_LEVEL=0" no_stack_protector="-fno-stack-protector -DSTACK_PROTECTOR_LEVEL=0"
$as_echo "#define HAVE_CC_NO_STACK_PROTECTOR 1" >>confdefs.h
fi fi
if test "$enable_stack_protector" = yes && test "$libc_cv_ssp" = yes; then if test "$enable_stack_protector" = yes && test "$libc_cv_ssp" = yes; then

View File

@ -653,6 +653,7 @@ stack_protector=
no_stack_protector= no_stack_protector=
if test "$libc_cv_ssp" = yes; then if test "$libc_cv_ssp" = yes; then
no_stack_protector="-fno-stack-protector -DSTACK_PROTECTOR_LEVEL=0" no_stack_protector="-fno-stack-protector -DSTACK_PROTECTOR_LEVEL=0"
AC_DEFINE(HAVE_CC_NO_STACK_PROTECTOR)
fi fi
if test "$enable_stack_protector" = yes && test "$libc_cv_ssp" = yes; then if test "$enable_stack_protector" = yes && test "$libc_cv_ssp" = yes; then

View File

@ -32,6 +32,7 @@ void * foo1_ifunc (void) __asm__ ("foo1");
__asm__(".type foo1, %gnu_indirect_function"); __asm__(".type foo1, %gnu_indirect_function");
void * void *
inhibit_stack_protector
foo1_ifunc (void) foo1_ifunc (void)
{ {
return ifunc_sel (one, minus_one, zero); return ifunc_sel (one, minus_one, zero);
@ -41,6 +42,7 @@ void * foo2_ifunc (void) __asm__ ("foo2");
__asm__(".type foo2, %gnu_indirect_function"); __asm__(".type foo2, %gnu_indirect_function");
void * void *
inhibit_stack_protector
foo2_ifunc (void) foo2_ifunc (void)
{ {
return ifunc_sel (minus_one, one, zero); return ifunc_sel (minus_one, one, zero);
@ -50,6 +52,7 @@ void * foo3_ifunc (void) __asm__ ("foo3");
__asm__(".type foo3, %gnu_indirect_function"); __asm__(".type foo3, %gnu_indirect_function");
void * void *
inhibit_stack_protector
foo3_ifunc (void) foo3_ifunc (void)
{ {
return ifunc_sel (one, zero, minus_one); return ifunc_sel (one, zero, minus_one);

View File

@ -21,6 +21,7 @@ void * foo_ifunc (void) __asm__ ("foo");
__asm__(".type foo, %gnu_indirect_function"); __asm__(".type foo, %gnu_indirect_function");
void * void *
inhibit_stack_protector
foo_ifunc (void) foo_ifunc (void)
{ {
return ifunc_one (one); return ifunc_one (one);

View File

@ -20,6 +20,7 @@ __asm__(".type foo, %gnu_indirect_function");
static void * static void *
__attribute__ ((used)) __attribute__ ((used))
inhibit_stack_protector
foo_ifunc (void) foo_ifunc (void)
{ {
return ifunc_one (one); return ifunc_one (one);

View File

@ -36,6 +36,7 @@ void * foo_ifunc (void) __asm__ ("foo");
__asm__(".type foo, %gnu_indirect_function"); __asm__(".type foo, %gnu_indirect_function");
void * void *
inhibit_stack_protector
foo_ifunc (void) foo_ifunc (void)
{ {
return ifunc_sel (one, minus_one, zero); 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"); __asm__(".type foo_hidden, %gnu_indirect_function");
void * void *
inhibit_stack_protector
foo_hidden_ifunc (void) foo_hidden_ifunc (void)
{ {
return ifunc_sel (minus_one, one, zero); 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"); __asm__(".type foo_protected, %gnu_indirect_function");
void * void *
inhibit_stack_protector
foo_protected_ifunc (void) foo_protected_ifunc (void)
{ {
return ifunc_sel (one, zero, minus_one); return ifunc_sel (one, zero, minus_one);

View File

@ -31,6 +31,7 @@ void * foo_ifunc (void) __asm__ ("foo");
__asm__(".type foo, %gnu_indirect_function"); __asm__(".type foo, %gnu_indirect_function");
void * void *
inhibit_stack_protector
foo_ifunc (void) foo_ifunc (void)
{ {
return ifunc_sel (one, minus_one, zero); 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"); __asm__(".type foo_hidden, %gnu_indirect_function");
void * void *
inhibit_stack_protector
foo_hidden_ifunc (void) foo_hidden_ifunc (void)
{ {
return ifunc_sel (minus_one, one, zero); 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"); __asm__(".type foo_protected, %gnu_indirect_function");
void * void *
inhibit_stack_protector
foo_protected_ifunc (void) foo_protected_ifunc (void)
{ {
return ifunc_sel (one, zero, minus_one); return ifunc_sel (one, zero, minus_one);

View File

@ -336,6 +336,16 @@ for linking")
#define attribute_relro __attribute__ ((section (".data.rel.ro"))) #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 /* The following macros are used for PLT bypassing within libc.so
(and if needed other libraries similarly). (and if needed other libraries similarly).
First of all, you need to have the function prototyped somewhere, First of all, you need to have the function prototyped somewhere,
@ -737,7 +747,7 @@ for linking")
/* Helper / base macros for indirect function symbols. */ /* Helper / base macros for indirect function symbols. */
#define __ifunc_resolver(type_name, name, expr, arg, init, classifier) \ #define __ifunc_resolver(type_name, name, expr, arg, init, classifier) \
classifier void *name##_ifunc (arg) \ classifier inhibit_stack_protector void *name##_ifunc (arg) \
{ \ { \
init (); \ init (); \
__typeof (type_name) *res = expr; \ __typeof (type_name) *res = expr; \

View File

@ -5,6 +5,7 @@
extern int global; extern int global;
static inline void * static inline void *
inhibit_stack_protector
ifunc_sel (int (*f1) (void), int (*f2) (void), int (*f3) (void)) ifunc_sel (int (*f1) (void), int (*f2) (void), int (*f3) (void))
{ {
switch (global) switch (global)
@ -19,6 +20,7 @@ ifunc_sel (int (*f1) (void), int (*f2) (void), int (*f3) (void))
} }
static inline void * static inline void *
inhibit_stack_protector
ifunc_one (int (*f1) (void)) ifunc_one (int (*f1) (void))
{ {
return f1; return f1;

View File

@ -29,6 +29,7 @@ extern TYPE_nacl_irt_query nacl_interface_query_ifunc (void)
asm ("nacl_interface_query"); asm ("nacl_interface_query");
TYPE_nacl_irt_query TYPE_nacl_irt_query
inhibit_stack_protector
nacl_interface_query_ifunc (void) nacl_interface_query_ifunc (void)
{ {
return &__nacl_irt_query; return &__nacl_irt_query;

View File

@ -5,6 +5,7 @@
extern int global; extern int global;
static inline void * static inline void *
inhibit_stack_protector
ifunc_sel (int (*f1) (void), int (*f2) (void), int (*f3) (void)) ifunc_sel (int (*f1) (void), int (*f2) (void), int (*f3) (void))
{ {
register void *ret __asm__ ("r3"); register void *ret __asm__ ("r3");
@ -32,6 +33,7 @@ ifunc_sel (int (*f1) (void), int (*f2) (void), int (*f3) (void))
} }
static inline void * static inline void *
inhibit_stack_protector
ifunc_one (int (*f1) (void)) ifunc_one (int (*f1) (void))
{ {
register void *ret __asm__ ("r3"); register void *ret __asm__ ("r3");

View File

@ -287,6 +287,7 @@ while read file srcfile caller syscall args strong weak; do
(echo '#include <dl-vdso.h>'; \\ (echo '#include <dl-vdso.h>'; \\
echo 'extern void *${strong}_ifunc (void) __asm ("${strong}");'; \\ echo 'extern void *${strong}_ifunc (void) __asm ("${strong}");'; \\
echo 'void *'; \\ echo 'void *'; \\
echo 'inhibit_stack_protector'; \\
echo '${strong}_ifunc (void)'; \\ echo '${strong}_ifunc (void)'; \\
echo '{'; \\ echo '{'; \\
echo ' PREPARE_VERSION_KNOWN (symver, ${vdso_symver});'; \\ echo ' PREPARE_VERSION_KNOWN (symver, ${vdso_symver});'; \\

View File

@ -21,6 +21,7 @@
void *getcpu_ifunc (void) __asm__ ("__getcpu"); void *getcpu_ifunc (void) __asm__ ("__getcpu");
void * void *
inhibit_stack_protector
getcpu_ifunc (void) getcpu_ifunc (void)
{ {
PREPARE_VERSION (linux26, "LINUX_2.6", 61765110); PREPARE_VERSION (linux26, "LINUX_2.6", 61765110);

View File

@ -28,6 +28,7 @@ foo_impl (float x)
} }
void * void *
inhibit_stack_protector
foo_ifunc (void) foo_ifunc (void)
{ {
__m128i xmm = _mm_set1_epi32 (-1); __m128i xmm = _mm_set1_epi32 (-1);