diff options
author | Florian Weimer <fweimer@redhat.com> | 2021-05-10 10:31:41 +0200 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2021-05-10 10:31:41 +0200 |
commit | 2dd87703d4386f2776c5b5f375a494c91d7f9fe4 (patch) | |
tree | 94c59b0e923242d2ea1fe8992ea574d156fb7ded /sysdeps/unix/sysv/linux | |
parent | ee07b3a7222746fafc5d5cb2163c9609b81615ef (diff) | |
download | glibc-2dd87703d4386f2776c5b5f375a494c91d7f9fe4.tar.gz glibc-2dd87703d4386f2776c5b5f375a494c91d7f9fe4.tar.xz glibc-2dd87703d4386f2776c5b5f375a494c91d7f9fe4.zip |
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 <carlos@redhat.com> Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Diffstat (limited to 'sysdeps/unix/sysv/linux')
-rw-r--r-- | sysdeps/unix/sysv/linux/Versions | 6 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/dl-execstack.c | 76 |
2 files changed, 74 insertions, 8 deletions
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions index c35f783e2a..220bb2dffe 100644 --- a/sysdeps/unix/sysv/linux/Versions +++ b/sysdeps/unix/sysv/linux/Versions @@ -181,3 +181,9 @@ libc { __netlink_assert_response; } } + +ld { + GLIBC_PRIVATE { + __nptl_change_stack_perm; + } +} diff --git a/sysdeps/unix/sysv/linux/dl-execstack.c b/sysdeps/unix/sysv/linux/dl-execstack.c index 3339138c42..e2449d1890 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 <https://www.gnu.org/licenses/>. */ -#include <ldsodefs.h> -#include <sys/mman.h> #include <errno.h> +#include <ldsodefs.h> #include <libintl.h> -#include <stdbool.h> +#include <list.h> +#include <nptl/pthreadP.h> #include <stackinfo.h> +#include <stdbool.h> +#include <sys/mman.h> #include <sysdep.h> - +#include <unistd.h> 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) |