diff options
Diffstat (limited to 'libsanitizer/hwasan')
-rw-r--r-- | libsanitizer/hwasan/Makefile.am | 3 | ||||
-rw-r--r-- | libsanitizer/hwasan/Makefile.in | 12 | ||||
-rw-r--r-- | libsanitizer/hwasan/hwasan.cpp | 3 | ||||
-rw-r--r-- | libsanitizer/hwasan/hwasan.h | 25 | ||||
-rw-r--r-- | libsanitizer/hwasan/hwasan_allocation_functions.cpp | 24 | ||||
-rw-r--r-- | libsanitizer/hwasan/hwasan_allocator.cpp | 58 | ||||
-rw-r--r-- | libsanitizer/hwasan/hwasan_dynamic_shadow.cpp | 9 | ||||
-rw-r--r-- | libsanitizer/hwasan/hwasan_fuchsia.cpp | 23 | ||||
-rw-r--r-- | libsanitizer/hwasan/hwasan_interceptors.cpp | 70 | ||||
-rw-r--r-- | libsanitizer/hwasan/hwasan_interface_internal.h | 48 | ||||
-rw-r--r-- | libsanitizer/hwasan/hwasan_linux.cpp | 147 | ||||
-rw-r--r-- | libsanitizer/hwasan/hwasan_report.cpp | 82 | ||||
-rw-r--r-- | libsanitizer/hwasan/hwasan_setjmp_aarch64.S (renamed from libsanitizer/hwasan/hwasan_setjmp.S) | 21 | ||||
-rw-r--r-- | libsanitizer/hwasan/hwasan_setjmp_x86_64.S | 80 | ||||
-rw-r--r-- | libsanitizer/hwasan/hwasan_thread.cpp | 2 | ||||
-rw-r--r-- | libsanitizer/hwasan/hwasan_type_test.cpp | 2 |
16 files changed, 404 insertions, 205 deletions
diff --git a/libsanitizer/hwasan/Makefile.am b/libsanitizer/hwasan/Makefile.am index 5e3a0f1..cfc1bfe 100644 --- a/libsanitizer/hwasan/Makefile.am +++ b/libsanitizer/hwasan/Makefile.am @@ -28,7 +28,8 @@ hwasan_files = \ hwasan_new_delete.cpp \ hwasan_poisoning.cpp \ hwasan_report.cpp \ - hwasan_setjmp.S \ + hwasan_setjmp_aarch64.S \ + hwasan_setjmp_x86_64.S \ hwasan_tag_mismatch_aarch64.S \ hwasan_thread.cpp \ hwasan_thread_list.cpp \ diff --git a/libsanitizer/hwasan/Makefile.in b/libsanitizer/hwasan/Makefile.in index 22c5266..f63670b 100644 --- a/libsanitizer/hwasan/Makefile.in +++ b/libsanitizer/hwasan/Makefile.in @@ -151,9 +151,9 @@ am__objects_1 = hwasan_allocation_functions.lo hwasan_allocator.lo \ hwasan_fuchsia.lo hwasan_globals.lo hwasan_interceptors.lo \ hwasan_interceptors_vfork.lo hwasan_linux.lo \ hwasan_memintrinsics.lo hwasan_new_delete.lo \ - hwasan_poisoning.lo hwasan_report.lo hwasan_setjmp.lo \ - hwasan_tag_mismatch_aarch64.lo hwasan_thread.lo \ - hwasan_thread_list.lo hwasan_type_test.lo + hwasan_poisoning.lo hwasan_report.lo hwasan_setjmp_aarch64.lo \ + hwasan_setjmp_x86_64.lo hwasan_tag_mismatch_aarch64.lo \ + hwasan_thread.lo hwasan_thread_list.lo hwasan_type_test.lo am_libhwasan_la_OBJECTS = $(am__objects_1) libhwasan_la_OBJECTS = $(am_libhwasan_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) @@ -427,7 +427,8 @@ hwasan_files = \ hwasan_new_delete.cpp \ hwasan_poisoning.cpp \ hwasan_report.cpp \ - hwasan_setjmp.S \ + hwasan_setjmp_aarch64.S \ + hwasan_setjmp_x86_64.S \ hwasan_tag_mismatch_aarch64.S \ hwasan_thread.cpp \ hwasan_thread_list.cpp \ @@ -570,7 +571,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_new_delete.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_poisoning.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_report.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_setjmp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_setjmp_aarch64.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_setjmp_x86_64.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_tag_mismatch_aarch64.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_thread.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_thread_list.Plo@am__quote@ diff --git a/libsanitizer/hwasan/hwasan.cpp b/libsanitizer/hwasan/hwasan.cpp index cbe0dee..4654190 100644 --- a/libsanitizer/hwasan/hwasan.cpp +++ b/libsanitizer/hwasan/hwasan.cpp @@ -319,7 +319,7 @@ void __hwasan_init_static() { InitializeSingleGlobal(global); } -void __hwasan_init() { +__attribute__((constructor(0))) void __hwasan_init() { CHECK(!hwasan_init_is_running); if (hwasan_inited) return; hwasan_init_is_running = 1; @@ -360,6 +360,7 @@ void __hwasan_init() { HwasanTSDThreadInit(); HwasanAllocatorInit(); + HwasanInstallAtForkHandler(); #if HWASAN_CONTAINS_UBSAN __ubsan::InitAsPlugin(); diff --git a/libsanitizer/hwasan/hwasan.h b/libsanitizer/hwasan/hwasan.h index 7338b69..371c43f3 100644 --- a/libsanitizer/hwasan/hwasan.h +++ b/libsanitizer/hwasan/hwasan.h @@ -107,6 +107,8 @@ void InitThreads(); void InitializeInterceptors(); void HwasanAllocatorInit(); +void HwasanAllocatorLock(); +void HwasanAllocatorUnlock(); void *hwasan_malloc(uptr size, StackTrace *stack); void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack); @@ -140,6 +142,8 @@ void HwasanAtExit(); void HwasanOnDeadlySignal(int signo, void *info, void *context); +void HwasanInstallAtForkHandler(); + void UpdateMemoryUsage(); void AppendToErrorMessageBuffer(const char *buffer); @@ -183,25 +187,34 @@ void HwasanTagMismatch(uptr addr, uptr access_info, uptr *registers_frame, RunFreeHooks(ptr); \ } while (false) -#if HWASAN_WITH_INTERCEPTORS && defined(__aarch64__) +#if HWASAN_WITH_INTERCEPTORS // For both bionic and glibc __sigset_t is an unsigned long. typedef unsigned long __hw_sigset_t; // Setjmp and longjmp implementations are platform specific, and hence the -// interception code is platform specific too. As yet we've only implemented -// the interception for AArch64. -typedef unsigned long long __hw_register_buf[22]; +// interception code is platform specific too. +# if defined(__aarch64__) +constexpr size_t kHwRegisterBufSize = 22; +# elif defined(__x86_64__) +constexpr size_t kHwRegisterBufSize = 8; +# endif +typedef unsigned long long __hw_register_buf[kHwRegisterBufSize]; struct __hw_jmp_buf_struct { // NOTE: The machine-dependent definition of `__sigsetjmp' // assume that a `__hw_jmp_buf' begins with a `__hw_register_buf' and that // `__mask_was_saved' follows it. Do not move these members or add others // before it. + // + // We add a __magic field to our struct to catch cases where libc's setjmp + // populated the jmp_buf instead of our interceptor. __hw_register_buf __jmpbuf; // Calling environment. - int __mask_was_saved; // Saved the signal mask? + unsigned __mask_was_saved : 1; // Saved the signal mask? + unsigned __magic : 31; // Used to distinguish __hw_jmp_buf from jmp_buf. __hw_sigset_t __saved_mask; // Saved signal mask. }; typedef struct __hw_jmp_buf_struct __hw_jmp_buf[1]; typedef struct __hw_jmp_buf_struct __hw_sigjmp_buf[1]; -#endif // HWASAN_WITH_INTERCEPTORS && __aarch64__ +constexpr unsigned kHwJmpBufMagic = 0x248ACE77; +#endif // HWASAN_WITH_INTERCEPTORS #define ENSURE_HWASAN_INITED() \ do { \ diff --git a/libsanitizer/hwasan/hwasan_allocation_functions.cpp b/libsanitizer/hwasan/hwasan_allocation_functions.cpp index 6c2a607..850daed 100644 --- a/libsanitizer/hwasan/hwasan_allocation_functions.cpp +++ b/libsanitizer/hwasan/hwasan_allocation_functions.cpp @@ -17,6 +17,8 @@ #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" +#if !SANITIZER_FUCHSIA + using namespace __hwasan; static uptr allocated_for_dlsym; @@ -36,6 +38,9 @@ static void *AllocateFromLocalPool(uptr size_in_bytes) { return mem; } +extern "C" { + +SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_posix_memalign(void **memptr, uptr alignment, uptr size) { GET_MALLOC_STACK_TRACE; CHECK_NE(memptr, 0); @@ -43,16 +48,19 @@ int __sanitizer_posix_memalign(void **memptr, uptr alignment, uptr size) { return res; } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_memalign(uptr alignment, uptr size) { GET_MALLOC_STACK_TRACE; return hwasan_memalign(alignment, size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_aligned_alloc(uptr alignment, uptr size) { GET_MALLOC_STACK_TRACE; return hwasan_aligned_alloc(alignment, size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer___libc_memalign(uptr alignment, uptr size) { GET_MALLOC_STACK_TRACE; void *ptr = hwasan_memalign(alignment, size, &stack); @@ -61,16 +69,19 @@ void *__sanitizer___libc_memalign(uptr alignment, uptr size) { return ptr; } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_valloc(uptr size) { GET_MALLOC_STACK_TRACE; return hwasan_valloc(size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_pvalloc(uptr size) { GET_MALLOC_STACK_TRACE; return hwasan_pvalloc(size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_free(void *ptr) { GET_MALLOC_STACK_TRACE; if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) @@ -78,6 +89,7 @@ void __sanitizer_free(void *ptr) { hwasan_free(ptr, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cfree(void *ptr) { GET_MALLOC_STACK_TRACE; if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) @@ -85,22 +97,27 @@ void __sanitizer_cfree(void *ptr) { hwasan_free(ptr, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_malloc_usable_size(const void *ptr) { return __sanitizer_get_allocated_size(ptr); } +SANITIZER_INTERFACE_ATTRIBUTE struct __sanitizer_struct_mallinfo __sanitizer_mallinfo() { __sanitizer_struct_mallinfo sret; internal_memset(&sret, 0, sizeof(sret)); return sret; } +SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_mallopt(int cmd, int value) { return 0; } +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_malloc_stats(void) { // FIXME: implement, but don't call REAL(malloc_stats)! } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_calloc(uptr nmemb, uptr size) { GET_MALLOC_STACK_TRACE; if (UNLIKELY(!hwasan_inited)) @@ -109,6 +126,7 @@ void *__sanitizer_calloc(uptr nmemb, uptr size) { return hwasan_calloc(nmemb, size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_realloc(void *ptr, uptr size) { GET_MALLOC_STACK_TRACE; if (UNLIKELY(IsInDlsymAllocPool(ptr))) { @@ -127,11 +145,13 @@ void *__sanitizer_realloc(void *ptr, uptr size) { return hwasan_realloc(ptr, size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_reallocarray(void *ptr, uptr nmemb, uptr size) { GET_MALLOC_STACK_TRACE; return hwasan_reallocarray(ptr, nmemb, size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_malloc(uptr size) { GET_MALLOC_STACK_TRACE; if (UNLIKELY(!hwasan_init_is_running)) @@ -142,6 +162,8 @@ void *__sanitizer_malloc(uptr size) { return hwasan_malloc(size, &stack); } +} // extern "C" + #if HWASAN_WITH_INTERCEPTORS # define INTERCEPTOR_ALIAS(RET, FN, ARGS...) \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE RET WRAP(FN)(ARGS) \ @@ -170,3 +192,5 @@ INTERCEPTOR_ALIAS(int, mallopt, int cmd, int value); INTERCEPTOR_ALIAS(void, malloc_stats, void); # endif #endif // #if HWASAN_WITH_INTERCEPTORS + +#endif // SANITIZER_FUCHSIA diff --git a/libsanitizer/hwasan/hwasan_allocator.cpp b/libsanitizer/hwasan/hwasan_allocator.cpp index ef6d4d6..9e17299 100644 --- a/libsanitizer/hwasan/hwasan_allocator.cpp +++ b/libsanitizer/hwasan/hwasan_allocator.cpp @@ -107,6 +107,10 @@ void HwasanAllocatorInit() { tail_magic[i] = GetCurrentThread()->GenerateRandomTag(); } +void HwasanAllocatorLock() { allocator.ForceLock(); } + +void HwasanAllocatorUnlock() { allocator.ForceUnlock(); } + void AllocatorSwallowThreadLocalCache(AllocatorCache *cache) { allocator.SwallowCache(cache); } @@ -158,8 +162,11 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment, internal_memset(allocated, flags()->malloc_fill_byte, fill_size); } if (size != orig_size) { - internal_memcpy(reinterpret_cast<u8 *>(allocated) + orig_size, tail_magic, - size - orig_size - 1); + u8 *tail = reinterpret_cast<u8 *>(allocated) + orig_size; + uptr tail_length = size - orig_size; + internal_memcpy(tail, tail_magic, tail_length - 1); + // Short granule is excluded from magic tail, so we explicitly untag. + tail[tail_length - 1] = 0; } void *user_ptr = allocated; @@ -201,21 +208,37 @@ static bool PointerAndMemoryTagsMatch(void *tagged_ptr) { return PossiblyShortTagMatches(mem_tag, tagged_uptr, 1); } +static bool CheckInvalidFree(StackTrace *stack, void *untagged_ptr, + void *tagged_ptr) { + // This function can return true if halt_on_error is false. + if (!MemIsApp(reinterpret_cast<uptr>(untagged_ptr)) || + !PointerAndMemoryTagsMatch(tagged_ptr)) { + ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr)); + return true; + } + return false; +} + static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { CHECK(tagged_ptr); HWASAN_FREE_HOOK(tagged_ptr); - if (!PointerAndMemoryTagsMatch(tagged_ptr)) - ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr)); + bool in_taggable_region = + InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr)); + void *untagged_ptr = in_taggable_region ? UntagPtr(tagged_ptr) : tagged_ptr; + + if (CheckInvalidFree(stack, untagged_ptr, tagged_ptr)) + return; - void *untagged_ptr = InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr)) - ? UntagPtr(tagged_ptr) - : tagged_ptr; void *aligned_ptr = reinterpret_cast<void *>( RoundDownTo(reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment)); tag_t pointer_tag = GetTagFromPointer(reinterpret_cast<uptr>(tagged_ptr)); Metadata *meta = reinterpret_cast<Metadata *>(allocator.GetMetaData(aligned_ptr)); + if (!meta) { + ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr)); + return; + } uptr orig_size = meta->get_requested_size(); u32 free_context_id = StackDepotPut(*stack); u32 alloc_context_id = meta->alloc_context_id; @@ -228,7 +251,11 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { CHECK_LT(tail_size, kShadowAlignment); void *tail_beg = reinterpret_cast<void *>( reinterpret_cast<uptr>(aligned_ptr) + orig_size); - if (tail_size && internal_memcmp(tail_beg, tail_magic, tail_size)) + tag_t short_granule_memtag = *(reinterpret_cast<tag_t *>( + reinterpret_cast<uptr>(tail_beg) + tail_size)); + if (tail_size && + (internal_memcmp(tail_beg, tail_magic, tail_size) || + (in_taggable_region && pointer_tag != short_granule_memtag))) ReportTailOverwritten(stack, reinterpret_cast<uptr>(tagged_ptr), orig_size, tail_magic); } @@ -243,8 +270,7 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { Min(TaggedSize(orig_size), (uptr)flags()->max_free_fill_size); internal_memset(aligned_ptr, flags()->free_fill_byte, fill_size); } - if (InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr)) && - flags()->tag_in_free && malloc_bisect(stack, 0) && + if (in_taggable_region && flags()->tag_in_free && malloc_bisect(stack, 0) && atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) { // Always store full 8-bit tags on free to maximize UAF detection. tag_t tag; @@ -278,13 +304,15 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { static void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old, uptr new_size, uptr alignment) { - if (!PointerAndMemoryTagsMatch(tagged_ptr_old)) - ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr_old)); - + void *untagged_ptr_old = + InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr_old)) + ? UntagPtr(tagged_ptr_old) + : tagged_ptr_old; + if (CheckInvalidFree(stack, untagged_ptr_old, tagged_ptr_old)) + return nullptr; void *tagged_ptr_new = HwasanAllocate(stack, new_size, alignment, false /*zeroise*/); if (tagged_ptr_old && tagged_ptr_new) { - void *untagged_ptr_old = UntagPtr(tagged_ptr_old); Metadata *meta = reinterpret_cast<Metadata *>(allocator.GetMetaData(untagged_ptr_old)); internal_memcpy( @@ -305,6 +333,8 @@ static void *HwasanCalloc(StackTrace *stack, uptr nmemb, uptr size) { } HwasanChunkView FindHeapChunkByAddress(uptr address) { + if (!allocator.PointerIsMine(reinterpret_cast<void *>(address))) + return HwasanChunkView(); void *block = allocator.GetBlockBegin(reinterpret_cast<void*>(address)); if (!block) return HwasanChunkView(); diff --git a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp index bde22df..7642ba6 100644 --- a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp +++ b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp @@ -113,6 +113,15 @@ uptr FindDynamicShadowStart(uptr shadow_size_bytes) { } } // namespace __hwasan + +#elif SANITIZER_FUCHSIA + +namespace __hwasan { + +void InitShadowGOT() {} + +} // namespace __hwasan + #else namespace __hwasan { diff --git a/libsanitizer/hwasan/hwasan_fuchsia.cpp b/libsanitizer/hwasan/hwasan_fuchsia.cpp index e61f6ad..f51e148 100644 --- a/libsanitizer/hwasan/hwasan_fuchsia.cpp +++ b/libsanitizer/hwasan/hwasan_fuchsia.cpp @@ -34,6 +34,15 @@ bool InitShadow() { __sanitizer::InitShadowBounds(); CHECK_NE(__sanitizer::ShadowBounds.shadow_limit, 0); + // These variables are used by MemIsShadow for asserting we have a correct + // shadow address. On Fuchsia, we only have one region of shadow, so the + // bounds of Low shadow can be zero while High shadow represents the true + // bounds. Note that these are inclusive ranges. + kLowShadowStart = 0; + kLowShadowEnd = 0; + kHighShadowStart = __sanitizer::ShadowBounds.shadow_base; + kHighShadowEnd = __sanitizer::ShadowBounds.shadow_limit - 1; + return true; } @@ -143,6 +152,14 @@ static void ThreadExitHook(void *hook, thrd_t self) { hwasanThreadList().ReleaseThread(thread); } +uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) { + CHECK(IsAligned(p, kShadowAlignment)); + CHECK(IsAligned(size, kShadowAlignment)); + __sanitizer_fill_shadow(p, size, tag, + common_flags()->clear_shadow_mmap_threshold); + return AddTagToPointer(p, tag); +} + // Not implemented because Fuchsia does not use signal handlers. void HwasanOnDeadlySignal(int signo, void *info, void *context) {} @@ -163,6 +180,12 @@ void HwasanTSDThreadInit() {} // function is unneeded. void InstallAtExitHandler() {} +void HwasanInstallAtForkHandler() {} + +// TODO(fxbug.dev/81499): Once we finalize the tagged pointer ABI in zircon, we should come back +// here and implement the appropriate check that TBI is enabled. +void InitializeOsSupport() {} + } // namespace __hwasan extern "C" { diff --git a/libsanitizer/hwasan/hwasan_interceptors.cpp b/libsanitizer/hwasan/hwasan_interceptors.cpp index 68f8ade..f96ed88 100644 --- a/libsanitizer/hwasan/hwasan_interceptors.cpp +++ b/libsanitizer/hwasan/hwasan_interceptors.cpp @@ -49,15 +49,14 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*), DEFINE_REAL(int, vfork) DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork) -#endif // HWASAN_WITH_INTERCEPTORS -#if HWASAN_WITH_INTERCEPTORS && defined(__aarch64__) // Get and/or change the set of blocked signals. extern "C" int sigprocmask(int __how, const __hw_sigset_t *__restrict __set, __hw_sigset_t *__restrict __oset); #define SIG_BLOCK 0 #define SIG_SETMASK 2 extern "C" int __sigjmp_save(__hw_sigjmp_buf env, int savemask) { + env[0].__magic = kHwJmpBufMagic; env[0].__mask_was_saved = (savemask && sigprocmask(SIG_BLOCK, (__hw_sigset_t *)0, &env[0].__saved_mask) == 0); @@ -66,8 +65,14 @@ extern "C" int __sigjmp_save(__hw_sigjmp_buf env, int savemask) { static void __attribute__((always_inline)) InternalLongjmp(__hw_register_buf env, int retval) { +# if defined(__aarch64__) + constexpr size_t kSpIndex = 13; +# elif defined(__x86_64__) + constexpr size_t kSpIndex = 6; +# endif + // Clear all memory tags on the stack between here and where we're going. - unsigned long long stack_pointer = env[13]; + unsigned long long stack_pointer = env[kSpIndex]; // The stack pointer should never be tagged, so we don't need to clear the // tag for this function call. __hwasan_handle_longjmp((void *)stack_pointer); @@ -78,6 +83,7 @@ InternalLongjmp(__hw_register_buf env, int retval) { // Must implement this ourselves, since we don't know the order of registers // in different libc implementations and many implementations mangle the // stack pointer so we can't use it without knowing the demangling scheme. +# if defined(__aarch64__) register long int retval_tmp asm("x1") = retval; register void *env_address asm("x0") = &env[0]; asm volatile("ldp x19, x20, [%0, #0<<3];" @@ -100,9 +106,36 @@ InternalLongjmp(__hw_register_buf env, int retval) { "br x30;" : "+r"(env_address) : "r"(retval_tmp)); +# elif defined(__x86_64__) + register long int retval_tmp asm("%rsi") = retval; + register void *env_address asm("%rdi") = &env[0]; + asm volatile( + // Restore registers. + "mov (0*8)(%0),%%rbx;" + "mov (1*8)(%0),%%rbp;" + "mov (2*8)(%0),%%r12;" + "mov (3*8)(%0),%%r13;" + "mov (4*8)(%0),%%r14;" + "mov (5*8)(%0),%%r15;" + "mov (6*8)(%0),%%rsp;" + "mov (7*8)(%0),%%rdx;" + // Return 1 if retval is 0. + "mov $1,%%rax;" + "test %1,%1;" + "cmovnz %1,%%rax;" + "jmp *%%rdx;" ::"r"(env_address), + "r"(retval_tmp)); +# endif } INTERCEPTOR(void, siglongjmp, __hw_sigjmp_buf env, int val) { + if (env[0].__magic != kHwJmpBufMagic) { + Printf( + "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or " + "there is a bug in HWASan.\n"); + return REAL(siglongjmp)(env, val); + } + if (env[0].__mask_was_saved) // Restore the saved signal mask. (void)sigprocmask(SIG_SETMASK, &env[0].__saved_mask, @@ -114,32 +147,24 @@ INTERCEPTOR(void, siglongjmp, __hw_sigjmp_buf env, int val) { // _setjmp on start_thread. Hence we have to intercept the longjmp on // pthread_exit so the __hw_jmp_buf order matches. INTERCEPTOR(void, __libc_longjmp, __hw_jmp_buf env, int val) { + if (env[0].__magic != kHwJmpBufMagic) + return REAL(__libc_longjmp)(env, val); InternalLongjmp(env[0].__jmpbuf, val); } INTERCEPTOR(void, longjmp, __hw_jmp_buf env, int val) { + if (env[0].__magic != kHwJmpBufMagic) { + Printf( + "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or " + "there is a bug in HWASan.\n"); + return REAL(longjmp)(env, val); + } InternalLongjmp(env[0].__jmpbuf, val); } #undef SIG_BLOCK #undef SIG_SETMASK -#endif // HWASAN_WITH_INTERCEPTORS && __aarch64__ - -static void BeforeFork() { - StackDepotLockAll(); -} - -static void AfterFork() { - StackDepotUnlockAll(); -} - -INTERCEPTOR(int, fork, void) { - ENSURE_HWASAN_INITED(); - BeforeFork(); - int pid = REAL(fork)(); - AfterFork(); - return pid; -} +# endif // HWASAN_WITH_INTERCEPTORS namespace __hwasan { @@ -156,10 +181,11 @@ void InitializeInterceptors() { static int inited = 0; CHECK_EQ(inited, 0); - INTERCEPT_FUNCTION(fork); - #if HWASAN_WITH_INTERCEPTORS #if defined(__linux__) + INTERCEPT_FUNCTION(__libc_longjmp); + INTERCEPT_FUNCTION(longjmp); + INTERCEPT_FUNCTION(siglongjmp); INTERCEPT_FUNCTION(vfork); #endif // __linux__ INTERCEPT_FUNCTION(pthread_create); diff --git a/libsanitizer/hwasan/hwasan_interface_internal.h b/libsanitizer/hwasan/hwasan_interface_internal.h index 25c0f94..ef771ad 100644 --- a/libsanitizer/hwasan/hwasan_interface_internal.h +++ b/libsanitizer/hwasan/hwasan_interface_internal.h @@ -169,54 +169,6 @@ SANITIZER_INTERFACE_ATTRIBUTE void __hwasan_print_memory_usage(); SANITIZER_INTERFACE_ATTRIBUTE -int __sanitizer_posix_memalign(void **memptr, uptr alignment, uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_memalign(uptr alignment, uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_aligned_alloc(uptr alignment, uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer___libc_memalign(uptr alignment, uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_valloc(uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_pvalloc(uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_free(void *ptr); - -SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_cfree(void *ptr); - -SANITIZER_INTERFACE_ATTRIBUTE -uptr __sanitizer_malloc_usable_size(const void *ptr); - -SANITIZER_INTERFACE_ATTRIBUTE -__hwasan::__sanitizer_struct_mallinfo __sanitizer_mallinfo(); - -SANITIZER_INTERFACE_ATTRIBUTE -int __sanitizer_mallopt(int cmd, int value); - -SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_malloc_stats(void); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_calloc(uptr nmemb, uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_realloc(void *ptr, uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_reallocarray(void *ptr, uptr nmemb, uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_malloc(uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE void *__hwasan_memcpy(void *dst, const void *src, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void *__hwasan_memset(void *s, int c, uptr n); diff --git a/libsanitizer/hwasan/hwasan_linux.cpp b/libsanitizer/hwasan/hwasan_linux.cpp index e227235..a86ec28 100644 --- a/libsanitizer/hwasan/hwasan_linux.cpp +++ b/libsanitizer/hwasan/hwasan_linux.cpp @@ -15,30 +15,30 @@ #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD -#include "hwasan.h" -#include "hwasan_dynamic_shadow.h" -#include "hwasan_interface_internal.h" -#include "hwasan_mapping.h" -#include "hwasan_report.h" -#include "hwasan_thread.h" -#include "hwasan_thread_list.h" - -#include <dlfcn.h> -#include <elf.h> -#include <link.h> -#include <pthread.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/resource.h> -#include <sys/time.h> -#include <unistd.h> -#include <unwind.h> -#include <sys/prctl.h> -#include <errno.h> - -#include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_procmaps.h" +# include <dlfcn.h> +# include <elf.h> +# include <errno.h> +# include <link.h> +# include <pthread.h> +# include <signal.h> +# include <stdio.h> +# include <stdlib.h> +# include <sys/prctl.h> +# include <sys/resource.h> +# include <sys/time.h> +# include <unistd.h> +# include <unwind.h> + +# include "hwasan.h" +# include "hwasan_dynamic_shadow.h" +# include "hwasan_interface_internal.h" +# include "hwasan_mapping.h" +# include "hwasan_report.h" +# include "hwasan_thread.h" +# include "hwasan_thread_list.h" +# include "sanitizer_common/sanitizer_common.h" +# include "sanitizer_common/sanitizer_procmaps.h" +# include "sanitizer_common/sanitizer_stackdepot.h" // Configurations of HWASAN_WITH_INTERCEPTORS and SANITIZER_ANDROID. // @@ -50,10 +50,10 @@ // Tested with check-hwasan on x86_64-linux. // HWASAN_WITH_INTERCEPTORS=ON, SANITIZER_ANDROID=ON // Tested with check-hwasan on aarch64-linux-android. -#if !SANITIZER_ANDROID +# if !SANITIZER_ANDROID SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL uptr __hwasan_tls; -#endif +# endif namespace __hwasan { @@ -111,9 +111,9 @@ static void InitializeShadowBaseAddress(uptr shadow_size_bytes) { } void InitializeOsSupport() { -#define PR_SET_TAGGED_ADDR_CTRL 55 -#define PR_GET_TAGGED_ADDR_CTRL 56 -#define PR_TAGGED_ADDR_ENABLE (1UL << 0) +# define PR_SET_TAGGED_ADDR_CTRL 55 +# define PR_GET_TAGGED_ADDR_CTRL 56 +# define PR_TAGGED_ADDR_ENABLE (1UL << 0) // Check we're running on a kernel that can use the tagged address ABI. int local_errno = 0; if (internal_iserror(internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0), @@ -164,9 +164,9 @@ void InitializeOsSupport() { Die(); } } -#undef PR_SET_TAGGED_ADDR_CTRL -#undef PR_GET_TAGGED_ADDR_CTRL -#undef PR_TAGGED_ADDR_ENABLE +# undef PR_SET_TAGGED_ADDR_CTRL +# undef PR_GET_TAGGED_ADDR_CTRL +# undef PR_TAGGED_ADDR_ENABLE } bool InitShadow() { @@ -241,12 +241,11 @@ bool MemIsApp(uptr p) { CHECK(GetTagFromPointer(p) == 0); # endif - return p >= kHighMemStart || (p >= kLowMemStart && p <= kLowMemEnd); + return (p >= kHighMemStart && p <= kHighMemEnd) || + (p >= kLowMemStart && p <= kLowMemEnd); } -void InstallAtExitHandler() { - atexit(HwasanAtExit); -} +void InstallAtExitHandler() { atexit(HwasanAtExit); } // ---------------------- TSD ---------------- {{{1 @@ -262,7 +261,7 @@ extern "C" void __hwasan_thread_exit() { hwasanThreadList().ReleaseThread(t); } -#if HWASAN_WITH_INTERCEPTORS +# if HWASAN_WITH_INTERCEPTORS static pthread_key_t tsd_key; static bool tsd_key_inited = false; @@ -286,22 +285,18 @@ void HwasanTSDInit() { tsd_key_inited = true; CHECK_EQ(0, pthread_key_create(&tsd_key, HwasanTSDDtor)); } -#else +# else void HwasanTSDInit() {} void HwasanTSDThreadInit() {} -#endif +# endif -#if SANITIZER_ANDROID -uptr *GetCurrentThreadLongPtr() { - return (uptr *)get_android_tls_ptr(); -} -#else -uptr *GetCurrentThreadLongPtr() { - return &__hwasan_tls; -} -#endif +# if SANITIZER_ANDROID +uptr *GetCurrentThreadLongPtr() { return (uptr *)get_android_tls_ptr(); } +# else +uptr *GetCurrentThreadLongPtr() { return &__hwasan_tls; } +# endif -#if SANITIZER_ANDROID +# if SANITIZER_ANDROID void AndroidTestTlsSlot() { uptr kMagicValue = 0x010203040A0B0C0D; uptr *tls_ptr = GetCurrentThreadLongPtr(); @@ -316,9 +311,9 @@ void AndroidTestTlsSlot() { } *tls_ptr = old_value; } -#else +# else void AndroidTestTlsSlot() {} -#endif +# endif static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) { // Access type is passed in a platform dependent way (see below) and encoded @@ -326,32 +321,32 @@ static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) { // recoverable. Valid values of Y are 0 to 4, which are interpreted as // log2(access_size), and 0xF, which means that access size is passed via // platform dependent register (see below). -#if defined(__aarch64__) +# if defined(__aarch64__) // Access type is encoded in BRK immediate as 0x900 + 0xXY. For Y == 0xF, // access size is stored in X1 register. Access address is always in X0 // register. uptr pc = (uptr)info->si_addr; const unsigned code = ((*(u32 *)pc) >> 5) & 0xffff; if ((code & 0xff00) != 0x900) - return AccessInfo{}; // Not ours. + return AccessInfo{}; // Not ours. const bool is_store = code & 0x10; const bool recover = code & 0x20; const uptr addr = uc->uc_mcontext.regs[0]; const unsigned size_log = code & 0xf; if (size_log > 4 && size_log != 0xf) - return AccessInfo{}; // Not ours. + return AccessInfo{}; // Not ours. const uptr size = size_log == 0xf ? uc->uc_mcontext.regs[1] : 1U << size_log; -#elif defined(__x86_64__) +# elif defined(__x86_64__) // Access type is encoded in the instruction following INT3 as // NOP DWORD ptr [EAX + 0x40 + 0xXY]. For Y == 0xF, access size is stored in // RSI register. Access address is always in RDI register. uptr pc = (uptr)uc->uc_mcontext.gregs[REG_RIP]; - uint8_t *nop = (uint8_t*)pc; - if (*nop != 0x0f || *(nop + 1) != 0x1f || *(nop + 2) != 0x40 || + uint8_t *nop = (uint8_t *)pc; + if (*nop != 0x0f || *(nop + 1) != 0x1f || *(nop + 2) != 0x40 || *(nop + 3) < 0x40) - return AccessInfo{}; // Not ours. + return AccessInfo{}; // Not ours. const unsigned code = *(nop + 3); const bool is_store = code & 0x10; @@ -359,13 +354,13 @@ static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) { const uptr addr = uc->uc_mcontext.gregs[REG_RDI]; const unsigned size_log = code & 0xf; if (size_log > 4 && size_log != 0xf) - return AccessInfo{}; // Not ours. + return AccessInfo{}; // Not ours. const uptr size = size_log == 0xf ? uc->uc_mcontext.gregs[REG_RSI] : 1U << size_log; -#else -# error Unsupported architecture -#endif +# else +# error Unsupported architecture +# endif return AccessInfo{addr, size, is_store, !is_store, recover}; } @@ -378,12 +373,12 @@ static bool HwasanOnSIGTRAP(int signo, siginfo_t *info, ucontext_t *uc) { SignalContext sig{info, uc}; HandleTagMismatch(ai, StackTrace::GetNextInstructionPc(sig.pc), sig.bp, uc); -#if defined(__aarch64__) +# if defined(__aarch64__) uc->uc_mcontext.pc += 4; -#elif defined(__x86_64__) -#else -# error Unsupported architecture -#endif +# elif defined(__x86_64__) +# else +# error Unsupported architecture +# endif return true; } @@ -396,7 +391,7 @@ static void OnStackUnwind(const SignalContext &sig, const void *, void HwasanOnDeadlySignal(int signo, void *info, void *context) { // Probably a tag mismatch. if (signo == SIGTRAP) - if (HwasanOnSIGTRAP(signo, (siginfo_t *)info, (ucontext_t*)context)) + if (HwasanOnSIGTRAP(signo, (siginfo_t *)info, (ucontext_t *)context)) return; HandleDeadlySignal(info, context, GetTid(), &OnStackUnwind, nullptr); @@ -435,6 +430,18 @@ uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) { return AddTagToPointer(p, tag); } -} // namespace __hwasan +void HwasanInstallAtForkHandler() { + auto before = []() { + HwasanAllocatorLock(); + StackDepotLockAll(); + }; + auto after = []() { + StackDepotUnlockAll(); + HwasanAllocatorUnlock(); + }; + pthread_atfork(before, after, after); +} + +} // namespace __hwasan -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD diff --git a/libsanitizer/hwasan/hwasan_report.cpp b/libsanitizer/hwasan/hwasan_report.cpp index 44047c9..9b3b661 100644 --- a/libsanitizer/hwasan/hwasan_report.cpp +++ b/libsanitizer/hwasan/hwasan_report.cpp @@ -37,7 +37,7 @@ namespace __hwasan { class ScopedReport { public: ScopedReport(bool fatal = false) : error_message_(1), fatal(fatal) { - BlockingMutexLock lock(&error_message_lock_); + Lock lock(&error_message_lock_); error_message_ptr_ = fatal ? &error_message_ : nullptr; ++hwasan_report_count; } @@ -45,7 +45,7 @@ class ScopedReport { ~ScopedReport() { void (*report_cb)(const char *); { - BlockingMutexLock lock(&error_message_lock_); + Lock lock(&error_message_lock_); report_cb = error_report_callback_; error_message_ptr_ = nullptr; } @@ -61,7 +61,7 @@ class ScopedReport { } static void MaybeAppendToErrorMessage(const char *msg) { - BlockingMutexLock lock(&error_message_lock_); + Lock lock(&error_message_lock_); if (!error_message_ptr_) return; uptr len = internal_strlen(msg); @@ -72,7 +72,7 @@ class ScopedReport { } static void SetErrorReportCallback(void (*callback)(const char *)) { - BlockingMutexLock lock(&error_message_lock_); + Lock lock(&error_message_lock_); error_report_callback_ = callback; } @@ -82,12 +82,12 @@ class ScopedReport { bool fatal; static InternalMmapVector<char> *error_message_ptr_; - static BlockingMutex error_message_lock_; + static Mutex error_message_lock_; static void (*error_report_callback_)(const char *); }; InternalMmapVector<char> *ScopedReport::error_message_ptr_; -BlockingMutex ScopedReport::error_message_lock_; +Mutex ScopedReport::error_message_lock_; void (*ScopedReport::error_report_callback_)(const char *); // If there is an active ScopedReport, append to its error message. @@ -351,14 +351,16 @@ static void ShowHeapOrGlobalCandidate(uptr untagged_addr, tag_t *candidate, uptr size = GetGlobalSizeFromDescriptor(mem); if (size == 0) // We couldn't find the size of the global from the descriptors. - Printf("%p is located to the %s of a global variable in (%s+0x%x)\n", - untagged_addr, candidate == left ? "right" : "left", module_name, - module_address); + Printf( + "%p is located to the %s of a global variable in " + "\n #0 0x%x (%s+0x%x)\n", + untagged_addr, candidate == left ? "right" : "left", mem, + module_name, module_address); else Printf( "%p is located to the %s of a %zd-byte global variable in " - "(%s+0x%x)\n", - untagged_addr, candidate == left ? "right" : "left", size, + "\n #0 0x%x (%s+0x%x)\n", + untagged_addr, candidate == left ? "right" : "left", size, mem, module_name, module_address); } Printf("%s", d.Default()); @@ -372,6 +374,12 @@ void PrintAddressDescription( int num_descriptions_printed = 0; uptr untagged_addr = UntagAddr(tagged_addr); + if (MemIsShadow(untagged_addr)) { + Printf("%s%p is HWAsan shadow memory.\n%s", d.Location(), untagged_addr, + d.Default()); + return; + } + // Print some very basic information about the address, if it's a heap. HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr); if (uptr beg = chunk.Beg()) { @@ -549,28 +557,48 @@ static void PrintTagsAroundAddr(tag_t *tag_ptr) { "description of short granule tags\n"); } +uptr GetTopPc(StackTrace *stack) { + return stack->size ? StackTrace::GetPreviousInstructionPc(stack->trace[0]) + : 0; +} + void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) { ScopedReport R(flags()->halt_on_error); uptr untagged_addr = UntagAddr(tagged_addr); tag_t ptr_tag = GetTagFromPointer(tagged_addr); - tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr)); - tag_t mem_tag = *tag_ptr; + tag_t *tag_ptr = nullptr; + tag_t mem_tag = 0; + if (MemIsApp(untagged_addr)) { + tag_ptr = reinterpret_cast<tag_t *>(MemToShadow(untagged_addr)); + if (MemIsShadow(reinterpret_cast<uptr>(tag_ptr))) + mem_tag = *tag_ptr; + else + tag_ptr = nullptr; + } Decorator d; Printf("%s", d.Error()); - uptr pc = stack->size ? stack->trace[0] : 0; + uptr pc = GetTopPc(stack); const char *bug_type = "invalid-free"; - Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type, - untagged_addr, pc); + const Thread *thread = GetCurrentThread(); + if (thread) { + Report("ERROR: %s: %s on address %p at pc %p on thread T%zd\n", + SanitizerToolName, bug_type, untagged_addr, pc, thread->unique_id()); + } else { + Report("ERROR: %s: %s on address %p at pc %p on unknown thread\n", + SanitizerToolName, bug_type, untagged_addr, pc); + } Printf("%s", d.Access()); - Printf("tags: %02x/%02x (ptr/mem)\n", ptr_tag, mem_tag); + if (tag_ptr) + Printf("tags: %02x/%02x (ptr/mem)\n", ptr_tag, mem_tag); Printf("%s", d.Default()); stack->Print(); PrintAddressDescription(tagged_addr, 0, nullptr); - PrintTagsAroundAddr(tag_ptr); + if (tag_ptr) + PrintTagsAroundAddr(tag_ptr); ReportErrorSummary(bug_type, stack); } @@ -578,6 +606,15 @@ void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) { void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size, const u8 *expected) { uptr tail_size = kShadowAlignment - (orig_size % kShadowAlignment); + u8 actual_expected[kShadowAlignment]; + internal_memcpy(actual_expected, expected, tail_size); + tag_t ptr_tag = GetTagFromPointer(tagged_addr); + // Short granule is stashed in the last byte of the magic string. To avoid + // confusion, make the expected magic string contain the short granule tag. + if (orig_size % kShadowAlignment != 0) { + actual_expected[tail_size - 1] = ptr_tag; + } + ScopedReport R(flags()->halt_on_error); Decorator d; uptr untagged_addr = UntagAddr(tagged_addr); @@ -614,14 +651,13 @@ void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size, s.append("Expected: "); for (uptr i = 0; i < kShadowAlignment - tail_size; i++) s.append(".. "); - for (uptr i = 0; i < tail_size; i++) - s.append("%02x ", expected[i]); + for (uptr i = 0; i < tail_size; i++) s.append("%02x ", actual_expected[i]); s.append("\n"); s.append(" "); for (uptr i = 0; i < kShadowAlignment - tail_size; i++) s.append(" "); for (uptr i = 0; i < tail_size; i++) - s.append("%s ", expected[i] != tail[i] ? "^^" : " "); + s.append("%s ", actual_expected[i] != tail[i] ? "^^" : " "); s.append("\nThis error occurs when a buffer overflow overwrites memory\n" "to the right of a heap object, but within the %zd-byte granule, e.g.\n" @@ -647,11 +683,11 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size, GetCurrentThread()->stack_allocations()); Decorator d; - Printf("%s", d.Error()); uptr untagged_addr = UntagAddr(tagged_addr); // TODO: when possible, try to print heap-use-after-free, etc. const char *bug_type = "tag-mismatch"; - uptr pc = stack->size ? stack->trace[0] : 0; + uptr pc = GetTopPc(stack); + Printf("%s", d.Error()); Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type, untagged_addr, pc); diff --git a/libsanitizer/hwasan/hwasan_setjmp.S b/libsanitizer/hwasan/hwasan_setjmp_aarch64.S index 381af63..744748a 100644 --- a/libsanitizer/hwasan/hwasan_setjmp.S +++ b/libsanitizer/hwasan/hwasan_setjmp_aarch64.S @@ -1,4 +1,4 @@ -//===-- hwasan_setjmp.S --------------------------------------------------------===// +//===-- hwasan_setjmp_aarch64.S -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -29,7 +29,7 @@ // Hence we have to write this function in assembly. .section .text -.file "hwasan_setjmp.S" +.file "hwasan_setjmp_aarch64.S" .global __interceptor_setjmp ASM_TYPE_FUNCTION(__interceptor_setjmp) @@ -80,24 +80,19 @@ __interceptor_sigsetjmp: ASM_SIZE(__interceptor_sigsetjmp) -.macro ALIAS first second - .globl \second +.macro WEAK_ALIAS first second + .weak \second .equ \second\(), \first .endm #if SANITIZER_ANDROID -ALIAS __interceptor_sigsetjmp, sigsetjmp -.weak sigsetjmp - -ALIAS __interceptor_setjmp_bionic, setjmp -.weak setjmp +WEAK_ALIAS __interceptor_sigsetjmp, sigsetjmp +WEAK_ALIAS __interceptor_setjmp_bionic, setjmp #else -ALIAS __interceptor_sigsetjmp, __sigsetjmp -.weak __sigsetjmp +WEAK_ALIAS __interceptor_sigsetjmp, __sigsetjmp #endif -ALIAS __interceptor_setjmp, _setjmp -.weak _setjmp +WEAK_ALIAS __interceptor_setjmp, _setjmp #endif // We do not need executable stack. diff --git a/libsanitizer/hwasan/hwasan_setjmp_x86_64.S b/libsanitizer/hwasan/hwasan_setjmp_x86_64.S new file mode 100644 index 0000000..84512d1 --- /dev/null +++ b/libsanitizer/hwasan/hwasan_setjmp_x86_64.S @@ -0,0 +1,80 @@ +//===-- hwasan_setjmp_x86_64.S --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// setjmp interceptor for x86_64. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_asm.h" + +#if HWASAN_WITH_INTERCEPTORS && defined(__x86_64__) +#include "sanitizer_common/sanitizer_platform.h" + +// We want to save the context of the calling function. +// That requires +// 1) No modification of the return address by this function. +// 2) No modification of the stack pointer by this function. +// 3) (no modification of any other saved register, but that's not really going +// to occur, and hence isn't as much of a worry). +// +// There's essentially no way to ensure that the compiler will not modify the +// stack pointer when compiling a C function. +// Hence we have to write this function in assembly. +// +// TODO: Handle Intel CET. + +.section .text +.file "hwasan_setjmp_x86_64.S" + +.global __interceptor_setjmp +ASM_TYPE_FUNCTION(__interceptor_setjmp) +__interceptor_setjmp: + CFI_STARTPROC + xorl %esi, %esi + jmp __interceptor_sigsetjmp + CFI_ENDPROC +ASM_SIZE(__interceptor_setjmp) + +.global __interceptor_sigsetjmp +ASM_TYPE_FUNCTION(__interceptor_sigsetjmp) +__interceptor_sigsetjmp: + CFI_STARTPROC + + // Save callee save registers. + mov %rbx, (0*8)(%rdi) + mov %rbp, (1*8)(%rdi) + mov %r12, (2*8)(%rdi) + mov %r13, (3*8)(%rdi) + mov %r14, (4*8)(%rdi) + mov %r15, (5*8)(%rdi) + + // Save SP as it was in caller's frame. + lea 8(%rsp), %rdx + mov %rdx, (6*8)(%rdi) + + // Save return address. + mov (%rsp), %rax + mov %rax, (7*8)(%rdi) + + jmp __sigjmp_save + + CFI_ENDPROC +ASM_SIZE(__interceptor_sigsetjmp) + + +.macro WEAK_ALIAS first second + .weak \second + .equ \second\(), \first +.endm + +WEAK_ALIAS __interceptor_sigsetjmp, __sigsetjmp +WEAK_ALIAS __interceptor_setjmp, _setjmp +#endif + +// We do not need executable stack. +NO_EXEC_STACK_DIRECTIVE diff --git a/libsanitizer/hwasan/hwasan_thread.cpp b/libsanitizer/hwasan/hwasan_thread.cpp index ee747a3..5b65718 100644 --- a/libsanitizer/hwasan/hwasan_thread.cpp +++ b/libsanitizer/hwasan/hwasan_thread.cpp @@ -45,13 +45,13 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size, if (auto sz = flags()->heap_history_size) heap_allocations_ = HeapAllocationsRingBuffer::New(sz); - InitStackAndTls(state); #if !SANITIZER_FUCHSIA // Do not initialize the stack ring buffer just yet on Fuchsia. Threads will // be initialized before we enter the thread itself, so we will instead call // this later. InitStackRingBuffer(stack_buffer_start, stack_buffer_size); #endif + InitStackAndTls(state); } void Thread::InitStackRingBuffer(uptr stack_buffer_start, diff --git a/libsanitizer/hwasan/hwasan_type_test.cpp b/libsanitizer/hwasan/hwasan_type_test.cpp index 8cff495..5307073 100644 --- a/libsanitizer/hwasan/hwasan_type_test.cpp +++ b/libsanitizer/hwasan/hwasan_type_test.cpp @@ -19,7 +19,7 @@ #define CHECK_TYPE_SIZE_FITS(TYPE) \ COMPILER_CHECK(sizeof(__hw_##TYPE) <= sizeof(TYPE)) -#if HWASAN_WITH_INTERCEPTORS && defined(__aarch64__) +#if HWASAN_WITH_INTERCEPTORS CHECK_TYPE_SIZE_FITS(jmp_buf); CHECK_TYPE_SIZE_FITS(sigjmp_buf); #endif |