1 | //===-- asan_rtl.cpp ------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file is a part of AddressSanitizer, an address sanity checker. |
10 | // |
11 | // Main file of the ASan run-time library. |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "asan_activation.h" |
15 | #include "asan_allocator.h" |
16 | #include "asan_fake_stack.h" |
17 | #include "asan_interceptors.h" |
18 | #include "asan_interface_internal.h" |
19 | #include "asan_internal.h" |
20 | #include "asan_mapping.h" |
21 | #include "asan_poisoning.h" |
22 | #include "asan_report.h" |
23 | #include "asan_stack.h" |
24 | #include "asan_stats.h" |
25 | #include "asan_suppressions.h" |
26 | #include "asan_thread.h" |
27 | #include "lsan/lsan_common.h" |
28 | #include "sanitizer_common/sanitizer_atomic.h" |
29 | #include "sanitizer_common/sanitizer_flags.h" |
30 | #include "sanitizer_common/sanitizer_interface_internal.h" |
31 | #include "sanitizer_common/sanitizer_libc.h" |
32 | #include "sanitizer_common/sanitizer_symbolizer.h" |
33 | #include "ubsan/ubsan_init.h" |
34 | #include "ubsan/ubsan_platform.h" |
35 | |
36 | uptr __asan_shadow_memory_dynamic_address; // Global interface symbol. |
37 | int __asan_option_detect_stack_use_after_return; // Global interface symbol. |
38 | uptr *__asan_test_only_reported_buggy_pointer; // Used only for testing asan. |
39 | |
40 | namespace __asan { |
41 | |
42 | uptr AsanMappingProfile[kAsanMappingProfileSize]; |
43 | |
44 | static void AsanDie() { |
45 | static atomic_uint32_t num_calls; |
46 | if (atomic_fetch_add(a: &num_calls, v: 1, mo: memory_order_relaxed) != 0) { |
47 | // Don't die twice - run a busy loop. |
48 | while (1) { |
49 | internal_sched_yield(); |
50 | } |
51 | } |
52 | if (common_flags()->print_module_map >= 1) |
53 | DumpProcessMap(); |
54 | |
55 | WaitForDebugger(seconds: flags()->sleep_before_dying, label: "before dying" ); |
56 | |
57 | if (flags()->unmap_shadow_on_exit) { |
58 | if (kMidMemBeg) { |
59 | UnmapOrDie(addr: (void*)kLowShadowBeg, size: kMidMemBeg - kLowShadowBeg); |
60 | UnmapOrDie(addr: (void*)kMidMemEnd, kHighShadowEnd - kMidMemEnd); |
61 | } else { |
62 | if (kHighShadowEnd) |
63 | UnmapOrDie(addr: (void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); |
64 | } |
65 | } |
66 | } |
67 | |
68 | static void CheckUnwind() { |
69 | GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check); |
70 | stack.Print(); |
71 | } |
72 | |
73 | // -------------------------- Globals --------------------- {{{1 |
74 | static StaticSpinMutex asan_inited_mutex; |
75 | static atomic_uint8_t asan_inited = {.val_dont_use: 0}; |
76 | |
77 | static void SetAsanInited() { |
78 | atomic_store(a: &asan_inited, v: 1, mo: memory_order_release); |
79 | } |
80 | |
81 | bool AsanInited() { |
82 | return atomic_load(a: &asan_inited, mo: memory_order_acquire) == 1; |
83 | } |
84 | |
85 | bool replace_intrin_cached; |
86 | |
87 | #if !ASAN_FIXED_MAPPING |
88 | uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; |
89 | #endif |
90 | |
91 | // -------------------------- Misc ---------------- {{{1 |
92 | void ShowStatsAndAbort() { |
93 | __asan_print_accumulated_stats(); |
94 | Die(); |
95 | } |
96 | |
97 | NOINLINE |
98 | static void ReportGenericErrorWrapper(uptr addr, bool is_write, int size, |
99 | int exp_arg, bool fatal) { |
100 | GET_CALLER_PC_BP_SP; |
101 | ReportGenericError(pc, bp, sp, addr, is_write, access_size: size, exp: exp_arg, fatal); |
102 | } |
103 | |
104 | // --------------- LowLevelAllocateCallbac ---------- {{{1 |
105 | static void OnLowLevelAllocate(uptr ptr, uptr size) { |
106 | PoisonShadow(addr: ptr, size, value: kAsanInternalHeapMagic); |
107 | } |
108 | |
109 | // -------------------------- Run-time entry ------------------- {{{1 |
110 | // exported functions |
111 | #define ASAN_REPORT_ERROR(type, is_write, size) \ |
112 | extern "C" NOINLINE INTERFACE_ATTRIBUTE \ |
113 | void __asan_report_ ## type ## size(uptr addr) { \ |
114 | GET_CALLER_PC_BP_SP; \ |
115 | ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \ |
116 | } \ |
117 | extern "C" NOINLINE INTERFACE_ATTRIBUTE \ |
118 | void __asan_report_exp_ ## type ## size(uptr addr, u32 exp) { \ |
119 | GET_CALLER_PC_BP_SP; \ |
120 | ReportGenericError(pc, bp, sp, addr, is_write, size, exp, true); \ |
121 | } \ |
122 | extern "C" NOINLINE INTERFACE_ATTRIBUTE \ |
123 | void __asan_report_ ## type ## size ## _noabort(uptr addr) { \ |
124 | GET_CALLER_PC_BP_SP; \ |
125 | ReportGenericError(pc, bp, sp, addr, is_write, size, 0, false); \ |
126 | } \ |
127 | |
128 | ASAN_REPORT_ERROR(load, false, 1) |
129 | ASAN_REPORT_ERROR(load, false, 2) |
130 | ASAN_REPORT_ERROR(load, false, 4) |
131 | ASAN_REPORT_ERROR(load, false, 8) |
132 | ASAN_REPORT_ERROR(load, false, 16) |
133 | ASAN_REPORT_ERROR(store, true, 1) |
134 | ASAN_REPORT_ERROR(store, true, 2) |
135 | ASAN_REPORT_ERROR(store, true, 4) |
136 | ASAN_REPORT_ERROR(store, true, 8) |
137 | ASAN_REPORT_ERROR(store, true, 16) |
138 | |
139 | #define ASAN_REPORT_ERROR_N(type, is_write) \ |
140 | extern "C" NOINLINE INTERFACE_ATTRIBUTE \ |
141 | void __asan_report_ ## type ## _n(uptr addr, uptr size) { \ |
142 | GET_CALLER_PC_BP_SP; \ |
143 | ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \ |
144 | } \ |
145 | extern "C" NOINLINE INTERFACE_ATTRIBUTE \ |
146 | void __asan_report_exp_ ## type ## _n(uptr addr, uptr size, u32 exp) { \ |
147 | GET_CALLER_PC_BP_SP; \ |
148 | ReportGenericError(pc, bp, sp, addr, is_write, size, exp, true); \ |
149 | } \ |
150 | extern "C" NOINLINE INTERFACE_ATTRIBUTE \ |
151 | void __asan_report_ ## type ## _n_noabort(uptr addr, uptr size) { \ |
152 | GET_CALLER_PC_BP_SP; \ |
153 | ReportGenericError(pc, bp, sp, addr, is_write, size, 0, false); \ |
154 | } \ |
155 | |
156 | ASAN_REPORT_ERROR_N(load, false) |
157 | ASAN_REPORT_ERROR_N(store, true) |
158 | |
159 | #define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg, fatal) \ |
160 | uptr sp = MEM_TO_SHADOW(addr); \ |
161 | uptr s = size <= ASAN_SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp) \ |
162 | : *reinterpret_cast<u16 *>(sp); \ |
163 | if (UNLIKELY(s)) { \ |
164 | if (UNLIKELY(size >= ASAN_SHADOW_GRANULARITY || \ |
165 | ((s8)((addr & (ASAN_SHADOW_GRANULARITY - 1)) + size - 1)) >= \ |
166 | (s8)s)) { \ |
167 | ReportGenericErrorWrapper(addr, is_write, size, exp_arg, fatal); \ |
168 | } \ |
169 | } |
170 | |
171 | #define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size) \ |
172 | extern "C" NOINLINE INTERFACE_ATTRIBUTE \ |
173 | void __asan_##type##size(uptr addr) { \ |
174 | ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0, true) \ |
175 | } \ |
176 | extern "C" NOINLINE INTERFACE_ATTRIBUTE \ |
177 | void __asan_exp_##type##size(uptr addr, u32 exp) { \ |
178 | ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp, true) \ |
179 | } \ |
180 | extern "C" NOINLINE INTERFACE_ATTRIBUTE \ |
181 | void __asan_##type##size ## _noabort(uptr addr) { \ |
182 | ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0, false) \ |
183 | } \ |
184 | |
185 | ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1) |
186 | ASAN_MEMORY_ACCESS_CALLBACK(load, false, 2) |
187 | ASAN_MEMORY_ACCESS_CALLBACK(load, false, 4) |
188 | ASAN_MEMORY_ACCESS_CALLBACK(load, false, 8) |
189 | ASAN_MEMORY_ACCESS_CALLBACK(load, false, 16) |
190 | ASAN_MEMORY_ACCESS_CALLBACK(store, true, 1) |
191 | ASAN_MEMORY_ACCESS_CALLBACK(store, true, 2) |
192 | ASAN_MEMORY_ACCESS_CALLBACK(store, true, 4) |
193 | ASAN_MEMORY_ACCESS_CALLBACK(store, true, 8) |
194 | ASAN_MEMORY_ACCESS_CALLBACK(store, true, 16) |
195 | |
196 | extern "C" |
197 | NOINLINE INTERFACE_ATTRIBUTE |
198 | void __asan_loadN(uptr addr, uptr size) { |
199 | if ((addr = __asan_region_is_poisoned(beg: addr, size))) { |
200 | GET_CALLER_PC_BP_SP; |
201 | ReportGenericError(pc, bp, sp, addr, is_write: false, access_size: size, exp: 0, fatal: true); |
202 | } |
203 | } |
204 | |
205 | extern "C" |
206 | NOINLINE INTERFACE_ATTRIBUTE |
207 | void __asan_exp_loadN(uptr addr, uptr size, u32 exp) { |
208 | if ((addr = __asan_region_is_poisoned(beg: addr, size))) { |
209 | GET_CALLER_PC_BP_SP; |
210 | ReportGenericError(pc, bp, sp, addr, is_write: false, access_size: size, exp, fatal: true); |
211 | } |
212 | } |
213 | |
214 | extern "C" |
215 | NOINLINE INTERFACE_ATTRIBUTE |
216 | void __asan_loadN_noabort(uptr addr, uptr size) { |
217 | if ((addr = __asan_region_is_poisoned(beg: addr, size))) { |
218 | GET_CALLER_PC_BP_SP; |
219 | ReportGenericError(pc, bp, sp, addr, is_write: false, access_size: size, exp: 0, fatal: false); |
220 | } |
221 | } |
222 | |
223 | extern "C" |
224 | NOINLINE INTERFACE_ATTRIBUTE |
225 | void __asan_storeN(uptr addr, uptr size) { |
226 | if ((addr = __asan_region_is_poisoned(beg: addr, size))) { |
227 | GET_CALLER_PC_BP_SP; |
228 | ReportGenericError(pc, bp, sp, addr, is_write: true, access_size: size, exp: 0, fatal: true); |
229 | } |
230 | } |
231 | |
232 | extern "C" |
233 | NOINLINE INTERFACE_ATTRIBUTE |
234 | void __asan_exp_storeN(uptr addr, uptr size, u32 exp) { |
235 | if ((addr = __asan_region_is_poisoned(beg: addr, size))) { |
236 | GET_CALLER_PC_BP_SP; |
237 | ReportGenericError(pc, bp, sp, addr, is_write: true, access_size: size, exp, fatal: true); |
238 | } |
239 | } |
240 | |
241 | extern "C" |
242 | NOINLINE INTERFACE_ATTRIBUTE |
243 | void __asan_storeN_noabort(uptr addr, uptr size) { |
244 | if ((addr = __asan_region_is_poisoned(beg: addr, size))) { |
245 | GET_CALLER_PC_BP_SP; |
246 | ReportGenericError(pc, bp, sp, addr, is_write: true, access_size: size, exp: 0, fatal: false); |
247 | } |
248 | } |
249 | |
250 | // Force the linker to keep the symbols for various ASan interface functions. |
251 | // We want to keep those in the executable in order to let the instrumented |
252 | // dynamic libraries access the symbol even if it is not used by the executable |
253 | // itself. This should help if the build system is removing dead code at link |
254 | // time. |
255 | static NOINLINE void force_interface_symbols() { |
256 | volatile int fake_condition = 0; // prevent dead condition elimination. |
257 | // __asan_report_* functions are noreturn, so we need a switch to prevent |
258 | // the compiler from removing any of them. |
259 | // clang-format off |
260 | switch (fake_condition) { |
261 | case 1: __asan_report_load1(addr: 0); break; |
262 | case 2: __asan_report_load2(addr: 0); break; |
263 | case 3: __asan_report_load4(addr: 0); break; |
264 | case 4: __asan_report_load8(addr: 0); break; |
265 | case 5: __asan_report_load16(addr: 0); break; |
266 | case 6: __asan_report_load_n(addr: 0, size: 0); break; |
267 | case 7: __asan_report_store1(addr: 0); break; |
268 | case 8: __asan_report_store2(addr: 0); break; |
269 | case 9: __asan_report_store4(addr: 0); break; |
270 | case 10: __asan_report_store8(addr: 0); break; |
271 | case 11: __asan_report_store16(addr: 0); break; |
272 | case 12: __asan_report_store_n(addr: 0, size: 0); break; |
273 | case 13: __asan_report_exp_load1(addr: 0, exp: 0); break; |
274 | case 14: __asan_report_exp_load2(addr: 0, exp: 0); break; |
275 | case 15: __asan_report_exp_load4(addr: 0, exp: 0); break; |
276 | case 16: __asan_report_exp_load8(addr: 0, exp: 0); break; |
277 | case 17: __asan_report_exp_load16(addr: 0, exp: 0); break; |
278 | case 18: __asan_report_exp_load_n(addr: 0, size: 0, exp: 0); break; |
279 | case 19: __asan_report_exp_store1(addr: 0, exp: 0); break; |
280 | case 20: __asan_report_exp_store2(addr: 0, exp: 0); break; |
281 | case 21: __asan_report_exp_store4(addr: 0, exp: 0); break; |
282 | case 22: __asan_report_exp_store8(addr: 0, exp: 0); break; |
283 | case 23: __asan_report_exp_store16(addr: 0, exp: 0); break; |
284 | case 24: __asan_report_exp_store_n(addr: 0, size: 0, exp: 0); break; |
285 | case 25: __asan_register_globals(globals: nullptr, n: 0); break; |
286 | case 26: __asan_unregister_globals(globals: nullptr, n: 0); break; |
287 | case 27: __asan_set_death_callback(callback: nullptr); break; |
288 | case 28: __asan_set_error_report_callback(callback: nullptr); break; |
289 | case 29: __asan_handle_no_return(); break; |
290 | case 30: __asan_address_is_poisoned(addr: nullptr); break; |
291 | case 31: __asan_poison_memory_region(addr: nullptr, size: 0); break; |
292 | case 32: __asan_unpoison_memory_region(addr: nullptr, size: 0); break; |
293 | case 34: __asan_before_dynamic_init(module_name: nullptr); break; |
294 | case 35: __asan_after_dynamic_init(); break; |
295 | case 36: __asan_poison_stack_memory(addr: 0, size: 0); break; |
296 | case 37: __asan_unpoison_stack_memory(addr: 0, size: 0); break; |
297 | case 38: __asan_region_is_poisoned(beg: 0, size: 0); break; |
298 | case 39: __asan_describe_address(addr: 0); break; |
299 | case 40: __asan_set_shadow_00(addr: 0, size: 0); break; |
300 | case 41: __asan_set_shadow_01(addr: 0, size: 0); break; |
301 | case 42: __asan_set_shadow_02(addr: 0, size: 0); break; |
302 | case 43: __asan_set_shadow_03(addr: 0, size: 0); break; |
303 | case 44: __asan_set_shadow_04(addr: 0, size: 0); break; |
304 | case 45: __asan_set_shadow_05(addr: 0, size: 0); break; |
305 | case 46: __asan_set_shadow_06(addr: 0, size: 0); break; |
306 | case 47: __asan_set_shadow_07(addr: 0, size: 0); break; |
307 | case 48: __asan_set_shadow_f1(addr: 0, size: 0); break; |
308 | case 49: __asan_set_shadow_f2(addr: 0, size: 0); break; |
309 | case 50: __asan_set_shadow_f3(addr: 0, size: 0); break; |
310 | case 51: __asan_set_shadow_f5(addr: 0, size: 0); break; |
311 | case 52: __asan_set_shadow_f8(addr: 0, size: 0); break; |
312 | } |
313 | // clang-format on |
314 | } |
315 | |
316 | static void asan_atexit() { |
317 | Printf(format: "AddressSanitizer exit stats:\n" ); |
318 | __asan_print_accumulated_stats(); |
319 | // Print AsanMappingProfile. |
320 | for (uptr i = 0; i < kAsanMappingProfileSize; i++) { |
321 | if (AsanMappingProfile[i] == 0) continue; |
322 | Printf(format: "asan_mapping.h:%zd -- %zd\n" , i, AsanMappingProfile[i]); |
323 | } |
324 | } |
325 | |
326 | static void InitializeHighMemEnd() { |
327 | #if !ASAN_FIXED_MAPPING |
328 | kHighMemEnd = GetMaxUserVirtualAddress(); |
329 | // Increase kHighMemEnd to make sure it's properly |
330 | // aligned together with kHighMemBeg: |
331 | kHighMemEnd |= (GetMmapGranularity() << ASAN_SHADOW_SCALE) - 1; |
332 | #endif // !ASAN_FIXED_MAPPING |
333 | CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0); |
334 | } |
335 | |
336 | void PrintAddressSpaceLayout() { |
337 | if (kHighMemBeg) { |
338 | Printf(format: "|| `[%p, %p]` || HighMem ||\n" , |
339 | (void*)kHighMemBeg, (void*)kHighMemEnd); |
340 | Printf(format: "|| `[%p, %p]` || HighShadow ||\n" , |
341 | (void*)kHighShadowBeg, (void*)kHighShadowEnd); |
342 | } |
343 | if (kMidMemBeg) { |
344 | Printf(format: "|| `[%p, %p]` || ShadowGap3 ||\n" , |
345 | (void*)kShadowGap3Beg, (void*)kShadowGap3End); |
346 | Printf(format: "|| `[%p, %p]` || MidMem ||\n" , |
347 | (void*)kMidMemBeg, (void*)kMidMemEnd); |
348 | Printf(format: "|| `[%p, %p]` || ShadowGap2 ||\n" , |
349 | (void*)kShadowGap2Beg, (void*)kShadowGap2End); |
350 | Printf(format: "|| `[%p, %p]` || MidShadow ||\n" , |
351 | (void*)kMidShadowBeg, (void*)kMidShadowEnd); |
352 | } |
353 | Printf(format: "|| `[%p, %p]` || ShadowGap ||\n" , |
354 | (void*)kShadowGapBeg, (void*)kShadowGapEnd); |
355 | if (kLowShadowBeg) { |
356 | Printf(format: "|| `[%p, %p]` || LowShadow ||\n" , |
357 | (void*)kLowShadowBeg, (void*)kLowShadowEnd); |
358 | Printf(format: "|| `[%p, %p]` || LowMem ||\n" , |
359 | (void*)kLowMemBeg, (void*)kLowMemEnd); |
360 | } |
361 | Printf(format: "MemToShadow(shadow): %p %p" , |
362 | (void*)MEM_TO_SHADOW(kLowShadowBeg), |
363 | (void*)MEM_TO_SHADOW(kLowShadowEnd)); |
364 | if (kHighMemBeg) { |
365 | Printf(format: " %p %p" , |
366 | (void*)MEM_TO_SHADOW(kHighShadowBeg), |
367 | (void*)MEM_TO_SHADOW(kHighShadowEnd)); |
368 | } |
369 | if (kMidMemBeg) { |
370 | Printf(format: " %p %p" , |
371 | (void*)MEM_TO_SHADOW(kMidShadowBeg), |
372 | (void*)MEM_TO_SHADOW(kMidShadowEnd)); |
373 | } |
374 | Printf(format: "\n" ); |
375 | Printf(format: "redzone=%zu\n" , (uptr)flags()->redzone); |
376 | Printf(format: "max_redzone=%zu\n" , (uptr)flags()->max_redzone); |
377 | Printf(format: "quarantine_size_mb=%zuM\n" , (uptr)flags()->quarantine_size_mb); |
378 | Printf(format: "thread_local_quarantine_size_kb=%zuK\n" , |
379 | (uptr)flags()->thread_local_quarantine_size_kb); |
380 | Printf(format: "malloc_context_size=%zu\n" , |
381 | (uptr)common_flags()->malloc_context_size); |
382 | |
383 | Printf(format: "SHADOW_SCALE: %d\n" , (int)ASAN_SHADOW_SCALE); |
384 | Printf(format: "SHADOW_GRANULARITY: %d\n" , (int)ASAN_SHADOW_GRANULARITY); |
385 | Printf(format: "SHADOW_OFFSET: %p\n" , (void *)ASAN_SHADOW_OFFSET); |
386 | CHECK(ASAN_SHADOW_SCALE >= 3 && ASAN_SHADOW_SCALE <= 7); |
387 | if (kMidMemBeg) |
388 | CHECK(kMidShadowBeg > kLowShadowEnd && |
389 | kMidMemBeg > kMidShadowEnd && |
390 | kHighShadowBeg > kMidMemEnd); |
391 | } |
392 | |
393 | static bool AsanInitInternal() { |
394 | if (LIKELY(AsanInited())) |
395 | return true; |
396 | SanitizerToolName = "AddressSanitizer" ; |
397 | |
398 | CacheBinaryName(); |
399 | |
400 | // Initialize flags. This must be done early, because most of the |
401 | // initialization steps look at flags(). |
402 | InitializeFlags(); |
403 | |
404 | WaitForDebugger(seconds: flags()->sleep_before_init, label: "before init" ); |
405 | |
406 | // Stop performing init at this point if we are being loaded via |
407 | // dlopen() and the platform supports it. |
408 | if (SANITIZER_SUPPORTS_INIT_FOR_DLOPEN && UNLIKELY(HandleDlopenInit())) { |
409 | VReport(1, "AddressSanitizer init is being performed for dlopen().\n" ); |
410 | return false; |
411 | } |
412 | |
413 | // Make sure we are not statically linked. |
414 | __interception::DoesNotSupportStaticLinking(); |
415 | AsanCheckIncompatibleRT(); |
416 | AsanCheckDynamicRTPrereqs(); |
417 | AvoidCVE_2016_2143(); |
418 | |
419 | SetCanPoisonMemory(flags()->poison_heap); |
420 | SetMallocContextSize(common_flags()->malloc_context_size); |
421 | |
422 | InitializePlatformExceptionHandlers(); |
423 | |
424 | InitializeHighMemEnd(); |
425 | |
426 | // Install tool-specific callbacks in sanitizer_common. |
427 | AddDieCallback(callback: AsanDie); |
428 | SetCheckUnwindCallback(CheckUnwind); |
429 | SetPrintfAndReportCallback(AppendToErrorMessageBuffer); |
430 | |
431 | __sanitizer_set_report_path(path: common_flags()->log_path); |
432 | |
433 | __asan_option_detect_stack_use_after_return = |
434 | flags()->detect_stack_use_after_return; |
435 | |
436 | __sanitizer::InitializePlatformEarly(); |
437 | |
438 | // Setup internal allocator callback. |
439 | SetLowLevelAllocateMinAlignment(ASAN_SHADOW_GRANULARITY); |
440 | SetLowLevelAllocateCallback(OnLowLevelAllocate); |
441 | |
442 | InitializeAsanInterceptors(); |
443 | CheckASLR(); |
444 | |
445 | // Enable system log ("adb logcat") on Android. |
446 | // Doing this before interceptors are initialized crashes in: |
447 | // AsanInitInternal -> android_log_write -> __interceptor_strcmp |
448 | AndroidLogInit(); |
449 | |
450 | ReplaceSystemMalloc(); |
451 | |
452 | DisableCoreDumperIfNecessary(); |
453 | |
454 | InitializeShadowMemory(); |
455 | |
456 | AsanTSDInit(destructor: PlatformTSDDtor); |
457 | InstallDeadlySignalHandlers(handler: AsanOnDeadlySignal); |
458 | |
459 | AllocatorOptions allocator_options; |
460 | allocator_options.SetFrom(f: flags(), cf: common_flags()); |
461 | InitializeAllocator(options: allocator_options); |
462 | |
463 | if (SANITIZER_START_BACKGROUND_THREAD_IN_ASAN_INTERNAL) |
464 | MaybeStartBackgroudThread(); |
465 | |
466 | // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited |
467 | // should be set to 1 prior to initializing the threads. |
468 | replace_intrin_cached = flags()->replace_intrin; |
469 | SetAsanInited(); |
470 | |
471 | if (flags()->atexit) |
472 | Atexit(function: asan_atexit); |
473 | |
474 | InitializeCoverage(enabled: common_flags()->coverage, coverage_dir: common_flags()->coverage_dir); |
475 | |
476 | // Now that ASan runtime is (mostly) initialized, deactivate it if |
477 | // necessary, so that it can be re-activated when requested. |
478 | if (flags()->start_deactivated) |
479 | AsanDeactivate(); |
480 | |
481 | // interceptors |
482 | InitTlsSize(); |
483 | |
484 | // Create main thread. |
485 | AsanThread *main_thread = CreateMainThread(); |
486 | CHECK_EQ(0, main_thread->tid()); |
487 | force_interface_symbols(); // no-op. |
488 | SanitizerInitializeUnwinder(); |
489 | |
490 | if (CAN_SANITIZE_LEAKS) { |
491 | __lsan::InitCommonLsan(); |
492 | InstallAtExitCheckLeaks(); |
493 | } |
494 | |
495 | InstallAtForkHandler(); |
496 | |
497 | #if CAN_SANITIZE_UB |
498 | __ubsan::InitAsPlugin(); |
499 | #endif |
500 | |
501 | InitializeSuppressions(); |
502 | |
503 | if (CAN_SANITIZE_LEAKS) { |
504 | // LateInitialize() calls dlsym, which can allocate an error string buffer |
505 | // in the TLS. Let's ignore the allocation to avoid reporting a leak. |
506 | __lsan::ScopedInterceptorDisabler disabler; |
507 | Symbolizer::LateInitialize(); |
508 | } else { |
509 | Symbolizer::LateInitialize(); |
510 | } |
511 | |
512 | VReport(1, "AddressSanitizer Init done\n" ); |
513 | |
514 | WaitForDebugger(seconds: flags()->sleep_after_init, label: "after init" ); |
515 | |
516 | return true; |
517 | } |
518 | |
519 | // Initialize as requested from some part of ASan runtime library (interceptors, |
520 | // allocator, etc). |
521 | void AsanInitFromRtl() { |
522 | if (LIKELY(AsanInited())) |
523 | return; |
524 | SpinMutexLock lock(&asan_inited_mutex); |
525 | AsanInitInternal(); |
526 | } |
527 | |
528 | bool TryAsanInitFromRtl() { |
529 | if (LIKELY(AsanInited())) |
530 | return true; |
531 | if (!asan_inited_mutex.TryLock()) |
532 | return false; |
533 | bool result = AsanInitInternal(); |
534 | asan_inited_mutex.Unlock(); |
535 | return result; |
536 | } |
537 | |
538 | #if ASAN_DYNAMIC |
539 | // Initialize runtime in case it's LD_PRELOAD-ed into unsanitized executable |
540 | // (and thus normal initializers from .preinit_array or modules haven't run). |
541 | |
542 | class AsanInitializer { |
543 | public: |
544 | AsanInitializer() { |
545 | AsanInitFromRtl(); |
546 | } |
547 | }; |
548 | |
549 | static AsanInitializer asan_initializer; |
550 | #endif // ASAN_DYNAMIC |
551 | |
552 | void UnpoisonStack(uptr bottom, uptr top, const char *type) { |
553 | static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M |
554 | if (top - bottom > kMaxExpectedCleanupSize) { |
555 | static bool reported_warning = false; |
556 | if (reported_warning) |
557 | return; |
558 | reported_warning = true; |
559 | Report( |
560 | format: "WARNING: ASan is ignoring requested __asan_handle_no_return: " |
561 | "stack type: %s top: %p; bottom %p; size: %p (%zd)\n" |
562 | "False positive error reports may follow\n" |
563 | "For details see " |
564 | "https://github.com/google/sanitizers/issues/189\n" , |
565 | type, (void *)top, (void *)bottom, (void *)(top - bottom), |
566 | top - bottom); |
567 | return; |
568 | } |
569 | PoisonShadow(addr: bottom, size: RoundUpTo(size: top - bottom, ASAN_SHADOW_GRANULARITY), value: 0); |
570 | } |
571 | |
572 | static void UnpoisonDefaultStack() { |
573 | uptr bottom, top; |
574 | |
575 | if (AsanThread *curr_thread = GetCurrentThread()) { |
576 | int local_stack; |
577 | const uptr page_size = GetPageSizeCached(); |
578 | top = curr_thread->stack_top(); |
579 | bottom = ((uptr)&local_stack - page_size) & ~(page_size - 1); |
580 | } else { |
581 | CHECK(!SANITIZER_FUCHSIA); |
582 | // If we haven't seen this thread, try asking the OS for stack bounds. |
583 | uptr tls_addr, tls_size, stack_size; |
584 | GetThreadStackAndTls(/*main=*/false, stk_addr: &bottom, stk_size: &stack_size, tls_addr: &tls_addr, |
585 | tls_size: &tls_size); |
586 | top = bottom + stack_size; |
587 | } |
588 | |
589 | UnpoisonStack(bottom, top, type: "default" ); |
590 | } |
591 | |
592 | static void UnpoisonFakeStack() { |
593 | AsanThread *curr_thread = GetCurrentThread(); |
594 | if (!curr_thread) |
595 | return; |
596 | FakeStack *stack = curr_thread->get_fake_stack(); |
597 | if (!stack) |
598 | return; |
599 | stack->HandleNoReturn(); |
600 | } |
601 | |
602 | } // namespace __asan |
603 | |
604 | // ---------------------- Interface ---------------- {{{1 |
605 | using namespace __asan; |
606 | |
607 | void NOINLINE __asan_handle_no_return() { |
608 | if (UNLIKELY(!AsanInited())) |
609 | return; |
610 | |
611 | if (!PlatformUnpoisonStacks()) |
612 | UnpoisonDefaultStack(); |
613 | |
614 | UnpoisonFakeStack(); |
615 | } |
616 | |
617 | extern "C" void *() { |
618 | AsanThread *t = GetCurrentThread(); |
619 | CHECK(t); |
620 | return t->extra_spill_area(); |
621 | } |
622 | |
623 | void __asan_handle_vfork(void *sp) { |
624 | AsanThread *t = GetCurrentThread(); |
625 | CHECK(t); |
626 | uptr bottom = t->stack_bottom(); |
627 | PoisonShadow(addr: bottom, size: (uptr)sp - bottom, value: 0); |
628 | } |
629 | |
630 | void NOINLINE __asan_set_death_callback(void (*callback)(void)) { |
631 | SetUserDieCallback(callback); |
632 | } |
633 | |
634 | // Initialize as requested from instrumented application code. |
635 | // We use this call as a trigger to wake up ASan from deactivated state. |
636 | void __asan_init() { |
637 | AsanActivate(); |
638 | AsanInitFromRtl(); |
639 | } |
640 | |
641 | void __asan_version_mismatch_check() { |
642 | // Do nothing. |
643 | } |
644 | |