File: | projects/compiler-rt/lib/cfi/cfi.cc |
Warning: | line 231, column 9 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_DIAG1 | |||
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~svn306458/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~svn306458/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~svn306458/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~svn306458/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~svn306458/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~svn306458/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, strsz = 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 | else if (p->d_tag == DT_STRSZ10) | |||
198 | strsz = p->d_un.d_ptr; | |||
199 | } | |||
200 | ||||
201 | if (symtab > strtab) { | |||
202 | 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); | |||
203 | return 0; | |||
204 | } | |||
205 | ||||
206 | // Verify that strtab and symtab are inside of the same LOAD segment. | |||
207 | // This excludes VDSO, which has (very high) bogus strtab and symtab pointers. | |||
208 | int phdr_idx; | |||
209 | for (phdr_idx = 0; phdr_idx < info->dlpi_phnum; phdr_idx++) { | |||
210 | const Elf_Phdr *phdr = &info->dlpi_phdr[phdr_idx]; | |||
211 | if (phdr->p_type == PT_LOAD1) { | |||
212 | uptr beg = info->dlpi_addr + phdr->p_vaddr; | |||
213 | uptr end = beg + phdr->p_memsz; | |||
214 | if (strtab >= beg && strtab + strsz < end && symtab >= beg && | |||
215 | symtab < end) | |||
216 | break; | |||
217 | } | |||
218 | } | |||
219 | if (phdr_idx == info->dlpi_phnum) { | |||
220 | // Nope, either different segments or just bogus pointers. | |||
221 | // Can not handle this. | |||
222 | 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); | |||
223 | return 0; | |||
224 | } | |||
225 | ||||
226 | for (const ElfW(Sym)Elf64_Sym *p = (const ElfW(Sym)Elf64_Sym *)symtab; (ElfW(Addr)Elf64_Addr)p < strtab; | |||
227 | ++p) { | |||
228 | // There is no reliable way to find the end of the symbol table. In | |||
229 | // lld-produces files, there are other sections between symtab and strtab. | |||
230 | // Stop looking when the symbol name is not inside strtab. | |||
231 | if (p->st_name >= strsz) break; | |||
| ||||
232 | char *name = (char*)(strtab + p->st_name); | |||
233 | if (strcmp(name, "__cfi_check") == 0) { | |||
234 | assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) ||((p->st_info == (((1) << 4) + ((2) & 0xf)) || p-> st_info == (((2) << 4) + ((2) & 0xf))) ? static_cast <void> (0) : __assert_fail ("p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) || p->st_info == ELF32_ST_INFO(STB_WEAK, STT_FUNC)" , "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn306458/projects/compiler-rt/lib/cfi/cfi.cc" , 235, __PRETTY_FUNCTION__)) | |||
235 | p->st_info == ELF32_ST_INFO(STB_WEAK, STT_FUNC))((p->st_info == (((1) << 4) + ((2) & 0xf)) || p-> st_info == (((2) << 4) + ((2) & 0xf))) ? static_cast <void> (0) : __assert_fail ("p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) || p->st_info == ELF32_ST_INFO(STB_WEAK, STT_FUNC)" , "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn306458/projects/compiler-rt/lib/cfi/cfi.cc" , 235, __PRETTY_FUNCTION__)); | |||
236 | uptr addr = info->dlpi_addr + p->st_value; | |||
237 | return addr; | |||
238 | } | |||
239 | } | |||
240 | return 0; | |||
241 | } | |||
242 | ||||
243 | int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *data) { | |||
244 | uptr cfi_check = find_cfi_check_in_dso(info); | |||
| ||||
245 | if (cfi_check) | |||
246 | 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); | |||
247 | ||||
248 | ShadowBuilder *b = reinterpret_cast<ShadowBuilder *>(data); | |||
249 | ||||
250 | for (int i = 0; i < info->dlpi_phnum; i++) { | |||
251 | const Elf_Phdr *phdr = &info->dlpi_phdr[i]; | |||
252 | if (phdr->p_type == PT_LOAD1) { | |||
253 | // Jump tables are in the executable segment. | |||
254 | // VTables are in the non-executable one. | |||
255 | // Need to fill shadow for both. | |||
256 | // FIXME: reject writable if vtables are in the r/o segment. Depend on | |||
257 | // PT_RELRO? | |||
258 | uptr cur_beg = info->dlpi_addr + phdr->p_vaddr; | |||
259 | uptr cur_end = cur_beg + phdr->p_memsz; | |||
260 | if (cfi_check) { | |||
261 | VReport(1, " %zx .. %zx\n", cur_beg, cur_end)do { if ((uptr)Verbosity() >= (1)) Report(" %zx .. %zx\n" , cur_beg, cur_end); } while (0); | |||
262 | b->Add(cur_beg, cur_end, cfi_check); | |||
263 | } else { | |||
264 | b->AddUnchecked(cur_beg, cur_end); | |||
265 | } | |||
266 | } | |||
267 | } | |||
268 | return 0; | |||
269 | } | |||
270 | ||||
271 | // Init or update shadow for the current set of loaded libraries. | |||
272 | void UpdateShadow() { | |||
273 | ShadowBuilder b; | |||
274 | b.Start(); | |||
275 | dl_iterate_phdr(dl_iterate_phdr_cb, &b); | |||
276 | b.Install(); | |||
277 | } | |||
278 | ||||
279 | void InitShadow() { | |||
280 | 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~svn306458/projects/compiler-rt/lib/cfi/cfi.cc" , 280, "(" "(0)" ") " "==" " (" "(GetShadow())" ")", v1, v2); } while (false); | |||
281 | 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~svn306458/projects/compiler-rt/lib/cfi/cfi.cc" , 281, "(" "(0)" ") " "==" " (" "(GetShadowSize())" ")", v1, v2 ); } while (false); | |||
282 | ||||
283 | uptr vma = GetMaxVirtualAddress(); | |||
284 | // Shadow is 2 -> 2**kShadowGranularity. | |||
285 | SetShadowSize((vma >> (kShadowGranularity - 1)) + 1); | |||
286 | 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); | |||
287 | ||||
288 | UpdateShadow(); | |||
289 | } | |||
290 | ||||
291 | THREADLOCAL__thread int in_loader; | |||
292 | BlockingMutex shadow_update_lock(LINKER_INITIALIZED); | |||
293 | ||||
294 | void EnterLoader() { | |||
295 | if (in_loader == 0) { | |||
296 | shadow_update_lock.Lock(); | |||
297 | } | |||
298 | ++in_loader; | |||
299 | } | |||
300 | ||||
301 | void ExitLoader() { | |||
302 | 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~svn306458/projects/compiler-rt/lib/cfi/cfi.cc" , 302, "(" "(in_loader > 0)" ") " "!=" " (" "0" ")", v1, v2 ); } while (false); | |||
303 | --in_loader; | |||
304 | UpdateShadow(); | |||
305 | if (in_loader == 0) { | |||
306 | shadow_update_lock.Unlock(); | |||
307 | } | |||
308 | } | |||
309 | ||||
310 | ALWAYS_INLINEinline __attribute__((always_inline)) void CfiSlowPathCommon(u64 CallSiteTypeId, void *Ptr, | |||
311 | void *DiagData) { | |||
312 | uptr Addr = (uptr)Ptr; | |||
313 | VReport(3, "__cfi_slowpath: %llx, %p\n", CallSiteTypeId, Ptr)do { if ((uptr)Verbosity() >= (3)) Report("__cfi_slowpath: %llx, %p\n" , CallSiteTypeId, Ptr); } while (0); | |||
314 | ShadowValue sv = ShadowValue::load(Addr); | |||
315 | if (sv.is_invalid()) { | |||
316 | 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); | |||
317 | #ifdef CFI_ENABLE_DIAG1 | |||
318 | if (DiagData) { | |||
319 | __ubsan_handle_cfi_check_fail( | |||
320 | reinterpret_cast<__ubsan::CFICheckFailData *>(DiagData), Addr, false); | |||
321 | return; | |||
322 | } | |||
323 | #endif | |||
324 | Trap(); | |||
325 | } | |||
326 | if (sv.is_unchecked()) { | |||
327 | 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); | |||
328 | return; | |||
329 | } | |||
330 | CFICheckFn cfi_check = sv.get_cfi_check(); | |||
331 | VReport(2, "__cfi_check at %p\n", cfi_check)do { if ((uptr)Verbosity() >= (2)) Report("__cfi_check at %p\n" , cfi_check); } while (0); | |||
332 | cfi_check(CallSiteTypeId, Ptr, DiagData); | |||
333 | } | |||
334 | ||||
335 | void InitializeFlags() { | |||
336 | SetCommonFlagsDefaults(); | |||
337 | #ifdef CFI_ENABLE_DIAG1 | |||
338 | __ubsan::Flags *uf = __ubsan::flags(); | |||
339 | uf->SetDefaults(); | |||
340 | #endif | |||
341 | ||||
342 | FlagParser cfi_parser; | |||
343 | RegisterCommonFlags(&cfi_parser); | |||
344 | cfi_parser.ParseString(GetEnv("CFI_OPTIONS")); | |||
345 | ||||
346 | #ifdef CFI_ENABLE_DIAG1 | |||
347 | FlagParser ubsan_parser; | |||
348 | __ubsan::RegisterUbsanFlags(&ubsan_parser, uf); | |||
349 | RegisterCommonFlags(&ubsan_parser); | |||
350 | ||||
351 | const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions(); | |||
352 | ubsan_parser.ParseString(ubsan_default_options); | |||
353 | ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS")); | |||
354 | #endif | |||
355 | ||||
356 | InitializeCommonFlags(); | |||
357 | ||||
358 | if (Verbosity()) | |||
359 | ReportUnrecognizedFlags(); | |||
360 | ||||
361 | if (common_flags()->help) { | |||
362 | cfi_parser.PrintFlagDescriptions(); | |||
363 | } | |||
364 | } | |||
365 | ||||
366 | } // namespace __cfi | |||
367 | ||||
368 | using namespace __cfi; | |||
369 | ||||
370 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE__attribute__((visibility("default"))) void | |||
371 | __cfi_slowpath(u64 CallSiteTypeId, void *Ptr) { | |||
372 | CfiSlowPathCommon(CallSiteTypeId, Ptr, nullptr); | |||
373 | } | |||
374 | ||||
375 | #ifdef CFI_ENABLE_DIAG1 | |||
376 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE__attribute__((visibility("default"))) void | |||
377 | __cfi_slowpath_diag(u64 CallSiteTypeId, void *Ptr, void *DiagData) { | |||
378 | CfiSlowPathCommon(CallSiteTypeId, Ptr, DiagData); | |||
379 | } | |||
380 | #endif | |||
381 | ||||
382 | // Setup shadow for dlopen()ed libraries. | |||
383 | // The actual shadow setup happens after dlopen() returns, which means that | |||
384 | // a library can not be a target of any CFI checks while its constructors are | |||
385 | // running. It's unclear how to fix this without some extra help from libc. | |||
386 | // In glibc, mmap inside dlopen is not interceptable. | |||
387 | // Maybe a seccomp-bpf filter? | |||
388 | // We could insert a high-priority constructor into the library, but that would | |||
389 | // not help with the uninstrumented libraries. | |||
390 | 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) { | |||
391 | EnterLoader(); | |||
392 | void *handle = REAL(dlopen)__interception::real_dlopen(filename, flag); | |||
393 | ExitLoader(); | |||
394 | return handle; | |||
395 | } | |||
396 | ||||
397 | 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) { | |||
398 | EnterLoader(); | |||
399 | int res = REAL(dlclose)__interception::real_dlclose(handle); | |||
400 | ExitLoader(); | |||
401 | return res; | |||
402 | } | |||
403 | ||||
404 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE__attribute__((visibility("default"))) | |||
405 | #if !SANITIZER_CAN_USE_PREINIT_ARRAY1 | |||
406 | // On ELF platforms, the constructor is invoked using .preinit_array (see below) | |||
407 | __attribute__((constructor(0))) | |||
408 | #endif | |||
409 | void __cfi_init() { | |||
410 | SanitizerToolName = "CFI"; | |||
411 | InitializeFlags(); | |||
412 | InitShadow(); | |||
413 | ||||
414 | INTERCEPT_FUNCTION(dlopen)::__interception::GetRealFunctionAddress( "dlopen", (::__interception ::uptr *)&__interception::real_dlopen, (::__interception:: uptr) & (dlopen), (::__interception::uptr) & __interceptor_dlopen ); | |||
415 | INTERCEPT_FUNCTION(dlclose)::__interception::GetRealFunctionAddress( "dlclose", (::__interception ::uptr *)&__interception::real_dlclose, (::__interception ::uptr) & (dlclose), (::__interception::uptr) & __interceptor_dlclose ); | |||
416 | ||||
417 | #ifdef CFI_ENABLE_DIAG1 | |||
418 | __ubsan::InitAsPlugin(); | |||
419 | #endif | |||
420 | } | |||
421 | ||||
422 | #if SANITIZER_CAN_USE_PREINIT_ARRAY1 | |||
423 | // On ELF platforms, run cfi initialization before any other constructors. | |||
424 | // On other platforms we use the constructor attribute to arrange to run our | |||
425 | // initialization early. | |||
426 | extern "C" { | |||
427 | __attribute__((section(".preinit_array"), | |||
428 | used)) void (*__cfi_preinit)(void) = __cfi_init; | |||
429 | } | |||
430 | #endif |