1 | /* AArch64 BTI functions. |
2 | Copyright (C) 2020-2024 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 (fmt: "%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 (errcode: 0, object: l->l_name, occasion: "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 (l: dep, program); |
93 | } |
94 | } |
95 | |