diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2021-11-19 20:06:13 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2021-11-19 20:06:13 +0000 |
| commit | c0981da47d5696fe36474fcf86b4ce03ae3ff818 (patch) | |
| tree | f42add1021b9f2ac6a69ac7cf6c4499962739a45 /compiler-rt/lib/hwasan/hwasan_allocator.cpp | |
| parent | 344a3780b2e33f6ca763666c380202b18aab72a3 (diff) | |
Diffstat (limited to 'compiler-rt/lib/hwasan/hwasan_allocator.cpp')
| -rw-r--r-- | compiler-rt/lib/hwasan/hwasan_allocator.cpp | 58 |
1 files changed, 44 insertions, 14 deletions
diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp index ef6d4d6c7678..9e1729964e27 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp +++ b/compiler-rt/lib/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(); |
