diff options
Diffstat (limited to 'lib/hwasan/hwasan.cpp')
-rw-r--r-- | lib/hwasan/hwasan.cpp | 155 |
1 files changed, 136 insertions, 19 deletions
diff --git a/lib/hwasan/hwasan.cpp b/lib/hwasan/hwasan.cpp index 6f2246552164..7b5c6c694be9 100644 --- a/lib/hwasan/hwasan.cpp +++ b/lib/hwasan/hwasan.cpp @@ -193,27 +193,12 @@ void UpdateMemoryUsage() { void UpdateMemoryUsage() {} #endif -// Prepare to run instrumented code on the main thread. -void InitInstrumentation() { - if (hwasan_instrumentation_inited) return; - - if (!InitShadow()) { - Printf("FATAL: HWAddressSanitizer cannot mmap the shadow memory.\n"); - DumpProcessMap(); - Die(); - } - - InitThreads(); - hwasanThreadList().CreateCurrentThread(); - - hwasan_instrumentation_inited = 1; -} - } // namespace __hwasan +using namespace __hwasan; + void __sanitizer::BufferedStackTrace::UnwindImpl( uptr pc, uptr bp, void *context, bool request_fast, u32 max_depth) { - using namespace __hwasan; Thread *t = GetCurrentThread(); if (!t) { // the thread is still being created. @@ -231,9 +216,117 @@ void __sanitizer::BufferedStackTrace::UnwindImpl( Unwind(max_depth, pc, 0, context, 0, 0, false); } -// Interface. +struct hwasan_global { + s32 gv_relptr; + u32 info; +}; + +static void InitGlobals(const hwasan_global *begin, const hwasan_global *end) { + for (auto *desc = begin; desc != end; ++desc) { + uptr gv = reinterpret_cast<uptr>(desc) + desc->gv_relptr; + uptr size = desc->info & 0xffffff; + uptr full_granule_size = RoundDownTo(size, 16); + u8 tag = desc->info >> 24; + TagMemoryAligned(gv, full_granule_size, tag); + if (size % 16) + TagMemoryAligned(gv + full_granule_size, 16, size % 16); + } +} -using namespace __hwasan; +enum { NT_LLVM_HWASAN_GLOBALS = 3 }; + +struct hwasan_global_note { + s32 begin_relptr; + s32 end_relptr; +}; + +// Check that the given library meets the code model requirements for tagged +// globals. These properties are not checked at link time so they need to be +// checked at runtime. +static void CheckCodeModel(ElfW(Addr) base, const ElfW(Phdr) * phdr, + ElfW(Half) phnum) { + ElfW(Addr) min_addr = -1ull, max_addr = 0; + for (unsigned i = 0; i != phnum; ++i) { + if (phdr[i].p_type != PT_LOAD) + continue; + ElfW(Addr) lo = base + phdr[i].p_vaddr, hi = lo + phdr[i].p_memsz; + if (min_addr > lo) + min_addr = lo; + if (max_addr < hi) + max_addr = hi; + } + + if (max_addr - min_addr > 1ull << 32) { + Report("FATAL: HWAddressSanitizer: library size exceeds 2^32\n"); + Die(); + } + if (max_addr > 1ull << 48) { + Report("FATAL: HWAddressSanitizer: library loaded above address 2^48\n"); + Die(); + } +} + +static void InitGlobalsFromPhdrs(ElfW(Addr) base, const ElfW(Phdr) * phdr, + ElfW(Half) phnum) { + for (unsigned i = 0; i != phnum; ++i) { + if (phdr[i].p_type != PT_NOTE) + continue; + const char *note = reinterpret_cast<const char *>(base + phdr[i].p_vaddr); + const char *nend = note + phdr[i].p_memsz; + while (note < nend) { + auto *nhdr = reinterpret_cast<const ElfW(Nhdr) *>(note); + const char *name = note + sizeof(ElfW(Nhdr)); + const char *desc = name + RoundUpTo(nhdr->n_namesz, 4); + if (nhdr->n_type != NT_LLVM_HWASAN_GLOBALS || + internal_strcmp(name, "LLVM") != 0) { + note = desc + RoundUpTo(nhdr->n_descsz, 4); + continue; + } + + // Only libraries with instrumented globals need to be checked against the + // code model since they use relocations that aren't checked at link time. + CheckCodeModel(base, phdr, phnum); + + auto *global_note = reinterpret_cast<const hwasan_global_note *>(desc); + auto *global_begin = reinterpret_cast<const hwasan_global *>( + note + global_note->begin_relptr); + auto *global_end = reinterpret_cast<const hwasan_global *>( + note + global_note->end_relptr); + InitGlobals(global_begin, global_end); + return; + } + } +} + +static void InitLoadedGlobals() { + dl_iterate_phdr( + [](dl_phdr_info *info, size_t size, void *data) { + InitGlobalsFromPhdrs(info->dlpi_addr, info->dlpi_phdr, + info->dlpi_phnum); + return 0; + }, + nullptr); +} + +// Prepare to run instrumented code on the main thread. +static void InitInstrumentation() { + if (hwasan_instrumentation_inited) return; + + InitPrctl(); + + if (!InitShadow()) { + Printf("FATAL: HWAddressSanitizer cannot mmap the shadow memory.\n"); + DumpProcessMap(); + Die(); + } + + InitThreads(); + hwasanThreadList().CreateCurrentThread(); + + hwasan_instrumentation_inited = 1; +} + +// Interface. uptr __hwasan_shadow_memory_dynamic_address; // Global interface symbol. @@ -244,6 +337,17 @@ void __hwasan_init_frames(uptr beg, uptr end) {} void __hwasan_init_static() { InitShadowGOT(); InitInstrumentation(); + + // In the non-static code path we call dl_iterate_phdr here. But at this point + // libc might not have been initialized enough for dl_iterate_phdr to work. + // Fortunately, since this is a statically linked executable we can use the + // linker-defined symbol __ehdr_start to find the only relevant set of phdrs. + extern ElfW(Ehdr) __ehdr_start; + InitGlobalsFromPhdrs( + 0, + reinterpret_cast<const ElfW(Phdr) *>( + reinterpret_cast<const char *>(&__ehdr_start) + __ehdr_start.e_phoff), + __ehdr_start.e_phnum); } void __hwasan_init() { @@ -267,6 +371,7 @@ void __hwasan_init() { DisableCoreDumperIfNecessary(); InitInstrumentation(); + InitLoadedGlobals(); // Needs to be called here because flags()->random_tags might not have been // initialized when InitInstrumentation() was called. @@ -301,6 +406,18 @@ void __hwasan_init() { hwasan_inited = 1; } +void __hwasan_library_loaded(ElfW(Addr) base, const ElfW(Phdr) * phdr, + ElfW(Half) phnum) { + InitGlobalsFromPhdrs(base, phdr, phnum); +} + +void __hwasan_library_unloaded(ElfW(Addr) base, const ElfW(Phdr) * phdr, + ElfW(Half) phnum) { + for (; phnum != 0; ++phdr, --phnum) + if (phdr->p_type == PT_LOAD) + TagMemory(base + phdr->p_vaddr, phdr->p_memsz, 0); +} + void __hwasan_print_shadow(const void *p, uptr sz) { uptr ptr_raw = UntagAddr(reinterpret_cast<uptr>(p)); uptr shadow_first = MemToShadow(ptr_raw); |