aboutsummaryrefslogtreecommitdiff
path: root/nptl/allocatestack.c
diff options
context:
space:
mode:
Diffstat (limited to 'nptl/allocatestack.c')
-rw-r--r--nptl/allocatestack.c66
1 files changed, 52 insertions, 14 deletions
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;
}