diff options
-rw-r--r-- | nptl/ChangeLog | 6 | ||||
-rw-r--r-- | nptl/allocatestack.c | 66 |
2 files changed, 58 insertions, 14 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 0ee343c3d1..e18c9cac21 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,5 +1,11 @@ 2003-09-24 Ulrich Drepper <drepper@redhat.com> + * allocatestack.c (change_stack_perm): Split out from + __make_stacks_executable. + (allocate_stack): If the required permission changed between the time + we started preparing the stack and queueing it, change the permission. + (__make_stacks_executable): Call change_stack_perm. + * Makefile: Build tst-execstack-mod locally. * tst-execstack-mod.c: New file. diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c index dc501650b8..24292e7295 100644 --- a/nptl/allocatestack.c +++ b/nptl/allocatestack.c @@ -249,6 +249,29 @@ queue_stack (struct pthread *stack) } +static int +internal_function +change_stack_perm (struct pthread *pd +#ifdef NEED_SEPARATE_REGISTER_STACK + , size_t pagemask +#endif + ) +{ +#ifdef NEED_SEPARATE_REGISTER_STACK + void *stack = (pd->stackblock + + (((((pd->stackblock_size - pd->guardsize) / 2) + & pagemask) + pd->guardsize) & pagemask)); + size_t len = pd->stackblock + pd->stackblock_size - stack; +#else + void *stack = pd->stackblock + pd->guardsize; + size_t len = pd->stackblock_size - pd->guardsize; +#endif + if (mprotect (stack, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + return errno; + + return 0; +} + static int allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, @@ -493,6 +516,28 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, lll_unlock (stack_cache_lock); + /* There might have been a race. Another thread might have + caused the stacks to get exec permission while this new + stack was prepared. Detect if this was possible and + change the permission if necessary. */ + if (__builtin_expect ((GL(dl_stack_flags) & PF_X) != 0 + && (prot & PROT_EXEC) == 0, 0)) + { + int err = change_stack_perm (pd +#ifdef NEED_SEPARATE_REGISTER_STACK + , ~pagesize_m1 +#endif + ); + if (err != 0) + { + /* Free the stack memory we just allocated. */ + (void) munmap (mem, size); + + return err; + } + } + + /* Note that all of the stack and the thread descriptor is zeroed. This means we do not have to initialize fields with initial value zero. This is specifically true for @@ -630,26 +675,19 @@ __make_stacks_executable (void) list_t *runp; list_for_each (runp, &stack_used) { - struct pthread *const pd = list_entry (runp, struct pthread, list); + err = change_stack_perm (list_entry (runp, struct pthread, list) #ifdef NEED_SEPARATE_REGISTER_STACK - void *stack = (pd->stackblock - + (((((pd->stackblock_size - pd->guardsize) / 2) - & pagemask) + pd->guardsize) & pagemask)); - size_t len = pd->stackblock + pd->stackblock_size - stack; -#else - void *stack = pd->stackblock + pd->guardsize; - size_t len = pd->stackblock_size - pd->guardsize; + , pagemask #endif - if (mprotect (stack, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) - { - err = errno; - break; - } + ); + if (err != 0) + break; } lll_unlock (stack_cache_lock); - _dl_make_stack_executable (); + if (err == 0) + _dl_make_stack_executable (); return err; } |