| 1 | /* Stack executability handling for GNU dynamic linker. Linux version. |
| 2 | Copyright (C) 2003-2021 Free Software Foundation, Inc. |
| 3 | This file is part of the GNU C Library. |
| 4 | |
| 5 | The GNU C Library is free software; you can redistribute it and/or |
| 6 | modify it under the terms of the GNU Lesser General Public |
| 7 | License as published by the Free Software Foundation; either |
| 8 | version 2.1 of the License, or (at your option) any later version. |
| 9 | |
| 10 | The GNU C Library is distributed in the hope that it will be useful, |
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | Lesser General Public License for more details. |
| 14 | |
| 15 | You should have received a copy of the GNU Lesser General Public |
| 16 | License along with the GNU C Library; if not, see |
| 17 | <https://www.gnu.org/licenses/>. */ |
| 18 | |
| 19 | #include <errno.h> |
| 20 | #include <ldsodefs.h> |
| 21 | #include <libintl.h> |
| 22 | #include <list.h> |
| 23 | #include <pthreadP.h> |
| 24 | #include <stackinfo.h> |
| 25 | #include <stdbool.h> |
| 26 | #include <sys/mman.h> |
| 27 | #include <sysdep.h> |
| 28 | #include <unistd.h> |
| 29 | |
| 30 | extern int __stack_prot attribute_relro attribute_hidden; |
| 31 | |
| 32 | static int |
| 33 | make_main_stack_executable (void **stack_endp) |
| 34 | { |
| 35 | /* This gives us the highest/lowest page that needs to be changed. */ |
| 36 | uintptr_t page = ((uintptr_t) *stack_endp |
| 37 | & -(intptr_t) GLRO(dl_pagesize)); |
| 38 | int result = 0; |
| 39 | |
| 40 | if (__builtin_expect (__mprotect ((void *) page, GLRO(dl_pagesize), |
| 41 | __stack_prot) == 0, 1)) |
| 42 | goto return_success; |
| 43 | result = errno; |
| 44 | goto out; |
| 45 | |
| 46 | return_success: |
| 47 | /* Clear the address. */ |
| 48 | *stack_endp = NULL; |
| 49 | |
| 50 | /* Remember that we changed the permission. */ |
| 51 | GL(dl_stack_flags) |= PF_X; |
| 52 | |
| 53 | out: |
| 54 | #ifdef check_consistency |
| 55 | check_consistency (); |
| 56 | #endif |
| 57 | |
| 58 | return result; |
| 59 | } |
| 60 | |
| 61 | int |
| 62 | _dl_make_stacks_executable (void **stack_endp) |
| 63 | { |
| 64 | /* First the main thread's stack. */ |
| 65 | int err = make_main_stack_executable (stack_endp); |
| 66 | if (err != 0) |
| 67 | return err; |
| 68 | |
| 69 | lll_lock (GL (dl_stack_cache_lock), LLL_PRIVATE); |
| 70 | |
| 71 | list_t *runp; |
| 72 | list_for_each (runp, &GL (dl_stack_used)) |
| 73 | { |
| 74 | err = __nptl_change_stack_perm (list_entry (runp, struct pthread, list)); |
| 75 | if (err != 0) |
| 76 | break; |
| 77 | } |
| 78 | |
| 79 | /* Also change the permission for the currently unused stacks. This |
| 80 | might be wasted time but better spend it here than adding a check |
| 81 | in the fast path. */ |
| 82 | if (err == 0) |
| 83 | list_for_each (runp, &GL (dl_stack_cache)) |
| 84 | { |
| 85 | err = __nptl_change_stack_perm (list_entry (runp, struct pthread, |
| 86 | list)); |
| 87 | if (err != 0) |
| 88 | break; |
| 89 | } |
| 90 | |
| 91 | lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE); |
| 92 | |
| 93 | return err; |
| 94 | } |
| 95 | |
| 96 | int |
| 97 | __nptl_change_stack_perm (struct pthread *pd) |
| 98 | { |
| 99 | #ifdef NEED_SEPARATE_REGISTER_STACK |
| 100 | size_t pagemask = __getpagesize () - 1; |
| 101 | void *stack = (pd->stackblock |
| 102 | + (((((pd->stackblock_size - pd->guardsize) / 2) |
| 103 | & pagemask) + pd->guardsize) & pagemask)); |
| 104 | size_t len = pd->stackblock + pd->stackblock_size - stack; |
| 105 | #elif _STACK_GROWS_DOWN |
| 106 | void *stack = pd->stackblock + pd->guardsize; |
| 107 | size_t len = pd->stackblock_size - pd->guardsize; |
| 108 | #elif _STACK_GROWS_UP |
| 109 | void *stack = pd->stackblock; |
| 110 | size_t len = (uintptr_t) pd - pd->guardsize - (uintptr_t) pd->stackblock; |
| 111 | #else |
| 112 | # error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" |
| 113 | #endif |
| 114 | if (__mprotect (stack, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) |
| 115 | return errno; |
| 116 | |
| 117 | return 0; |
| 118 | } |
| 119 | rtld_hidden_def (__nptl_change_stack_perm) |
| 120 | |