(root)/
glibc-2.38/
sysdeps/
aarch64/
dl-bti.c
       1  /* AArch64 BTI functions.
       2     Copyright (C) 2020-2023 Free Software Foundation, Inc.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <unistd.h>
      19  #include <errno.h>
      20  #include <libintl.h>
      21  #include <ldsodefs.h>
      22  #include <sys/mman.h>
      23  
      24  /* See elf/dl-load.h.  */
      25  #ifndef MAP_COPY
      26  # define MAP_COPY (MAP_PRIVATE | MAP_DENYWRITE)
      27  #endif
      28  
      29  /* Enable BTI protection for MAP.  */
      30  
      31  void
      32  _dl_bti_protect (struct link_map *map, int fd)
      33  {
      34    const size_t pagesz = GLRO(dl_pagesize);
      35    const ElfW(Phdr) *phdr;
      36  
      37    for (phdr = map->l_phdr; phdr < &map->l_phdr[map->l_phnum]; ++phdr)
      38      if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X))
      39        {
      40  	size_t vstart = ALIGN_DOWN (phdr->p_vaddr, pagesz);
      41  	size_t vend = ALIGN_UP (phdr->p_vaddr + phdr->p_filesz, pagesz);
      42  	off_t off = ALIGN_DOWN (phdr->p_offset, pagesz);
      43  	void *start = (void *) (vstart + map->l_addr);
      44  	size_t len = vend - vstart;
      45  
      46  	unsigned prot = PROT_EXEC | PROT_BTI;
      47  	if (phdr->p_flags & PF_R)
      48  	  prot |= PROT_READ;
      49  	if (phdr->p_flags & PF_W)
      50  	  prot |= PROT_WRITE;
      51  
      52  	if (fd == -1)
      53  	  /* Ignore failures for kernel mapped binaries.  */
      54  	  __mprotect (start, len, prot);
      55  	else
      56  	  map->l_mach.bti_fail = __mmap (start, len, prot,
      57  					 MAP_FIXED|MAP_COPY|MAP_FILE,
      58  					 fd, off) == MAP_FAILED;
      59        }
      60  }
      61  
      62  
      63  static void
      64  bti_failed (struct link_map *l, const char *program)
      65  {
      66    if (program)
      67      _dl_fatal_printf ("%s: %s: failed to turn on BTI protection\n",
      68  		      program, l->l_name);
      69    else
      70      /* Note: the errno value is not available any more.  */
      71      _dl_signal_error (0, l->l_name, "dlopen",
      72  		      N_("failed to turn on BTI protection"));
      73  }
      74  
      75  
      76  /* Enable BTI for L and its dependencies.  */
      77  
      78  void
      79  _dl_bti_check (struct link_map *l, const char *program)
      80  {
      81    if (!GLRO(dl_aarch64_cpu_features).bti)
      82      return;
      83  
      84    if (l->l_mach.bti_fail)
      85      bti_failed (l, program);
      86  
      87    unsigned int i = l->l_searchlist.r_nlist;
      88    while (i-- > 0)
      89      {
      90        struct link_map *dep = l->l_initfini[i];
      91        if (dep->l_mach.bti_fail)
      92  	bti_failed (dep, program);
      93      }
      94  }