File: | projects/compiler-rt/lib/cfi/cfi.cc |
Warning: | line 225, column 35 Access to field 'st_name' results in a dereference of a null pointer (loaded from variable 'p') |
1 | //===-------- cfi.cc ------------------------------------------------------===// | |||
2 | // | |||
3 | // The LLVM Compiler Infrastructure | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | // | |||
10 | // This file implements the runtime support for the cross-DSO CFI. | |||
11 | // | |||
12 | //===----------------------------------------------------------------------===// | |||
13 | ||||
14 | #include <assert.h> | |||
15 | #include <elf.h> | |||
16 | #include <link.h> | |||
17 | #include <string.h> | |||
18 | #include <sys/mman.h> | |||
19 | ||||
20 | typedef ElfW(Phdr)Elf64_Phdr Elf_Phdr; | |||
21 | typedef ElfW(Ehdr)Elf64_Ehdr Elf_Ehdr; | |||
22 | ||||
23 | #include "interception/interception.h" | |||
24 | #include "sanitizer_common/sanitizer_common.h" | |||
25 | #include "sanitizer_common/sanitizer_flag_parser.h" | |||
26 | #include "ubsan/ubsan_init.h" | |||
27 | #include "ubsan/ubsan_flags.h" | |||
28 | ||||
29 | #ifdef CFI_ENABLE_DIAG | |||
30 | #include "ubsan/ubsan_handlers.h" | |||
31 | #endif | |||
32 | ||||
33 | using namespace __sanitizer; | |||
34 | ||||
35 | namespace __cfi { | |||
36 | ||||
37 | #define kCfiShadowLimitsStorageSize4096 4096 // 1 page | |||
38 | // Lets hope that the data segment is mapped with 4K pages. | |||
39 | // The pointer to the cfi shadow region is stored at the start of this page. | |||
40 | // The rest of the page is unused and re-mapped read-only. | |||
41 | static union { | |||
42 | char space[kCfiShadowLimitsStorageSize4096]; | |||
43 | struct { | |||
44 | uptr start; | |||
45 | uptr size; | |||
46 | } limits; | |||
47 | } cfi_shadow_limits_storage | |||
48 | __attribute__((aligned(kCfiShadowLimitsStorageSize4096))); | |||
49 | static constexpr uptr kShadowGranularity = 12; | |||
50 | static constexpr uptr kShadowAlign = 1UL << kShadowGranularity; // 4096 | |||
51 | ||||
52 | static constexpr uint16_t kInvalidShadow = 0; | |||
53 | static constexpr uint16_t kUncheckedShadow = 0xFFFFU; | |||
54 | ||||
55 | // Get the start address of the CFI shadow region. | |||
56 | uptr GetShadow() { | |||
57 | return cfi_shadow_limits_storage.limits.start; | |||
58 | } | |||
59 | ||||
60 | uptr GetShadowSize() { | |||
61 | return cfi_shadow_limits_storage.limits.size; | |||
62 | } | |||
63 | ||||
64 | // This will only work while the shadow is not allocated. | |||
65 | void SetShadowSize(uptr size) { | |||
66 | cfi_shadow_limits_storage.limits.size = size; | |||
67 | } | |||
68 | ||||
69 | uptr MemToShadowOffset(uptr x) { | |||
70 | return (x >> kShadowGranularity) << 1; | |||
71 | } | |||
72 | ||||
73 | uint16_t *MemToShadow(uptr x, uptr shadow_base) { | |||
74 | return (uint16_t *)(shadow_base + MemToShadowOffset(x)); | |||
75 | } | |||
76 | ||||
77 | typedef int (*CFICheckFn)(u64, void *, void *); | |||
78 | ||||
79 | // This class reads and decodes the shadow contents. | |||
80 | class ShadowValue { | |||
81 | uptr addr; | |||
82 | uint16_t v; | |||
83 | explicit ShadowValue(uptr addr, uint16_t v) : addr(addr), v(v) {} | |||
84 | ||||
85 | public: | |||
86 | bool is_invalid() const { return v == kInvalidShadow; } | |||
87 | ||||
88 | bool is_unchecked() const { return v == kUncheckedShadow; } | |||
89 | ||||
90 | CFICheckFn get_cfi_check() const { | |||
91 | assert(!is_invalid() && !is_unchecked())((!is_invalid() && !is_unchecked()) ? static_cast< void> (0) : __assert_fail ("!is_invalid() && !is_unchecked()" , "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn299582/projects/compiler-rt/lib/cfi/cfi.cc" , 91, __PRETTY_FUNCTION__)); | |||
92 | uptr aligned_addr = addr & ~(kShadowAlign - 1); | |||
93 | uptr p = aligned_addr - (((uptr)v - 1) << kShadowGranularity); | |||
94 | return reinterpret_cast<CFICheckFn>(p); | |||
95 | } | |||
96 | ||||
97 | // Load a shadow value for the given application memory address. | |||
98 | static const ShadowValue load(uptr addr) { | |||
99 | uptr shadow_base = GetShadow(); | |||
100 | uptr shadow_offset = MemToShadowOffset(addr); | |||
101 | if (shadow_offset > GetShadowSize()) | |||
102 | return ShadowValue(addr, kInvalidShadow); | |||
103 | else | |||
104 | return ShadowValue( | |||
105 | addr, *reinterpret_cast<uint16_t *>(shadow_base + shadow_offset)); | |||
106 | } | |||
107 | }; | |||
108 | ||||
109 | class ShadowBuilder { | |||
110 | uptr shadow_; | |||
111 | ||||
112 | public: | |||
113 | // Allocate a new empty shadow (for the entire address space) on the side. | |||
114 | void Start(); | |||
115 | // Mark the given address range as unchecked. | |||
116 | // This is used for uninstrumented libraries like libc. | |||
117 | // Any CFI check with a target in that range will pass. | |||
118 | void AddUnchecked(uptr begin, uptr end); | |||
119 | // Mark the given address range as belonging to a library with the given | |||
120 | // cfi_check function. | |||
121 | void Add(uptr begin, uptr end, uptr cfi_check); | |||
122 | // Finish shadow construction. Atomically switch the current active shadow | |||
123 | // region with the newly constructed one and deallocate the former. | |||
124 | void Install(); | |||
125 | }; | |||
126 | ||||
127 | void ShadowBuilder::Start() { | |||
128 | shadow_ = (uptr)MmapNoReserveOrDie(GetShadowSize(), "CFI shadow"); | |||
129 | VReport(1, "CFI: shadow at %zx .. %zx\n", shadow_, shadow_ + GetShadowSize())do { if ((uptr)Verbosity() >= (1)) Report("CFI: shadow at %zx .. %zx\n" , shadow_, shadow_ + GetShadowSize()); } while (0); | |||
130 | } | |||
131 | ||||
132 | void ShadowBuilder::AddUnchecked(uptr begin, uptr end) { | |||
133 | uint16_t *shadow_begin = MemToShadow(begin, shadow_); | |||
134 | uint16_t *shadow_end = MemToShadow(end - 1, shadow_) + 1; | |||
135 | memset(shadow_begin, kUncheckedShadow, | |||
136 | (shadow_end - shadow_begin) * sizeof(*shadow_begin)); | |||
137 | } | |||
138 | ||||
139 | void ShadowBuilder::Add(uptr begin, uptr end, uptr cfi_check) { | |||
140 | assert((cfi_check & (kShadowAlign - 1)) == 0)(((cfi_check & (kShadowAlign - 1)) == 0) ? static_cast< void> (0) : __assert_fail ("(cfi_check & (kShadowAlign - 1)) == 0" , "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn299582/projects/compiler-rt/lib/cfi/cfi.cc" , 140, __PRETTY_FUNCTION__)); | |||
141 | ||||
142 | // Don't fill anything below cfi_check. We can not represent those addresses | |||
143 | // in the shadow, and must make sure at codegen to place all valid call | |||
144 | // targets above cfi_check. | |||
145 | begin = Max(begin, cfi_check); | |||
146 | uint16_t *s = MemToShadow(begin, shadow_); | |||
147 | uint16_t *s_end = MemToShadow(end - 1, shadow_) + 1; | |||
148 | uint16_t sv = ((begin - cfi_check) >> kShadowGranularity) + 1; | |||
149 | for (; s < s_end; s++, sv++) | |||
150 | *s = sv; | |||
151 | } | |||
152 | ||||
153 | #if SANITIZER_LINUX1 | |||
154 | void ShadowBuilder::Install() { | |||
155 | MprotectReadOnly(shadow_, GetShadowSize()); | |||
156 | uptr main_shadow = GetShadow(); | |||
157 | if (main_shadow) { | |||
158 | // Update. | |||
159 | void *res = mremap((void *)shadow_, GetShadowSize(), GetShadowSize(), | |||
160 | MREMAP_MAYMOVE1 | MREMAP_FIXED2, (void *)main_shadow); | |||
161 | CHECK(res != MAP_FAILED)do { __sanitizer::u64 v1 = (u64)((res != ((void *) -1))); __sanitizer ::u64 v2 = (u64)(0); if (__builtin_expect(!!(!(v1 != v2)), 0) ) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn299582/projects/compiler-rt/lib/cfi/cfi.cc" , 161, "(" "(res != ((void *) -1))" ") " "!=" " (" "0" ")", v1 , v2); } while (false); | |||
162 | } else { | |||
163 | // Initial setup. | |||
164 | CHECK_EQ(kCfiShadowLimitsStorageSize, GetPageSizeCached())do { __sanitizer::u64 v1 = (u64)((4096)); __sanitizer::u64 v2 = (u64)((GetPageSizeCached())); if (__builtin_expect(!!(!(v1 == v2)), 0)) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn299582/projects/compiler-rt/lib/cfi/cfi.cc" , 164, "(" "(4096)" ") " "==" " (" "(GetPageSizeCached())" ")" , v1, v2); } while (false); | |||
165 | CHECK_EQ(0, GetShadow())do { __sanitizer::u64 v1 = (u64)((0)); __sanitizer::u64 v2 = ( u64)((GetShadow())); if (__builtin_expect(!!(!(v1 == v2)), 0) ) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn299582/projects/compiler-rt/lib/cfi/cfi.cc" , 165, "(" "(0)" ") " "==" " (" "(GetShadow())" ")", v1, v2); } while (false); | |||
166 | cfi_shadow_limits_storage.limits.start = shadow_; | |||
167 | MprotectReadOnly((uptr)&cfi_shadow_limits_storage, | |||
168 | sizeof(cfi_shadow_limits_storage)); | |||
169 | CHECK_EQ(shadow_, GetShadow())do { __sanitizer::u64 v1 = (u64)((shadow_)); __sanitizer::u64 v2 = (u64)((GetShadow())); if (__builtin_expect(!!(!(v1 == v2 )), 0)) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn299582/projects/compiler-rt/lib/cfi/cfi.cc" , 169, "(" "(shadow_)" ") " "==" " (" "(GetShadow())" ")", v1 , v2); } while (false); | |||
170 | } | |||
171 | } | |||
172 | #else | |||
173 | #error not implemented | |||
174 | #endif | |||
175 | ||||
176 | // This is a workaround for a glibc bug: | |||
177 | // https://sourceware.org/bugzilla/show_bug.cgi?id=15199 | |||
178 | // Other platforms can, hopefully, just do | |||
179 | // dlopen(RTLD_NOLOAD | RTLD_LAZY) | |||
180 | // dlsym("__cfi_check"). | |||
181 | uptr find_cfi_check_in_dso(dl_phdr_info *info) { | |||
182 | const ElfW(Dyn)Elf64_Dyn *dynamic = nullptr; | |||
183 | for (int i = 0; i < info->dlpi_phnum; ++i) { | |||
184 | if (info->dlpi_phdr[i].p_type == PT_DYNAMIC2) { | |||
185 | dynamic = | |||
186 | (const ElfW(Dyn)Elf64_Dyn *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr); | |||
187 | break; | |||
188 | } | |||
189 | } | |||
190 | if (!dynamic) return 0; | |||
191 | uptr strtab = 0, symtab = 0; | |||
192 | for (const ElfW(Dyn)Elf64_Dyn *p = dynamic; p->d_tag != PT_NULL0; ++p) { | |||
193 | if (p->d_tag == DT_SYMTAB6) | |||
194 | symtab = p->d_un.d_ptr; | |||
195 | else if (p->d_tag == DT_STRTAB5) | |||
196 | strtab = p->d_un.d_ptr; | |||
197 | } | |||
198 | ||||
199 | if (symtab > strtab) { | |||
200 | VReport(1, "Can not handle: symtab > strtab (%p > %zx)\n", symtab, strtab)do { if ((uptr)Verbosity() >= (1)) Report("Can not handle: symtab > strtab (%p > %zx)\n" , symtab, strtab); } while (0); | |||
201 | return 0; | |||
202 | } | |||
203 | ||||
204 | // Verify that strtab and symtab are inside of the same LOAD segment. | |||
205 | // This excludes VDSO, which has (very high) bogus strtab and symtab pointers. | |||
206 | int phdr_idx; | |||
207 | for (phdr_idx = 0; phdr_idx < info->dlpi_phnum; phdr_idx++) { | |||
208 | const Elf_Phdr *phdr = &info->dlpi_phdr[phdr_idx]; | |||
209 | if (phdr->p_type == PT_LOAD1) { | |||
210 | uptr beg = info->dlpi_addr + phdr->p_vaddr; | |||
211 | uptr end = beg + phdr->p_memsz; | |||
212 | if (strtab >= beg && strtab < end && symtab >= beg && symtab < end) | |||
213 | break; | |||
214 | } | |||
215 | } | |||
216 | if (phdr_idx == info->dlpi_phnum) { | |||
217 | // Nope, either different segments or just bogus pointers. | |||
218 | // Can not handle this. | |||
219 | VReport(1, "Can not handle: symtab %p, strtab %zx\n", symtab, strtab)do { if ((uptr)Verbosity() >= (1)) Report("Can not handle: symtab %p, strtab %zx\n" , symtab, strtab); } while (0); | |||
220 | return 0; | |||
221 | } | |||
222 | ||||
223 | for (const ElfW(Sym)Elf64_Sym *p = (const ElfW(Sym)Elf64_Sym *)symtab; (ElfW(Addr)Elf64_Addr)p < strtab; | |||
224 | ++p) { | |||
225 | char *name = (char*)(strtab + p->st_name); | |||
| ||||
226 | if (strcmp(name, "__cfi_check") == 0) { | |||
227 | assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC))((p->st_info == (((1) << 4) + ((2) & 0xf))) ? static_cast <void> (0) : __assert_fail ("p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC)" , "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn299582/projects/compiler-rt/lib/cfi/cfi.cc" , 227, __PRETTY_FUNCTION__)); | |||
228 | uptr addr = info->dlpi_addr + p->st_value; | |||
229 | return addr; | |||
230 | } | |||
231 | } | |||
232 | return 0; | |||
233 | } | |||
234 | ||||
235 | int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *data) { | |||
236 | uptr cfi_check = find_cfi_check_in_dso(info); | |||
| ||||
237 | if (cfi_check) | |||
238 | VReport(1, "Module '%s' __cfi_check %zx\n", info->dlpi_name, cfi_check)do { if ((uptr)Verbosity() >= (1)) Report("Module '%s' __cfi_check %zx\n" , info->dlpi_name, cfi_check); } while (0); | |||
239 | ||||
240 | ShadowBuilder *b = reinterpret_cast<ShadowBuilder *>(data); | |||
241 | ||||
242 | for (int i = 0; i < info->dlpi_phnum; i++) { | |||
243 | const Elf_Phdr *phdr = &info->dlpi_phdr[i]; | |||
244 | if (phdr->p_type == PT_LOAD1) { | |||
245 | // Jump tables are in the executable segment. | |||
246 | // VTables are in the non-executable one. | |||
247 | // Need to fill shadow for both. | |||
248 | // FIXME: reject writable if vtables are in the r/o segment. Depend on | |||
249 | // PT_RELRO? | |||
250 | uptr cur_beg = info->dlpi_addr + phdr->p_vaddr; | |||
251 | uptr cur_end = cur_beg + phdr->p_memsz; | |||
252 | if (cfi_check) { | |||
253 | VReport(1, " %zx .. %zx\n", cur_beg, cur_end)do { if ((uptr)Verbosity() >= (1)) Report(" %zx .. %zx\n" , cur_beg, cur_end); } while (0); | |||
254 | b->Add(cur_beg, cur_end, cfi_check); | |||
255 | } else { | |||
256 | b->AddUnchecked(cur_beg, cur_end); | |||
257 | } | |||
258 | } | |||
259 | } | |||
260 | return 0; | |||
261 | } | |||
262 | ||||
263 | // Init or update shadow for the current set of loaded libraries. | |||
264 | void UpdateShadow() { | |||
265 | ShadowBuilder b; | |||
266 | b.Start(); | |||
267 | dl_iterate_phdr(dl_iterate_phdr_cb, &b); | |||
268 | b.Install(); | |||
269 | } | |||
270 | ||||
271 | void InitShadow() { | |||
272 | CHECK_EQ(0, GetShadow())do { __sanitizer::u64 v1 = (u64)((0)); __sanitizer::u64 v2 = ( u64)((GetShadow())); if (__builtin_expect(!!(!(v1 == v2)), 0) ) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn299582/projects/compiler-rt/lib/cfi/cfi.cc" , 272, "(" "(0)" ") " "==" " (" "(GetShadow())" ")", v1, v2); } while (false); | |||
273 | CHECK_EQ(0, GetShadowSize())do { __sanitizer::u64 v1 = (u64)((0)); __sanitizer::u64 v2 = ( u64)((GetShadowSize())); if (__builtin_expect(!!(!(v1 == v2)) , 0)) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn299582/projects/compiler-rt/lib/cfi/cfi.cc" , 273, "(" "(0)" ") " "==" " (" "(GetShadowSize())" ")", v1, v2 ); } while (false); | |||
274 | ||||
275 | uptr vma = GetMaxVirtualAddress(); | |||
276 | // Shadow is 2 -> 2**kShadowGranularity. | |||
277 | SetShadowSize((vma >> (kShadowGranularity - 1)) + 1); | |||
278 | VReport(1, "CFI: VMA size %zx, shadow size %zx\n", vma, GetShadowSize())do { if ((uptr)Verbosity() >= (1)) Report("CFI: VMA size %zx, shadow size %zx\n" , vma, GetShadowSize()); } while (0); | |||
279 | ||||
280 | UpdateShadow(); | |||
281 | } | |||
282 | ||||
283 | THREADLOCAL__thread int in_loader; | |||
284 | BlockingMutex shadow_update_lock(LINKER_INITIALIZED); | |||
285 | ||||
286 | void EnterLoader() { | |||
287 | if (in_loader == 0) { | |||
288 | shadow_update_lock.Lock(); | |||
289 | } | |||
290 | ++in_loader; | |||
291 | } | |||
292 | ||||
293 | void ExitLoader() { | |||
294 | CHECK(in_loader > 0)do { __sanitizer::u64 v1 = (u64)((in_loader > 0)); __sanitizer ::u64 v2 = (u64)(0); if (__builtin_expect(!!(!(v1 != v2)), 0) ) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn299582/projects/compiler-rt/lib/cfi/cfi.cc" , 294, "(" "(in_loader > 0)" ") " "!=" " (" "0" ")", v1, v2 ); } while (false); | |||
295 | --in_loader; | |||
296 | UpdateShadow(); | |||
297 | if (in_loader == 0) { | |||
298 | shadow_update_lock.Unlock(); | |||
299 | } | |||
300 | } | |||
301 | ||||
302 | ALWAYS_INLINEinline __attribute__((always_inline)) void CfiSlowPathCommon(u64 CallSiteTypeId, void *Ptr, | |||
303 | void *DiagData) { | |||
304 | uptr Addr = (uptr)Ptr; | |||
305 | VReport(3, "__cfi_slowpath: %llx, %p\n", CallSiteTypeId, Ptr)do { if ((uptr)Verbosity() >= (3)) Report("__cfi_slowpath: %llx, %p\n" , CallSiteTypeId, Ptr); } while (0); | |||
306 | ShadowValue sv = ShadowValue::load(Addr); | |||
307 | if (sv.is_invalid()) { | |||
308 | VReport(1, "CFI: invalid memory region for a check target: %p\n", Ptr)do { if ((uptr)Verbosity() >= (1)) Report("CFI: invalid memory region for a check target: %p\n" , Ptr); } while (0); | |||
309 | #ifdef CFI_ENABLE_DIAG | |||
310 | if (DiagData) { | |||
311 | __ubsan_handle_cfi_check_fail( | |||
312 | reinterpret_cast<__ubsan::CFICheckFailData *>(DiagData), Addr, false); | |||
313 | return; | |||
314 | } | |||
315 | #endif | |||
316 | Trap(); | |||
317 | } | |||
318 | if (sv.is_unchecked()) { | |||
319 | VReport(2, "CFI: unchecked call (shadow=FFFF): %p\n", Ptr)do { if ((uptr)Verbosity() >= (2)) Report("CFI: unchecked call (shadow=FFFF): %p\n" , Ptr); } while (0); | |||
320 | return; | |||
321 | } | |||
322 | CFICheckFn cfi_check = sv.get_cfi_check(); | |||
323 | VReport(2, "__cfi_check at %p\n", cfi_check)do { if ((uptr)Verbosity() >= (2)) Report("__cfi_check at %p\n" , cfi_check); } while (0); | |||
324 | cfi_check(CallSiteTypeId, Ptr, DiagData); | |||
325 | } | |||
326 | ||||
327 | void InitializeFlags() { | |||
328 | SetCommonFlagsDefaults(); | |||
329 | #ifdef CFI_ENABLE_DIAG | |||
330 | __ubsan::Flags *uf = __ubsan::flags(); | |||
331 | uf->SetDefaults(); | |||
332 | #endif | |||
333 | ||||
334 | FlagParser cfi_parser; | |||
335 | RegisterCommonFlags(&cfi_parser); | |||
336 | cfi_parser.ParseString(GetEnv("CFI_OPTIONS")); | |||
337 | ||||
338 | #ifdef CFI_ENABLE_DIAG | |||
339 | FlagParser ubsan_parser; | |||
340 | __ubsan::RegisterUbsanFlags(&ubsan_parser, uf); | |||
341 | RegisterCommonFlags(&ubsan_parser); | |||
342 | ||||
343 | const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions(); | |||
344 | ubsan_parser.ParseString(ubsan_default_options); | |||
345 | ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS")); | |||
346 | #endif | |||
347 | ||||
348 | InitializeCommonFlags(); | |||
349 | ||||
350 | if (Verbosity()) | |||
351 | ReportUnrecognizedFlags(); | |||
352 | ||||
353 | if (common_flags()->help) { | |||
354 | cfi_parser.PrintFlagDescriptions(); | |||
355 | } | |||
356 | } | |||
357 | ||||
358 | } // namespace __cfi | |||
359 | ||||
360 | using namespace __cfi; | |||
361 | ||||
362 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE__attribute__((visibility("default"))) void | |||
363 | __cfi_slowpath(u64 CallSiteTypeId, void *Ptr) { | |||
364 | CfiSlowPathCommon(CallSiteTypeId, Ptr, nullptr); | |||
365 | } | |||
366 | ||||
367 | #ifdef CFI_ENABLE_DIAG | |||
368 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE__attribute__((visibility("default"))) void | |||
369 | __cfi_slowpath_diag(u64 CallSiteTypeId, void *Ptr, void *DiagData) { | |||
370 | CfiSlowPathCommon(CallSiteTypeId, Ptr, DiagData); | |||
371 | } | |||
372 | #endif | |||
373 | ||||
374 | // Setup shadow for dlopen()ed libraries. | |||
375 | // The actual shadow setup happens after dlopen() returns, which means that | |||
376 | // a library can not be a target of any CFI checks while its constructors are | |||
377 | // running. It's unclear how to fix this without some extra help from libc. | |||
378 | // In glibc, mmap inside dlopen is not interceptable. | |||
379 | // Maybe a seccomp-bpf filter? | |||
380 | // We could insert a high-priority constructor into the library, but that would | |||
381 | // not help with the uninstrumented libraries. | |||
382 | INTERCEPTOR(void*, dlopen, const char *filename, int flag)typedef void* (*dlopen_f)(const char *filename, int flag); namespace __interception { dlopen_f real_dlopen; } extern "C" void* dlopen (const char *filename, int flag) __attribute__((weak, alias("__interceptor_" "dlopen"), visibility("default"))); extern "C" __attribute__ ((visibility("default"))) void* __interceptor_dlopen(const char *filename, int flag) { | |||
383 | EnterLoader(); | |||
384 | void *handle = REAL(dlopen)__interception::real_dlopen(filename, flag); | |||
385 | ExitLoader(); | |||
386 | return handle; | |||
387 | } | |||
388 | ||||
389 | INTERCEPTOR(int, dlclose, void *handle)typedef int (*dlclose_f)(void *handle); namespace __interception { dlclose_f real_dlclose; } extern "C" int dlclose(void *handle ) __attribute__((weak, alias("__interceptor_" "dlclose"), visibility ("default"))); extern "C" __attribute__((visibility("default" ))) int __interceptor_dlclose(void *handle) { | |||
390 | EnterLoader(); | |||
391 | int res = REAL(dlclose)__interception::real_dlclose(handle); | |||
392 | ExitLoader(); | |||
393 | return res; | |||
394 | } | |||
395 | ||||
396 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE__attribute__((visibility("default"))) | |||
397 | #if !SANITIZER_CAN_USE_PREINIT_ARRAY1 | |||
398 | // On ELF platforms, the constructor is invoked using .preinit_array (see below) | |||
399 | __attribute__((constructor(0))) | |||
400 | #endif | |||
401 | void __cfi_init() { | |||
402 | SanitizerToolName = "CFI"; | |||
403 | InitializeFlags(); | |||
404 | InitShadow(); | |||
405 | ||||
406 | INTERCEPT_FUNCTION(dlopen)::__interception::GetRealFunctionAddress( "dlopen", (::__interception ::uptr *)&__interception::real_dlopen, (::__interception:: uptr) & (dlopen), (::__interception::uptr) & __interceptor_dlopen ); | |||
407 | INTERCEPT_FUNCTION(dlclose)::__interception::GetRealFunctionAddress( "dlclose", (::__interception ::uptr *)&__interception::real_dlclose, (::__interception ::uptr) & (dlclose), (::__interception::uptr) & __interceptor_dlclose ); | |||
408 | ||||
409 | #ifdef CFI_ENABLE_DIAG | |||
410 | __ubsan::InitAsPlugin(); | |||
411 | #endif | |||
412 | } | |||
413 | ||||
414 | #if SANITIZER_CAN_USE_PREINIT_ARRAY1 | |||
415 | // On ELF platforms, run cfi initialization before any other constructors. | |||
416 | // On other platforms we use the constructor attribute to arrange to run our | |||
417 | // initialization early. | |||
418 | extern "C" { | |||
419 | __attribute__((section(".preinit_array"), | |||
420 | used)) void (*__cfi_preinit)(void) = __cfi_init; | |||
421 | } | |||
422 | #endif |