From c5f98d2ab24c466d39434c0e34f6826a77d5a0b7 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 24 Aug 2018 01:12:26 +0000 Subject: [PATCH] [hwasan] implement detection of double-free (invalid-free) llvm-svn: 340591 --- compiler-rt/lib/hwasan/hwasan_allocator.cc | 13 ++++- compiler-rt/lib/hwasan/hwasan_report.cc | 71 ++++++++++++++++++------- compiler-rt/lib/hwasan/hwasan_report.h | 1 + compiler-rt/test/hwasan/TestCases/double-free.c | 23 ++++++++ 4 files changed, 87 insertions(+), 21 deletions(-) create mode 100644 compiler-rt/test/hwasan/TestCases/double-free.c diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cc b/compiler-rt/lib/hwasan/hwasan_allocator.cc index 23e919e..95dcc07 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocator.cc +++ b/compiler-rt/lib/hwasan/hwasan_allocator.cc @@ -24,6 +24,7 @@ #include "hwasan_mapping.h" #include "hwasan_thread.h" #include "hwasan_poisoning.h" +#include "hwasan_report.h" namespace __hwasan { @@ -173,11 +174,21 @@ static void *HwasanAllocate(StackTrace *stack, uptr size, uptr alignment, return user_ptr; } +static bool PointerAndMemoryTagsMatch(void *user_ptr) { + CHECK(user_ptr); + tag_t ptr_tag = GetTagFromPointer(reinterpret_cast(user_ptr)); + tag_t mem_tag = *reinterpret_cast( + MEM_TO_SHADOW(GetAddressFromPointer(user_ptr))); + return ptr_tag == mem_tag; +} + void HwasanDeallocate(StackTrace *stack, void *user_ptr) { CHECK(user_ptr); HWASAN_FREE_HOOK(user_ptr); void *p = GetAddressFromPointer(user_ptr); + if (!PointerAndMemoryTagsMatch(user_ptr)) + ReportInvalidFree(stack, reinterpret_cast(user_ptr)); Metadata *meta = reinterpret_cast(allocator.GetMetaData(p)); uptr size = meta->requested_size; meta->state = CHUNK_FREE; @@ -226,7 +237,7 @@ void *HwasanReallocate(StackTrace *stack, void *user_old_p, uptr new_size, t ? t->GenerateRandomTag() : kFallbackAllocTag); } if (new_size > old_size) { - tag_t tag = GetTagFromPointer((uptr)user_old_p); + tag_t tag = GetTagFromPointer(reinterpret_cast(user_old_p)); TagMemoryAligned((uptr)old_p + old_size, new_size - old_size, tag); } return user_old_p; diff --git a/compiler-rt/lib/hwasan/hwasan_report.cc b/compiler-rt/lib/hwasan/hwasan_report.cc index c390c0c..ea52d1a 100644 --- a/compiler-rt/lib/hwasan/hwasan_report.cc +++ b/compiler-rt/lib/hwasan/hwasan_report.cc @@ -109,6 +109,54 @@ void ReportInvalidAccessInsideAddressRange(const char *what, const void *start, // DescribeMemoryRange(start, size); } +static void PrintTagsAroundAddr(tag_t *tag_ptr) { + Printf( + "Memory tags around the buggy address (one tag corresponds to %zd " + "bytes):\n", kShadowAlignment); + + const uptr row_len = 16; // better be power of two. + const uptr num_rows = 11; + tag_t *center_row_beg = reinterpret_cast( + RoundDownTo(reinterpret_cast(tag_ptr), row_len)); + tag_t *beg_row = center_row_beg - row_len * (num_rows / 2); + tag_t *end_row = center_row_beg + row_len * (num_rows / 2); + for (tag_t *row = beg_row; row < end_row; row += row_len) { + Printf("%s", row == center_row_beg ? "=>" : " "); + for (uptr i = 0; i < row_len; i++) { + Printf("%s", row + i == tag_ptr ? "[" : " "); + Printf("%02x", row[i]); + Printf("%s", row + i == tag_ptr ? "]" : " "); + } + Printf("%s\n", row == center_row_beg ? "<=" : " "); + } +} + +void ReportInvalidFree(StackTrace *stack, uptr addr) { + ScopedErrorReportLock l; + uptr address = GetAddressFromPointer(addr); + tag_t ptr_tag = GetTagFromPointer(addr); + tag_t *tag_ptr = reinterpret_cast(MEM_TO_SHADOW(address)); + tag_t mem_tag = *tag_ptr; + Decorator d; + Printf("%s", d.Error()); + uptr pc = stack->size ? stack->trace[0] : 0; + const char *bug_type = "invalid-free"; + Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type, + address, pc); + Printf("%s", d.Access()); + Printf("tags: %02x/%02x (ptr/mem)\n", ptr_tag, mem_tag); + Printf("%s", d.Default()); + + stack->Print(); + + PrintAddressDescription(address, 0); + + PrintTagsAroundAddr(tag_ptr); + + ReportErrorSummary(bug_type, stack); + Die(); +} + void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size, bool is_store) { ScopedErrorReportLock l; @@ -119,7 +167,8 @@ void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size, // 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; - Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type, address, pc); + Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type, + address, pc); tag_t ptr_tag = GetTagFromPointer(addr); tag_t *tag_ptr = reinterpret_cast(MEM_TO_SHADOW(address)); @@ -133,25 +182,7 @@ void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size, PrintAddressDescription(address, access_size); - Printf( - "Memory tags around the buggy address (one tag corresponds to %zd " - "bytes):\n", kShadowAlignment); - - const uptr row_len = 16; // better be power of two. - const uptr num_rows = 11; - tag_t *center_row_beg = reinterpret_cast( - RoundDownTo(reinterpret_cast(tag_ptr), row_len)); - tag_t *beg_row = center_row_beg - row_len * (num_rows / 2); - tag_t *end_row = center_row_beg + row_len * (num_rows / 2); - for (tag_t *row = beg_row; row < end_row; row += row_len) { - Printf("%s", row == center_row_beg ? "=>" : " "); - for (uptr i = 0; i < row_len; i++) { - Printf("%s", row + i == tag_ptr ? "[" : " "); - Printf("%02x", row[i]); - Printf("%s", row + i == tag_ptr ? "]" : " "); - } - Printf("%s\n", row == center_row_beg ? "<=" : " "); - } + PrintTagsAroundAddr(tag_ptr); ReportErrorSummary(bug_type, stack); } diff --git a/compiler-rt/lib/hwasan/hwasan_report.h b/compiler-rt/lib/hwasan/hwasan_report.h index bb33f1a..7a9eec8 100644 --- a/compiler-rt/lib/hwasan/hwasan_report.h +++ b/compiler-rt/lib/hwasan/hwasan_report.h @@ -27,6 +27,7 @@ void ReportInvalidAccessInsideAddressRange(const char *what, const void *start, uptr size, uptr offset); void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size, bool is_store); +void ReportInvalidFree(StackTrace *stack, uptr addr); void ReportAtExitStatistics(); diff --git a/compiler-rt/test/hwasan/TestCases/double-free.c b/compiler-rt/test/hwasan/TestCases/double-free.c new file mode 100644 index 0000000..bb7b4ff --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/double-free.c @@ -0,0 +1,23 @@ +// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s + +// REQUIRES: stable-runtime + +#include +#include +#include + +int main() { + __hwasan_enable_allocator_tagging(); + char * volatile x = (char*)malloc(40); + free(x); + free(x); +// CHECK: ERROR: HWAddressSanitizer: invalid-free on address +// CHECK: tags: [[PTR_TAG:..]]/[[MEM_TAG:..]] (ptr/mem) +// CHECK: freed here: +// CHECK: previously allocated here: +// CHECK: Memory tags around the buggy address (one tag corresponds to 16 bytes): +// CHECK: =>{{.*}}[[MEM_TAG]] + fprintf(stderr, "DONE\n"); + __hwasan_disable_allocator_tagging(); +// CHECK-NOT: DONE +} -- 2.7.4