Index: include/sanitizer/hwasan_interface.h =================================================================== --- include/sanitizer/hwasan_interface.h +++ include/sanitizer/hwasan_interface.h @@ -18,11 +18,15 @@ #ifdef __cplusplus extern "C" { #endif - // Initialize shadow but not the rest of the runtime. + // Libc hook for program startup in statically linked executables. + // Initializes enough of the runtime to run instrumented code. This function + // should only be called in statically linked executables because it modifies + // the GOT, which won't work in regular binaries because RELRO will already + // have been applied by the time the function is called. This also means that + // the function should be called before libc applies RELRO. // Does not call libc unless there is an error. - // Can be called multiple times, or not at all (in which case shadow will - // be initialized in compiler-inserted __hwasan_init() call). - void __hwasan_shadow_init(void); + // Can be called multiple times. + void __hwasan_init_static(void); // This function may be optionally provided by user and should return // a string containing HWASan runtime options. See asan_flags.h for details. Index: lib/hwasan/hwasan.h =================================================================== --- lib/hwasan/hwasan.h +++ lib/hwasan/hwasan.h @@ -70,6 +70,7 @@ bool ProtectRange(uptr beg, uptr end); bool InitShadow(); void InitThreads(); +void InitInstrumentation(); void MadviseShadow(); char *GetProcSelfMaps(); void InitializeInterceptors(); Index: lib/hwasan/hwasan.cc =================================================================== --- lib/hwasan/hwasan.cc +++ lib/hwasan/hwasan.cc @@ -13,6 +13,7 @@ #include "hwasan.h" #include "hwasan_checks.h" +#include "hwasan_dynamic_shadow.h" #include "hwasan_poisoning.h" #include "hwasan_report.h" #include "hwasan_thread.h" @@ -57,7 +58,7 @@ } int hwasan_inited = 0; -int hwasan_shadow_inited = 0; +int hwasan_instrumentation_inited = 0; bool hwasan_init_is_running; int hwasan_report_count = 0; @@ -246,28 +247,39 @@ return nullptr; } -} // namespace __hwasan - -// Interface. - -using namespace __hwasan; - -uptr __hwasan_shadow_memory_dynamic_address; // Global interface symbol. +// Prepare to run instrumented code on the main thread. +void InitInstrumentation() { + if (hwasan_instrumentation_inited) return; -void __hwasan_shadow_init() { - if (hwasan_shadow_inited) return; if (!InitShadow()) { Printf("FATAL: HWAddressSanitizer cannot mmap the shadow memory.\n"); DumpProcessMap(); Die(); } - hwasan_shadow_inited = 1; + + InitThreads(); + hwasanThreadList().CreateCurrentThread(); + + hwasan_instrumentation_inited = 1; } +} // namespace __hwasan + +// Interface. + +using namespace __hwasan; + +uptr __hwasan_shadow_memory_dynamic_address; // Global interface symbol. + void __hwasan_init_frames(uptr beg, uptr end) { InitFrameDescriptors(beg, end); } +void __hwasan_init_static() { + InitShadowGOT(); + InitInstrumentation(); +} + void __hwasan_init() { CHECK(!hwasan_init_is_running); if (hwasan_inited) return; @@ -288,10 +300,11 @@ DisableCoreDumperIfNecessary(); - __hwasan_shadow_init(); + InitInstrumentation(); - InitThreads(); - hwasanThreadList().CreateCurrentThread(); + // Needs to be called here because flags()->random_tags might not have been + // initialized when InitInstrumentation() was called. + GetCurrentThread()->InitRandomState(); MadviseShadow(); Index: lib/hwasan/hwasan_dynamic_shadow.h =================================================================== --- lib/hwasan/hwasan_dynamic_shadow.h +++ lib/hwasan/hwasan_dynamic_shadow.h @@ -20,6 +20,7 @@ namespace __hwasan { uptr FindDynamicShadowStart(uptr shadow_size_bytes); +void InitShadowGOT(); } // namespace __hwasan Index: lib/hwasan/hwasan_dynamic_shadow.cc =================================================================== --- lib/hwasan/hwasan_dynamic_shadow.cc +++ lib/hwasan/hwasan_dynamic_shadow.cc @@ -18,6 +18,9 @@ #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_posix.h" +#include +#include + // The code in this file needs to run in an unrelocated binary. It should not // access any external symbol, including its own non-hidden globals. @@ -118,10 +121,28 @@ INTERFACE_ATTRIBUTE __attribute__((ifunc("__hwasan_premap_shadow"))) void __hwasan_shadow(); +extern __attribute((visibility("hidden"))) ElfW(Rela) __rela_iplt_start[], + __rela_iplt_end[]; + } // extern "C" namespace __hwasan { +void InitShadowGOT() { + // Call the ifunc resolver for __hwasan_shadow and fill in its GOT entry. This + // needs to be done before other ifunc resolvers (which are handled by libc) + // because a resolver might read __hwasan_shadow. + typedef ElfW(Addr) (*ifunc_resolver_t)(void); + for (ElfW(Rela) *r = __rela_iplt_start; r != __rela_iplt_end; ++r) { + ElfW(Addr)* offset = reinterpret_cast(r->r_offset); + ElfW(Addr) resolver = r->r_addend; + if (resolver == reinterpret_cast(&__hwasan_premap_shadow)) { + *offset = reinterpret_cast(resolver)(); + break; + } + } +} + uptr FindDynamicShadowStart(uptr shadow_size_bytes) { if (IsPremapShadowAvailable()) return FindPremappedShadowStart(shadow_size_bytes); @@ -132,10 +153,12 @@ #else namespace __hwasan { +void InitShadowGOT() {} + uptr FindDynamicShadowStart(uptr shadow_size_bytes) { return MapDynamicShadow(shadow_size_bytes); } } // namespace __hwasan -# + #endif // SANITIZER_ANDROID Index: lib/hwasan/hwasan_interface_internal.h =================================================================== --- lib/hwasan/hwasan_interface_internal.h +++ lib/hwasan/hwasan_interface_internal.h @@ -20,7 +20,7 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE -void __hwasan_shadow_init(); +void __hwasan_init_static(); SANITIZER_INTERFACE_ATTRIBUTE void __hwasan_init(); Index: lib/hwasan/hwasan_linux.cc =================================================================== --- lib/hwasan/hwasan_linux.cc +++ lib/hwasan/hwasan_linux.cc @@ -236,7 +236,7 @@ // ---------------------- TSD ---------------- {{{1 extern "C" void __hwasan_thread_enter() { - hwasanThreadList().CreateCurrentThread(); + hwasanThreadList().CreateCurrentThread()->InitRandomState(); } extern "C" void __hwasan_thread_exit() { @@ -289,7 +289,9 @@ #if SANITIZER_ANDROID void AndroidTestTlsSlot() { uptr kMagicValue = 0x010203040A0B0C0D; - *(uptr *)get_android_tls_ptr() = kMagicValue; + uptr *tls_ptr = GetCurrentThreadLongPtr(); + uptr old_value = *tls_ptr; + *tls_ptr = kMagicValue; dlerror(); if (*(uptr *)get_android_tls_ptr() != kMagicValue) { Printf( @@ -297,6 +299,7 @@ "for dlerror().\n"); Die(); } + *tls_ptr = old_value; } #else void AndroidTestTlsSlot() {} Index: lib/hwasan/hwasan_thread.h =================================================================== --- lib/hwasan/hwasan_thread.h +++ lib/hwasan/hwasan_thread.h @@ -24,6 +24,7 @@ class Thread { public: void Init(uptr stack_buffer_start, uptr stack_buffer_size); // Must be called from the thread itself. + void InitRandomState(); void Destroy(); uptr stack_top() { return stack_top_; } Index: lib/hwasan/hwasan_thread.cc =================================================================== --- lib/hwasan/hwasan_thread.cc +++ lib/hwasan/hwasan_thread.cc @@ -25,10 +25,13 @@ return seed; } +void Thread::InitRandomState() { + random_state_ = flags()->random_tags ? RandomSeed() : unique_id_; +} + void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size) { static u64 unique_id; unique_id_ = unique_id++; - random_state_ = flags()->random_tags ? RandomSeed() : unique_id_; if (auto sz = flags()->heap_history_size) heap_allocations_ = HeapAllocationsRingBuffer::New(sz);