]>
Commit | Line | Data |
---|---|---|
1 | /* AArch64 BTI functions. | |
2 | Copyright (C) 2020-2021 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 | } |