bionic: fix pthread_{create, exit}/signal race condition
(1) in pthread_create:
If the one signal is received before esp is subtracted by 16 and
__thread_entry( ) is called, the stack will be cleared by kernel
when it tries to contruct the signal stack frame. That will cause
that __thread_entry will get a wrong tls pointer from the stack
which leads to the segment fault when trying to access tls content.
(2) in pthread_exit
After pthread_exit called system call unmap(), its stack will be
freed. If one signal is received at that time, there is no stack
available for it.
Fixed by subtracting the child's esp by 16 before the clone system
call and by blocking signal handling before pthread_exit is started.
Author: Jack Ren <jack.ren@intel.com>
Signed-off-by: Bruce Beare <bruce.j.beare@intel.com>
This commit is contained in:
committed by
Jean-Baptiste Queru
parent
31e72bc328
commit
e480fc83b2
@@ -22,6 +22,7 @@ __pthread_clone:
|
|||||||
movl %eax, -8(%ecx)
|
movl %eax, -8(%ecx)
|
||||||
movl %ecx, -4(%ecx)
|
movl %ecx, -4(%ecx)
|
||||||
|
|
||||||
|
subl $16, %ecx
|
||||||
movl $__NR_clone, %eax
|
movl $__NR_clone, %eax
|
||||||
int $0x80
|
int $0x80
|
||||||
test %eax, %eax
|
test %eax, %eax
|
||||||
@@ -39,7 +40,6 @@ __pthread_clone:
|
|||||||
# we're in the child thread now, call __thread_entry
|
# we're in the child thread now, call __thread_entry
|
||||||
# with the appropriate arguments on the child stack
|
# with the appropriate arguments on the child stack
|
||||||
# we already placed most of them
|
# we already placed most of them
|
||||||
subl $16, %esp
|
|
||||||
jmp __thread_entry
|
jmp __thread_entry
|
||||||
hlt
|
hlt
|
||||||
|
|
||||||
|
|||||||
@@ -571,6 +571,7 @@ void pthread_exit(void * retval)
|
|||||||
void* stack_base = thread->attr.stack_base;
|
void* stack_base = thread->attr.stack_base;
|
||||||
int stack_size = thread->attr.stack_size;
|
int stack_size = thread->attr.stack_size;
|
||||||
int user_stack = (thread->attr.flags & PTHREAD_ATTR_FLAG_USER_STACK) != 0;
|
int user_stack = (thread->attr.flags & PTHREAD_ATTR_FLAG_USER_STACK) != 0;
|
||||||
|
sigset_t mask;
|
||||||
|
|
||||||
// call the cleanup handlers first
|
// call the cleanup handlers first
|
||||||
while (thread->cleanup_stack) {
|
while (thread->cleanup_stack) {
|
||||||
@@ -613,6 +614,10 @@ void pthread_exit(void * retval)
|
|||||||
pthread_mutex_unlock(&gThreadListLock);
|
pthread_mutex_unlock(&gThreadListLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sigfillset(&mask);
|
||||||
|
sigdelset(&mask, SIGSEGV);
|
||||||
|
(void)sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
|
||||||
|
|
||||||
// destroy the thread stack
|
// destroy the thread stack
|
||||||
if (user_stack)
|
if (user_stack)
|
||||||
_exit_thread((int)retval);
|
_exit_thread((int)retval);
|
||||||
|
|||||||
Reference in New Issue
Block a user