fix stack protector crashes on x32 & powerpc due to misplaced TLS canary
authorRich Felker <dalias@aerifal.cx>
Wed, 6 May 2015 22:37:19 +0000 (18:37 -0400)
committerRich Felker <dalias@aerifal.cx>
Wed, 6 May 2015 22:37:19 +0000 (18:37 -0400)
i386, x86_64, x32, and powerpc all use TLS for stack protector canary
values in the default stack protector ABI, but the location only
matched the ABI on i386 and x86_64. on x32, the expected location for
the canary contained the tid, thus producing spurious mismatches
(resulting in process termination) upon fork. on powerpc, the expected
location contained the stdio_locks list head, so returning from a
function after calling flockfile produced spurious mismatches. in both
cases, the random canary was not present, and a predictable value was
used instead, making the stack protector hardening much less effective
than it should be.

in the current fix, the thread structure has been expanded to have
canary fields at all three possible locations, and archs that use a
non-default location must define a macro in pthread_arch.h to choose
which location is used. for most archs (which lack TLS canary ABI) the
choice does not matter.

arch/powerpc/pthread_arch.h
arch/x32/pthread_arch.h
src/env/__stack_chk_fail.c
src/internal/pthread_impl.h
src/thread/pthread_create.c

index 2d1ee43cc76af9ea90abc6c6b62915f2d2987a7b..4115ec8c2357840af373a7aa1098a7e1fac1e61a 100644 (file)
@@ -17,3 +17,4 @@ static inline struct pthread *__pthread_self()
 // GPRs.
 #define CANCEL_REG_IP 32
 
+#define CANARY canary_at_end
index 23e10516000f861411006c22098c867dca5558f3..033bfd69a34b5ce446f6c4506ce549d41e8e3121 100644 (file)
@@ -8,3 +8,5 @@ static inline struct pthread *__pthread_self()
 #define TP_ADJ(p) (p)
 
 #define CANCEL_REG_IP 32
+
+#define CANARY canary2
index 1b6a9f820bf3c7babbefedc2acec1119e304d563..47784c62383d66df4ca9a3f337b4b953c6193c3f 100644 (file)
@@ -9,7 +9,7 @@ void __init_ssp(void *entropy)
        if (entropy) memcpy(&__stack_chk_guard, entropy, sizeof(uintptr_t));
        else __stack_chk_guard = (uintptr_t)&__stack_chk_guard * 1103515245;
 
-       __pthread_self()->canary = __stack_chk_guard;
+       __pthread_self()->CANARY = __stack_chk_guard;
 }
 
 void __stack_chk_fail(void)
index 56877b3a5e92609af29b1ce9088e7af0ced450b6..e29f9c82e421066db958d21aa0adb7ce2abc5b83 100644 (file)
@@ -16,7 +16,7 @@ struct pthread {
        struct pthread *self;
        void **dtv, *unused1, *unused2;
        uintptr_t sysinfo;
-       uintptr_t canary;
+       uintptr_t canary, canary2;
        pid_t tid, pid;
        int tsd_used, errno_val;
        volatile int cancel, canceldisable, cancelasync;
@@ -47,6 +47,7 @@ struct pthread {
        char *dlerror_buf;
        int dlerror_flag;
        void *stdio_locks;
+       uintptr_t canary_at_end;
        void **dtv_copy;
 };
 
@@ -89,6 +90,10 @@ struct __timer {
 
 #include "pthread_arch.h"
 
+#ifndef CANARY
+#define CANARY canary
+#endif
+
 #define SIGTIMER 32
 #define SIGCANCEL 33
 #define SIGSYNCCALL 34
index d7c0323a2ece9da3a0180e31fd7175581d6fab77..4eb8b8881d2871ed27153a506594924a9a8f90bb 100644 (file)
@@ -272,7 +272,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
        }
        new->robust_list.head = &new->robust_list.head;
        new->unblock_cancel = self->cancel;
-       new->canary = self->canary;
+       new->CANARY = self->CANARY;
 
        a_inc(&libc.threads_minus_1);
        ret = __clone((c11 ? start_c11 : start), stack, flags, new, &new->tid, TP_ADJ(new), &new->tid);