* 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.
This commit is contained in:
Ulrich Drepper 2003-09-25 03:16:53 +00:00
parent 9771695416
commit 279f1143af
2 changed files with 58 additions and 14 deletions

View File

@ -1,5 +1,11 @@
2003-09-24 Ulrich Drepper <drepper@redhat.com> 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. * Makefile: Build tst-execstack-mod locally.
* tst-execstack-mod.c: New file. * tst-execstack-mod.c: New file.

View File

@ -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 static int
allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, 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); 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 /* Note that all of the stack and the thread descriptor is
zeroed. This means we do not have to initialize fields zeroed. This means we do not have to initialize fields
with initial value zero. This is specifically true for with initial value zero. This is specifically true for
@ -630,25 +675,18 @@ __make_stacks_executable (void)
list_t *runp; list_t *runp;
list_for_each (runp, &stack_used) 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 #ifdef NEED_SEPARATE_REGISTER_STACK
void *stack = (pd->stackblock , pagemask
+ (((((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 #endif
if (mprotect (stack, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) );
{ if (err != 0)
err = errno;
break; break;
} }
}
lll_unlock (stack_cache_lock); lll_unlock (stack_cache_lock);
if (err == 0)
_dl_make_stack_executable (); _dl_make_stack_executable ();
return err; return err;