From 2dd87703d4386f2776c5b5f375a494c91d7f9fe4 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Mon, 10 May 2021 10:31:41 +0200 Subject: nptl: Move changing of stack permissions into ld.so All the stack lists are now in _rtld_global, so it is possible to change stack permissions directly from there, instead of calling into libpthread to do the change. Tested-by: Carlos O'Donell Reviewed-by: Carlos O'Donell --- sysdeps/unix/sysv/linux/dl-execstack.c | 76 ++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 8 deletions(-) (limited to 'sysdeps/unix/sysv/linux/dl-execstack.c') diff --git a/sysdeps/unix/sysv/linux/dl-execstack.c b/sysdeps/unix/sysv/linux/dl-execstack.c index 3339138..e2449d1 100644 --- a/sysdeps/unix/sysv/linux/dl-execstack.c +++ b/sysdeps/unix/sysv/linux/dl-execstack.c @@ -16,20 +16,21 @@ License along with the GNU C Library; if not, see . */ -#include -#include #include +#include #include -#include +#include +#include #include +#include +#include #include - +#include extern int __stack_prot attribute_relro attribute_hidden; - -int -_dl_make_stack_executable (void **stack_endp) +static int +make_main_stack_executable (void **stack_endp) { /* This gives us the highest/lowest page that needs to be changed. */ uintptr_t page = ((uintptr_t) *stack_endp @@ -56,4 +57,63 @@ _dl_make_stack_executable (void **stack_endp) return result; } -rtld_hidden_def (_dl_make_stack_executable) + +int +_dl_make_stacks_executable (void **stack_endp) +{ + /* First the main thread's stack. */ + int err = make_main_stack_executable (stack_endp); + if (err != 0) + return err; + + lll_lock (GL (dl_stack_cache_lock), LLL_PRIVATE); + + list_t *runp; + list_for_each (runp, &GL (dl_stack_used)) + { + err = __nptl_change_stack_perm (list_entry (runp, struct pthread, list)); + if (err != 0) + break; + } + + /* Also change the permission for the currently unused stacks. This + might be wasted time but better spend it here than adding a check + in the fast path. */ + if (err == 0) + list_for_each (runp, &GL (dl_stack_cache)) + { + err = __nptl_change_stack_perm (list_entry (runp, struct pthread, + list)); + if (err != 0) + break; + } + + lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE); + + return err; +} + +int +__nptl_change_stack_perm (struct pthread *pd) +{ +#ifdef NEED_SEPARATE_REGISTER_STACK + size_t pagemask = __getpagesize () - 1; + void *stack = (pd->stackblock + + (((((pd->stackblock_size - pd->guardsize) / 2) + & pagemask) + pd->guardsize) & pagemask)); + size_t len = pd->stackblock + pd->stackblock_size - stack; +#elif _STACK_GROWS_DOWN + void *stack = pd->stackblock + pd->guardsize; + size_t len = pd->stackblock_size - pd->guardsize; +#elif _STACK_GROWS_UP + void *stack = pd->stackblock; + size_t len = (uintptr_t) pd - pd->guardsize - (uintptr_t) pd->stackblock; +#else +# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" +#endif + if (__mprotect (stack, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + return errno; + + return 0; +} +rtld_hidden_def (__nptl_change_stack_perm) -- cgit v1.1