diff options
author | Rich Felker <dalias@aerifal.cx> | 2012-07-11 23:36:46 -0400 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2012-07-11 23:36:46 -0400 |
commit | 92f8396b0c8e4f146563b87f46137484cfb36e31 (patch) | |
tree | 62bd8daab801d7127114a33a83db28f591e01669 /src | |
parent | a03f69d4456d3ac5120cc07a22af8ecb631444bb (diff) | |
download | musl-92f8396b0c8e4f146563b87f46137484cfb36e31.tar.gz musl-92f8396b0c8e4f146563b87f46137484cfb36e31.tar.xz musl-92f8396b0c8e4f146563b87f46137484cfb36e31.zip |
fix potential race condition in detached threads
after the thread unmaps its own stack/thread structure, the kernel, performing child tid clear and futex wake, could clobber a new mapping made at the same location as the just-removed thread's tid field. disable kernel clearing of child tid to prevent this.
Diffstat (limited to 'src')
-rw-r--r-- | src/thread/pthread_create.c | 10 | ||||
-rw-r--r-- | src/thread/pthread_detach.c | 4 |
2 files changed, 10 insertions, 4 deletions
diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c index 48290d35..ae2f9e4e 100644 --- a/src/thread/pthread_create.c +++ b/src/thread/pthread_create.c @@ -36,6 +36,8 @@ void pthread_exit(void *result) if (!n) exit(0); if (self->detached && self->map_base) { + if (self->detached == 2) + __syscall(SYS_set_tid_address, 0); __syscall(SYS_rt_sigprocmask, SIG_BLOCK, (uint64_t[]){-1},0,8); __unmapself(self->map_base, self->map_size); } @@ -87,6 +89,7 @@ int pthread_create(pthread_t *res, const pthread_attr_t *attr, void *(*entry)(vo size_t guard = DEFAULT_GUARD_SIZE; struct pthread *self = pthread_self(), *new; unsigned char *map, *stack, *tsd; + unsigned flags = 0x7d8f00; if (!self) return ENOSYS; if (!libc.threaded) { @@ -121,7 +124,10 @@ int pthread_create(pthread_t *res, const pthread_attr_t *attr, void *(*entry)(vo new->start_arg = arg; new->self = new; new->tsd = (void *)tsd; - if (attr) new->detached = attr->_a_detach; + if (attr && attr->_a_detach) { + new->detached = 1; + flags -= 0x200000; + } new->unblock_cancel = self->cancel; new->canary = self->canary ^ (uintptr_t)&new; stack = (void *)new; @@ -129,7 +135,7 @@ int pthread_create(pthread_t *res, const pthread_attr_t *attr, void *(*entry)(vo __synccall_lock(); a_inc(&libc.threads_minus_1); - ret = __clone(start, stack, 0x7d8f00, new, &new->tid, new, &new->tid); + ret = __clone(start, stack, flags, new, &new->tid, new, &new->tid); __synccall_unlock(); diff --git a/src/thread/pthread_detach.c b/src/thread/pthread_detach.c index 8ef03d51..e8032398 100644 --- a/src/thread/pthread_detach.c +++ b/src/thread/pthread_detach.c @@ -5,7 +5,7 @@ int pthread_detach(pthread_t t) /* Cannot detach a thread that's already exiting */ if (a_swap(&t->exitlock, 1)) return pthread_join(t, 0); - t->detached = 1; - t->exitlock = 0; + t->detached = 2; + a_store(&t->exitlock, 0); return 0; } |