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:
Jack Ren 2011-09-21 12:44:11 +02:00 committed by Jean-Baptiste Queru
parent 31e72bc328
commit e480fc83b2
2 changed files with 6 additions and 1 deletions

View File

@ -22,6 +22,7 @@ __pthread_clone:
movl %eax, -8(%ecx)
movl %ecx, -4(%ecx)
subl $16, %ecx
movl $__NR_clone, %eax
int $0x80
test %eax, %eax
@ -39,7 +40,6 @@ __pthread_clone:
# we're in the child thread now, call __thread_entry
# with the appropriate arguments on the child stack
# we already placed most of them
subl $16, %esp
jmp __thread_entry
hlt

View File

@ -571,6 +571,7 @@ void pthread_exit(void * retval)
void* stack_base = thread->attr.stack_base;
int stack_size = thread->attr.stack_size;
int user_stack = (thread->attr.flags & PTHREAD_ATTR_FLAG_USER_STACK) != 0;
sigset_t mask;
// call the cleanup handlers first
while (thread->cleanup_stack) {
@ -613,6 +614,10 @@ void pthread_exit(void * retval)
pthread_mutex_unlock(&gThreadListLock);
}
sigfillset(&mask);
sigdelset(&mask, SIGSEGV);
(void)sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
// destroy the thread stack
if (user_stack)
_exit_thread((int)retval);