[03/18] Do not stack-protect ifunc resolvers.
Commit Message
From: Nick Alcock <nick.alcock@oracle.com>
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
depending on the availability of __attribute__ ((__optimize__
("-fno-stack-protector"))), and turning 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.
* config.h.in (HAVE_CC_NO_STACK_PROTECTOR): New macro.
* configure.ac (libc_cv_cc_no_stack_protector): Check if compiler
accepts __attribute__ ((__optimize__ ("-fno-stack-protector"))).
* 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 | 15 +++++++++++++++
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, 65 insertions(+), 3 deletions(-)
Comments
On 08 Mar 2016 13:50, Nix wrote:
> +AC_CACHE_CHECK(if $CC accepts -fno-stack-protector with \
> +__attribute__ ((__optimize__)),
m4 strings should be quoted. so this should be:
AC_CACHE_CHECK([if $CC ........], ...
-mike
On 08 Mar 2016 13:50, Nix wrote:
> +AC_CACHE_CHECK(if $CC accepts -fno-stack-protector with \
> +__attribute__ ((__optimize__)), libc_cv_cc_no_stack_protector, [dnl
> +cat > conftest.c <<EOF
> +void
> +__attribute__ ((__optimize__ ("-fno-stack-protector")))
> +foo (void) {}
> +EOF
actually, which versions of gcc *don't* support this ? if it's in gcc-4.7
and newer, then we don't need this test as we require that already.
-mike
On 9 Mar 2016, Mike Frysinger outgrape:
> On 08 Mar 2016 13:50, Nix wrote:
>> +AC_CACHE_CHECK(if $CC accepts -fno-stack-protector with \
>> +__attribute__ ((__optimize__)),
>
> m4 strings should be quoted. so this should be:
> AC_CACHE_CHECK([if $CC ........], ...
I copied it from the similarly unquoted
AC_CACHE_CHECK(if $CC accepts -fno-tree-loop-distribute-patterns with \
__attribute__ ((__optimize__)), libc_cv_cc_loop_to_function, [dnl
cat > conftest.c <<EOF
and didn't quote it out of unreasoning fear that \-escaping might get
broken if I did that. I didn't actually *test* it, or I'd have seen that
my fears were groundless. Fixed (at least, fixed my copy: I think the
other one is for another time).
On 9 Mar 2016, Mike Frysinger told this:
> On 08 Mar 2016 13:50, Nix wrote:
>> +AC_CACHE_CHECK(if $CC accepts -fno-stack-protector with \
>> +__attribute__ ((__optimize__)), libc_cv_cc_no_stack_protector, [dnl
>> +cat > conftest.c <<EOF
>> +void
>> +__attribute__ ((__optimize__ ("-fno-stack-protector")))
>> +foo (void) {}
>> +EOF
>
> actually, which versions of gcc *don't* support this ? if it's in gcc-4.7
> and newer, then we don't need this test as we require that already.
Good question. The worrying thing is that support for
__attribute__((__optimize__)) may not be enough: IIRC, that attribute
was not exactly perfectly functional in the first release or two after
it landed, IIRC.
Let's see...
... GCC 4.4?! OK, way older than I remembered. We can definitely drop
this: there have been fixes to fix things like target-specific options
with __attribute__((__optimize__)) right up until recently, but nothing
that would perturb -fno-stack-protector (and nothing at *all* between
4.6.x and 4.8.x, and I know 4.8.x works).
So I'll drop this bit.
(Technically this makes libc_cv_ssp useless too, because
-fstack-protector is *much* older than __attribute__((__optimize__)),
but it's consistent with the checks for -fstack-protector-strong and
-all to have it there, and those are much newer and still not
consistently supported on all targets. I can tear libc_cv_ssp and
have_ssp out as well if you think it worth doing.)
On Wed, 9 Mar 2016, Mike Frysinger wrote:
> On 08 Mar 2016 13:50, Nix wrote:
> > +AC_CACHE_CHECK(if $CC accepts -fno-stack-protector with \
> > +__attribute__ ((__optimize__)),
>
> m4 strings should be quoted. so this should be:
> AC_CACHE_CHECK([if $CC ........], ...
It would certainly be nice if someone cleaned up the existing *.ac scripts
and fragments to consistently follow this rule (for each autoconf macro,
there should generally be exactly one level of [] quoting around each of
its arguments, except in special cases such as where the Autoconf manual
explains that AC_LANG_SOURCE's argument should be double-quoted [[]]).
On 09 Mar 2016 23:48, Nix wrote:
> On 9 Mar 2016, Mike Frysinger told this:
> > On 08 Mar 2016 13:50, Nix wrote:
> >> +AC_CACHE_CHECK(if $CC accepts -fno-stack-protector with \
> >> +__attribute__ ((__optimize__)), libc_cv_cc_no_stack_protector, [dnl
> >> +cat > conftest.c <<EOF
> >> +void
> >> +__attribute__ ((__optimize__ ("-fno-stack-protector")))
> >> +foo (void) {}
> >> +EOF
> >
> > actually, which versions of gcc *don't* support this ? if it's in gcc-4.7
> > and newer, then we don't need this test as we require that already.
>
> Good question. The worrying thing is that support for
> __attribute__((__optimize__)) may not be enough: IIRC, that attribute
> was not exactly perfectly functional in the first release or two after
> it landed, IIRC.
>
> Let's see...
>
> ... GCC 4.4?! OK, way older than I remembered. We can definitely drop
> this: there have been fixes to fix things like target-specific options
> with __attribute__((__optimize__)) right up until recently, but nothing
> that would perturb -fno-stack-protector (and nothing at *all* between
> 4.6.x and 4.8.x, and I know 4.8.x works).
>
> So I'll drop this bit.
>
> (Technically this makes libc_cv_ssp useless too, because
> -fstack-protector is *much* older than __attribute__((__optimize__)),
> but it's consistent with the checks for -fstack-protector-strong and
> -all to have it there, and those are much newer and still not
> consistently supported on all targets. I can tear libc_cv_ssp and
> have_ssp out as well if you think it worth doing.)
checking for the flag itself we prob want to keep because not all targets
support SSP
-mike
@@ -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
+
/* Define if the regparm attribute shall be used for local functions
(gcc on ix86 only). */
#undef USE_REGPARMS
@@ -632,10 +632,25 @@ LIBC_TRY_CC_OPTION([$CFLAGS $CPPFLAGS -Werror -fstack-protector-all],
[libc_cv_ssp_all=no])
])
+AC_CACHE_CHECK(if $CC accepts -fno-stack-protector with \
+__attribute__ ((__optimize__)), libc_cv_cc_no_stack_protector, [dnl
+cat > conftest.c <<EOF
+void
+__attribute__ ((__optimize__ ("-fno-stack-protector")))
+foo (void) {}
+EOF
+libc_cv_cc_no_stack_protector=no
+if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -c conftest.c])
+then
+ libc_cv_cc_no_stack_protector=yes
+fi
+rm -f conftest*])
+
stack_protector=
no_stack_protector=
if test x$libc_cv_ssp = xyes; then
no_stack_protector=-fno-stack-protector
+ AC_DEFINE(HAVE_CC_NO_STACK_PROTECTOR)
fi
if test x$enable_stack_protector = xyes && test $libc_cv_ssp = yes; then
@@ -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);
@@ -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);
@@ -20,6 +20,7 @@ __asm__(".type foo, %gnu_indirect_function");
static void *
__attribute__ ((used))
+inhibit_stack_protector
foo_ifunc (void)
{
return ifunc_one (one);
@@ -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);
@@ -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);
@@ -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; \
@@ -34,6 +34,7 @@
static __typeof (fork) *
__attribute__ ((used))
+inhibit_stack_protector
fork_resolve (void)
{
return &__libc_fork;
@@ -34,6 +34,7 @@
static __typeof (longjmp) *
__attribute__ ((used))
+inhibit_stack_protector
longjmp_resolve (void)
{
return &__libc_longjmp;
@@ -34,6 +34,7 @@
static __typeof (system) *
__attribute__ ((used))
+inhibit_stack_protector
system_resolve (void)
{
return &__libc_system;
@@ -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;
@@ -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; \
} \
@@ -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;
@@ -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;
@@ -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");
@@ -287,6 +287,7 @@ while read file srcfile caller syscall args strong weak; do
(echo '#include <dl-vdso.h>'; \\
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});'; \\
@@ -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);
@@ -43,6 +43,7 @@ time_syscall (time_t *t)
}
void *
+inhibit_stack_protector
time_ifunc (void)
{
PREPARE_VERSION (linux2615, "LINUX_2.6.15", 123718565);
@@ -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);
@@ -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);
@@ -21,6 +21,7 @@
void *getcpu_ifunc (void) __asm__ ("__getcpu");
void *
+inhibit_stack_protector
getcpu_ifunc (void)
{
PREPARE_VERSION (linux26, "LINUX_2.6", 61765110);
@@ -28,6 +28,7 @@ foo_impl (float x)
}
void *
+inhibit_stack_protector
foo_ifunc (void)
{
__m128i xmm = _mm_set1_epi32 (-1);