(root)/
glibc-2.38/
sysdeps/
unix/
sysv/
linux/
dl-execstack.c
       1  /* Stack executability handling for GNU dynamic linker.  Linux version.
       2     Copyright (C) 2003-2023 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)