diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp --- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp +++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp @@ -201,16 +201,31 @@ return PossiblyShortTagMatches(mem_tag, tagged_uptr, 1); } -static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { - CHECK(tagged_ptr); - HWASAN_FREE_HOOK(tagged_ptr); +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(untagged_ptr)) || + !allocator.PointerIsMine(untagged_ptr)) { + ReportInvalidFree(stack, reinterpret_cast(tagged_ptr)); + return true; + } - if (!PointerAndMemoryTagsMatch(tagged_ptr)) + if (!PointerAndMemoryTagsMatch(tagged_ptr)) { ReportInvalidFree(stack, reinterpret_cast(tagged_ptr)); + return true; + } + return false; +} +static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { + CHECK(tagged_ptr); + HWASAN_FREE_HOOK(tagged_ptr); void *untagged_ptr = InTaggableRegion(reinterpret_cast(tagged_ptr)) ? UntagPtr(tagged_ptr) : tagged_ptr; + if (CheckInvalidFree(stack, untagged_ptr, tagged_ptr)) + return; + void *aligned_ptr = reinterpret_cast( RoundDownTo(reinterpret_cast(untagged_ptr), kShadowAlignment)); tag_t pointer_tag = GetTagFromPointer(reinterpret_cast(tagged_ptr)); @@ -278,13 +293,15 @@ static void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old, uptr new_size, uptr alignment) { - if (!PointerAndMemoryTagsMatch(tagged_ptr_old)) - ReportInvalidFree(stack, reinterpret_cast(tagged_ptr_old)); - + void *untagged_ptr_old = + InTaggableRegion(reinterpret_cast(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(allocator.GetMetaData(untagged_ptr_old)); internal_memcpy( @@ -305,6 +322,8 @@ } HwasanChunkView FindHeapChunkByAddress(uptr address) { + if (!allocator.PointerIsMine(reinterpret_cast(address))) + return HwasanChunkView(); void *block = allocator.GetBlockBegin(reinterpret_cast(address)); if (!block) return HwasanChunkView(); diff --git a/compiler-rt/lib/hwasan/hwasan_checks.h b/compiler-rt/lib/hwasan/hwasan_checks.h --- a/compiler-rt/lib/hwasan/hwasan_checks.h +++ b/compiler-rt/lib/hwasan/hwasan_checks.h @@ -67,7 +67,7 @@ tag_t ptr_tag = GetTagFromPointer(ptr); if (ptr_tag == mem_tag) return true; - if (mem_tag >= kShadowAlignment) + if (mem_tag >= kShadowAlignment || mem_tag == 0) return false; if ((ptr & (kShadowAlignment - 1)) + sz > mem_tag) return false; diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp --- a/compiler-rt/lib/hwasan/hwasan_report.cpp +++ b/compiler-rt/lib/hwasan/hwasan_report.cpp @@ -372,6 +372,12 @@ 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()) { @@ -559,8 +565,15 @@ uptr untagged_addr = UntagAddr(tagged_addr); tag_t ptr_tag = GetTagFromPointer(tagged_addr); - tag_t *tag_ptr = reinterpret_cast(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(MemToShadow(untagged_addr)); + if (MemIsShadow(reinterpret_cast(tag_ptr))) + mem_tag = *tag_ptr; + else + tag_ptr = nullptr; + } Decorator d; Printf("%s", d.Error()); uptr pc = GetTopPc(stack); @@ -574,14 +587,16 @@ 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); } diff --git a/compiler-rt/test/hwasan/TestCases/wild-free-realloc.c b/compiler-rt/test/hwasan/TestCases/wild-free-realloc.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/wild-free-realloc.c @@ -0,0 +1,14 @@ +// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s + +#include + +int main() { + char *p = (char *)malloc(1); + realloc(p + 0x10000000000, 2); + // CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread T{{[0-9]+}} + // CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in realloc + // CHECK: #1 {{.*}} in main {{.*}}wild-free-realloc.c:[[@LINE-3]] + // CHECK-NOT: Segmentation fault + // CHECK-NOT: SIGSEGV + return 0; +} diff --git a/compiler-rt/test/hwasan/TestCases/wild-free-shadow.c b/compiler-rt/test/hwasan/TestCases/wild-free-shadow.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/wild-free-shadow.c @@ -0,0 +1,17 @@ +// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s + +#include + +extern void *__hwasan_shadow_memory_dynamic_address; + +int main() { + char *p = (char *)malloc(1); + free(__hwasan_shadow_memory_dynamic_address); + // CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{[0x]+}}[[PTR:.*]] at pc {{[0x]+}}[[PC:.*]] on thread T{{[0-9]+}} + // CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in free + // CHECK: #1 {{.*}} in main {{.*}}wild-free-shadow.c:[[@LINE-3]] + // CHECK: {{[0x]+}}{{.*}}[[PTR]] is HWAsan shadow memory. + // CHECK-NOT: Segmentation fault + // CHECK-NOT: SIGSEGV + return 0; +} diff --git a/compiler-rt/test/hwasan/TestCases/wild-free.c b/compiler-rt/test/hwasan/TestCases/wild-free.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/wild-free.c @@ -0,0 +1,14 @@ +// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s + +#include + +int main() { + char *p = (char *)malloc(1); + free(p + 0x10000000000); + // CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread T{{[0-9]+}} + // CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in free + // CHECK: #1 {{.*}} in main {{.*}}wild-free.c:[[@LINE-3]] + // CHECK-NOT: Segmentation fault + // CHECK-NOT: SIGSEGV + return 0; +}