diff options
authorRich Felker <>2015-05-06 18:37:19 -0400
committerRich Felker <>2015-05-06 18:37:19 -0400
commit484194dbf41758eec0ef62fef5fe9350c21b9241 (patch)
parentd0040e239e8d3048a7fb38f0bacaad4838fac605 (diff)
fix stack protector crashes on x32 & powerpc due to misplaced TLS canary
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.
5 files changed, 11 insertions, 3 deletions
diff --git a/arch/powerpc/pthread_arch.h b/arch/powerpc/pthread_arch.h
index 2d1ee43c..4115ec8c 100644
--- a/arch/powerpc/pthread_arch.h
+++ b/arch/powerpc/pthread_arch.h
@@ -17,3 +17,4 @@ static inline struct pthread *__pthread_self()
// GPRs.
#define CANCEL_REG_IP 32
+#define CANARY canary_at_end
diff --git a/arch/x32/pthread_arch.h b/arch/x32/pthread_arch.h
index 23e10516..033bfd69 100644
--- a/arch/x32/pthread_arch.h
+++ b/arch/x32/pthread_arch.h
@@ -8,3 +8,5 @@ static inline struct pthread *__pthread_self()
#define TP_ADJ(p) (p)
#define CANCEL_REG_IP 32
+#define CANARY canary2
diff --git a/src/env/__stack_chk_fail.c b/src/env/__stack_chk_fail.c
index 1b6a9f82..47784c62 100644
--- a/src/env/__stack_chk_fail.c
+++ b/src/env/__stack_chk_fail.c
@@ -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)
diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h
index 56877b3a..e29f9c82 100644
--- a/src/internal/pthread_impl.h
+++ b/src/internal/pthread_impl.h
@@ -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
#define SIGTIMER 32
#define SIGCANCEL 33
#define SIGSYNCCALL 34
diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c
index d7c0323a..4eb8b888 100644
--- a/src/thread/pthread_create.c
+++ b/src/thread/pthread_create.c
@@ -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;
ret = __clone((c11 ? start_c11 : start), stack, flags, new, &new->tid, TP_ADJ(new), &new->tid);