]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/hwasan/hwasan.cpp
MFC r355070:
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / hwasan / hwasan.cpp
1 //===-- hwasan.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 HWAddressSanitizer.
10 //
11 // HWAddressSanitizer runtime.
12 //===----------------------------------------------------------------------===//
13
14 #include "hwasan.h"
15 #include "hwasan_checks.h"
16 #include "hwasan_dynamic_shadow.h"
17 #include "hwasan_poisoning.h"
18 #include "hwasan_report.h"
19 #include "hwasan_thread.h"
20 #include "hwasan_thread_list.h"
21 #include "sanitizer_common/sanitizer_atomic.h"
22 #include "sanitizer_common/sanitizer_common.h"
23 #include "sanitizer_common/sanitizer_flag_parser.h"
24 #include "sanitizer_common/sanitizer_flags.h"
25 #include "sanitizer_common/sanitizer_libc.h"
26 #include "sanitizer_common/sanitizer_procmaps.h"
27 #include "sanitizer_common/sanitizer_stackdepot.h"
28 #include "sanitizer_common/sanitizer_stacktrace.h"
29 #include "sanitizer_common/sanitizer_symbolizer.h"
30 #include "ubsan/ubsan_flags.h"
31 #include "ubsan/ubsan_init.h"
32
33 // ACHTUNG! No system header includes in this file.
34
35 using namespace __sanitizer;
36
37 namespace __hwasan {
38
39 void EnterSymbolizer() {
40   Thread *t = GetCurrentThread();
41   CHECK(t);
42   t->EnterSymbolizer();
43 }
44 void ExitSymbolizer() {
45   Thread *t = GetCurrentThread();
46   CHECK(t);
47   t->LeaveSymbolizer();
48 }
49 bool IsInSymbolizer() {
50   Thread *t = GetCurrentThread();
51   return t && t->InSymbolizer();
52 }
53
54 static Flags hwasan_flags;
55
56 Flags *flags() {
57   return &hwasan_flags;
58 }
59
60 int hwasan_inited = 0;
61 int hwasan_instrumentation_inited = 0;
62 bool hwasan_init_is_running;
63
64 int hwasan_report_count = 0;
65
66 void Flags::SetDefaults() {
67 #define HWASAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
68 #include "hwasan_flags.inc"
69 #undef HWASAN_FLAG
70 }
71
72 static void RegisterHwasanFlags(FlagParser *parser, Flags *f) {
73 #define HWASAN_FLAG(Type, Name, DefaultValue, Description) \
74   RegisterFlag(parser, #Name, Description, &f->Name);
75 #include "hwasan_flags.inc"
76 #undef HWASAN_FLAG
77 }
78
79 static void InitializeFlags() {
80   SetCommonFlagsDefaults();
81   {
82     CommonFlags cf;
83     cf.CopyFrom(*common_flags());
84     cf.external_symbolizer_path = GetEnv("HWASAN_SYMBOLIZER_PATH");
85     cf.malloc_context_size = 20;
86     cf.handle_ioctl = true;
87     // FIXME: test and enable.
88     cf.check_printf = false;
89     cf.intercept_tls_get_addr = true;
90     cf.exitcode = 99;
91     // 8 shadow pages ~512kB, small enough to cover common stack sizes.
92     cf.clear_shadow_mmap_threshold = 4096 * (SANITIZER_ANDROID ? 2 : 8);
93     // Sigtrap is used in error reporting.
94     cf.handle_sigtrap = kHandleSignalExclusive;
95
96 #if SANITIZER_ANDROID
97     // Let platform handle other signals. It is better at reporting them then we
98     // are.
99     cf.handle_segv = kHandleSignalNo;
100     cf.handle_sigbus = kHandleSignalNo;
101     cf.handle_abort = kHandleSignalNo;
102     cf.handle_sigill = kHandleSignalNo;
103     cf.handle_sigfpe = kHandleSignalNo;
104 #endif
105     OverrideCommonFlags(cf);
106   }
107
108   Flags *f = flags();
109   f->SetDefaults();
110
111   FlagParser parser;
112   RegisterHwasanFlags(&parser, f);
113   RegisterCommonFlags(&parser);
114
115 #if HWASAN_CONTAINS_UBSAN
116   __ubsan::Flags *uf = __ubsan::flags();
117   uf->SetDefaults();
118
119   FlagParser ubsan_parser;
120   __ubsan::RegisterUbsanFlags(&ubsan_parser, uf);
121   RegisterCommonFlags(&ubsan_parser);
122 #endif
123
124   // Override from user-specified string.
125   if (__hwasan_default_options)
126     parser.ParseString(__hwasan_default_options());
127 #if HWASAN_CONTAINS_UBSAN
128   const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
129   ubsan_parser.ParseString(ubsan_default_options);
130 #endif
131
132   parser.ParseStringFromEnv("HWASAN_OPTIONS");
133 #if HWASAN_CONTAINS_UBSAN
134   ubsan_parser.ParseStringFromEnv("UBSAN_OPTIONS");
135 #endif
136
137   InitializeCommonFlags();
138
139   if (Verbosity()) ReportUnrecognizedFlags();
140
141   if (common_flags()->help) parser.PrintFlagDescriptions();
142 }
143
144 static void HWAsanCheckFailed(const char *file, int line, const char *cond,
145                               u64 v1, u64 v2) {
146   Report("HWAddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
147          line, cond, (uptr)v1, (uptr)v2);
148   PRINT_CURRENT_STACK_CHECK();
149   Die();
150 }
151
152 static constexpr uptr kMemoryUsageBufferSize = 4096;
153
154 static void HwasanFormatMemoryUsage(InternalScopedString &s) {
155   HwasanThreadList &thread_list = hwasanThreadList();
156   auto thread_stats = thread_list.GetThreadStats();
157   auto *sds = StackDepotGetStats();
158   AllocatorStatCounters asc;
159   GetAllocatorStats(asc);
160   s.append(
161       "HWASAN pid: %d rss: %zd threads: %zd stacks: %zd"
162       " thr_aux: %zd stack_depot: %zd uniq_stacks: %zd"
163       " heap: %zd",
164       internal_getpid(), GetRSS(), thread_stats.n_live_threads,
165       thread_stats.total_stack_size,
166       thread_stats.n_live_threads * thread_list.MemoryUsedPerThread(),
167       sds->allocated, sds->n_uniq_ids, asc[AllocatorStatMapped]);
168 }
169
170 #if SANITIZER_ANDROID
171 static char *memory_usage_buffer = nullptr;
172
173 static void InitMemoryUsage() {
174   memory_usage_buffer =
175       (char *)MmapOrDie(kMemoryUsageBufferSize, "memory usage string");
176   CHECK(memory_usage_buffer);
177   memory_usage_buffer[0] = '\0';
178   DecorateMapping((uptr)memory_usage_buffer, kMemoryUsageBufferSize,
179                   memory_usage_buffer);
180 }
181
182 void UpdateMemoryUsage() {
183   if (!flags()->export_memory_stats)
184     return;
185   if (!memory_usage_buffer)
186     InitMemoryUsage();
187   InternalScopedString s(kMemoryUsageBufferSize);
188   HwasanFormatMemoryUsage(s);
189   internal_strncpy(memory_usage_buffer, s.data(), kMemoryUsageBufferSize - 1);
190   memory_usage_buffer[kMemoryUsageBufferSize - 1] = '\0';
191 }
192 #else
193 void UpdateMemoryUsage() {}
194 #endif
195
196 // Prepare to run instrumented code on the main thread.
197 void InitInstrumentation() {
198   if (hwasan_instrumentation_inited) return;
199
200   if (!InitShadow()) {
201     Printf("FATAL: HWAddressSanitizer cannot mmap the shadow memory.\n");
202     DumpProcessMap();
203     Die();
204   }
205
206   InitThreads();
207   hwasanThreadList().CreateCurrentThread();
208
209   hwasan_instrumentation_inited = 1;
210 }
211
212 } // namespace __hwasan
213
214 void __sanitizer::BufferedStackTrace::UnwindImpl(
215     uptr pc, uptr bp, void *context, bool request_fast, u32 max_depth) {
216   using namespace __hwasan;
217   Thread *t = GetCurrentThread();
218   if (!t) {
219     // the thread is still being created.
220     size = 0;
221     return;
222   }
223   if (!StackTrace::WillUseFastUnwind(request_fast)) {
224     // Block reports from our interceptors during _Unwind_Backtrace.
225     SymbolizerScope sym_scope;
226     return Unwind(max_depth, pc, bp, context, 0, 0, request_fast);
227   }
228   if (StackTrace::WillUseFastUnwind(request_fast))
229     Unwind(max_depth, pc, bp, nullptr, t->stack_top(), t->stack_bottom(), true);
230   else
231     Unwind(max_depth, pc, 0, context, 0, 0, false);
232 }
233
234 // Interface.
235
236 using namespace __hwasan;
237
238 uptr __hwasan_shadow_memory_dynamic_address;  // Global interface symbol.
239
240 // This function was used by the old frame descriptor mechanism. We keep it
241 // around to avoid breaking ABI.
242 void __hwasan_init_frames(uptr beg, uptr end) {}
243
244 void __hwasan_init_static() {
245   InitShadowGOT();
246   InitInstrumentation();
247 }
248
249 void __hwasan_init() {
250   CHECK(!hwasan_init_is_running);
251   if (hwasan_inited) return;
252   hwasan_init_is_running = 1;
253   SanitizerToolName = "HWAddressSanitizer";
254
255   InitTlsSize();
256
257   CacheBinaryName();
258   InitializeFlags();
259
260   // Install tool-specific callbacks in sanitizer_common.
261   SetCheckFailedCallback(HWAsanCheckFailed);
262
263   __sanitizer_set_report_path(common_flags()->log_path);
264
265   AndroidTestTlsSlot();
266
267   DisableCoreDumperIfNecessary();
268
269   InitInstrumentation();
270
271   // Needs to be called here because flags()->random_tags might not have been
272   // initialized when InitInstrumentation() was called.
273   GetCurrentThread()->InitRandomState();
274
275   MadviseShadow();
276
277   SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
278   // This may call libc -> needs initialized shadow.
279   AndroidLogInit();
280
281   InitializeInterceptors();
282   InstallDeadlySignalHandlers(HwasanOnDeadlySignal);
283   InstallAtExitHandler(); // Needs __cxa_atexit interceptor.
284
285   Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer);
286
287   InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
288
289   HwasanTSDInit();
290   HwasanTSDThreadInit();
291
292   HwasanAllocatorInit();
293
294 #if HWASAN_CONTAINS_UBSAN
295   __ubsan::InitAsPlugin();
296 #endif
297
298   VPrintf(1, "HWAddressSanitizer init done\n");
299
300   hwasan_init_is_running = 0;
301   hwasan_inited = 1;
302 }
303
304 void __hwasan_print_shadow(const void *p, uptr sz) {
305   uptr ptr_raw = UntagAddr(reinterpret_cast<uptr>(p));
306   uptr shadow_first = MemToShadow(ptr_raw);
307   uptr shadow_last = MemToShadow(ptr_raw + sz - 1);
308   Printf("HWASan shadow map for %zx .. %zx (pointer tag %x)\n", ptr_raw,
309          ptr_raw + sz, GetTagFromPointer((uptr)p));
310   for (uptr s = shadow_first; s <= shadow_last; ++s)
311     Printf("  %zx: %x\n", ShadowToMem(s), *(tag_t *)s);
312 }
313
314 sptr __hwasan_test_shadow(const void *p, uptr sz) {
315   if (sz == 0)
316     return -1;
317   tag_t ptr_tag = GetTagFromPointer((uptr)p);
318   uptr ptr_raw = UntagAddr(reinterpret_cast<uptr>(p));
319   uptr shadow_first = MemToShadow(ptr_raw);
320   uptr shadow_last = MemToShadow(ptr_raw + sz - 1);
321   for (uptr s = shadow_first; s <= shadow_last; ++s)
322     if (*(tag_t *)s != ptr_tag) {
323       sptr offset = ShadowToMem(s) - ptr_raw;
324       return offset < 0 ? 0 : offset;
325     }
326   return -1;
327 }
328
329 u16 __sanitizer_unaligned_load16(const uu16 *p) {
330   return *p;
331 }
332 u32 __sanitizer_unaligned_load32(const uu32 *p) {
333   return *p;
334 }
335 u64 __sanitizer_unaligned_load64(const uu64 *p) {
336   return *p;
337 }
338 void __sanitizer_unaligned_store16(uu16 *p, u16 x) {
339   *p = x;
340 }
341 void __sanitizer_unaligned_store32(uu32 *p, u32 x) {
342   *p = x;
343 }
344 void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
345   *p = x;
346 }
347
348 void __hwasan_loadN(uptr p, uptr sz) {
349   CheckAddressSized<ErrorAction::Abort, AccessType::Load>(p, sz);
350 }
351 void __hwasan_load1(uptr p) {
352   CheckAddress<ErrorAction::Abort, AccessType::Load, 0>(p);
353 }
354 void __hwasan_load2(uptr p) {
355   CheckAddress<ErrorAction::Abort, AccessType::Load, 1>(p);
356 }
357 void __hwasan_load4(uptr p) {
358   CheckAddress<ErrorAction::Abort, AccessType::Load, 2>(p);
359 }
360 void __hwasan_load8(uptr p) {
361   CheckAddress<ErrorAction::Abort, AccessType::Load, 3>(p);
362 }
363 void __hwasan_load16(uptr p) {
364   CheckAddress<ErrorAction::Abort, AccessType::Load, 4>(p);
365 }
366
367 void __hwasan_loadN_noabort(uptr p, uptr sz) {
368   CheckAddressSized<ErrorAction::Recover, AccessType::Load>(p, sz);
369 }
370 void __hwasan_load1_noabort(uptr p) {
371   CheckAddress<ErrorAction::Recover, AccessType::Load, 0>(p);
372 }
373 void __hwasan_load2_noabort(uptr p) {
374   CheckAddress<ErrorAction::Recover, AccessType::Load, 1>(p);
375 }
376 void __hwasan_load4_noabort(uptr p) {
377   CheckAddress<ErrorAction::Recover, AccessType::Load, 2>(p);
378 }
379 void __hwasan_load8_noabort(uptr p) {
380   CheckAddress<ErrorAction::Recover, AccessType::Load, 3>(p);
381 }
382 void __hwasan_load16_noabort(uptr p) {
383   CheckAddress<ErrorAction::Recover, AccessType::Load, 4>(p);
384 }
385
386 void __hwasan_storeN(uptr p, uptr sz) {
387   CheckAddressSized<ErrorAction::Abort, AccessType::Store>(p, sz);
388 }
389 void __hwasan_store1(uptr p) {
390   CheckAddress<ErrorAction::Abort, AccessType::Store, 0>(p);
391 }
392 void __hwasan_store2(uptr p) {
393   CheckAddress<ErrorAction::Abort, AccessType::Store, 1>(p);
394 }
395 void __hwasan_store4(uptr p) {
396   CheckAddress<ErrorAction::Abort, AccessType::Store, 2>(p);
397 }
398 void __hwasan_store8(uptr p) {
399   CheckAddress<ErrorAction::Abort, AccessType::Store, 3>(p);
400 }
401 void __hwasan_store16(uptr p) {
402   CheckAddress<ErrorAction::Abort, AccessType::Store, 4>(p);
403 }
404
405 void __hwasan_storeN_noabort(uptr p, uptr sz) {
406   CheckAddressSized<ErrorAction::Recover, AccessType::Store>(p, sz);
407 }
408 void __hwasan_store1_noabort(uptr p) {
409   CheckAddress<ErrorAction::Recover, AccessType::Store, 0>(p);
410 }
411 void __hwasan_store2_noabort(uptr p) {
412   CheckAddress<ErrorAction::Recover, AccessType::Store, 1>(p);
413 }
414 void __hwasan_store4_noabort(uptr p) {
415   CheckAddress<ErrorAction::Recover, AccessType::Store, 2>(p);
416 }
417 void __hwasan_store8_noabort(uptr p) {
418   CheckAddress<ErrorAction::Recover, AccessType::Store, 3>(p);
419 }
420 void __hwasan_store16_noabort(uptr p) {
421   CheckAddress<ErrorAction::Recover, AccessType::Store, 4>(p);
422 }
423
424 void __hwasan_tag_memory(uptr p, u8 tag, uptr sz) {
425   TagMemoryAligned(p, sz, tag);
426 }
427
428 uptr __hwasan_tag_pointer(uptr p, u8 tag) {
429   return AddTagToPointer(p, tag);
430 }
431
432 void __hwasan_handle_longjmp(const void *sp_dst) {
433   uptr dst = (uptr)sp_dst;
434   // HWASan does not support tagged SP.
435   CHECK(GetTagFromPointer(dst) == 0);
436
437   uptr sp = (uptr)__builtin_frame_address(0);
438   static const uptr kMaxExpectedCleanupSize = 64 << 20;  // 64M
439   if (dst < sp || dst - sp > kMaxExpectedCleanupSize) {
440     Report(
441         "WARNING: HWASan is ignoring requested __hwasan_handle_longjmp: "
442         "stack top: %p; target %p; distance: %p (%zd)\n"
443         "False positive error reports may follow\n",
444         (void *)sp, (void *)dst, dst - sp);
445     return;
446   }
447   TagMemory(sp, dst - sp, 0);
448 }
449
450 void __hwasan_handle_vfork(const void *sp_dst) {
451   uptr sp = (uptr)sp_dst;
452   Thread *t = GetCurrentThread();
453   CHECK(t);
454   uptr top = t->stack_top();
455   uptr bottom = t->stack_bottom();
456   if (top == 0 || bottom == 0 || sp < bottom || sp >= top) {
457     Report(
458         "WARNING: HWASan is ignoring requested __hwasan_handle_vfork: "
459         "stack top: %zx; current %zx; bottom: %zx \n"
460         "False positive error reports may follow\n",
461         top, sp, bottom);
462     return;
463   }
464   TagMemory(bottom, sp - bottom, 0);
465 }
466
467 extern "C" void *__hwasan_extra_spill_area() {
468   Thread *t = GetCurrentThread();
469   return &t->vfork_spill();
470 }
471
472 void __hwasan_print_memory_usage() {
473   InternalScopedString s(kMemoryUsageBufferSize);
474   HwasanFormatMemoryUsage(s);
475   Printf("%s\n", s.data());
476 }
477
478 static const u8 kFallbackTag = 0xBB;
479
480 u8 __hwasan_generate_tag() {
481   Thread *t = GetCurrentThread();
482   if (!t) return kFallbackTag;
483   return t->GenerateRandomTag();
484 }
485
486 #if !SANITIZER_SUPPORTS_WEAK_HOOKS
487 extern "C" {
488 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
489 const char* __hwasan_default_options() { return ""; }
490 }  // extern "C"
491 #endif
492
493 extern "C" {
494 SANITIZER_INTERFACE_ATTRIBUTE
495 void __sanitizer_print_stack_trace() {
496   GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME());
497   stack.Print();
498 }
499 } // extern "C"