[compiler-rt] bae9527 - [hwasan] Add report for wild frees.

Florian Mayer via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 13 01:05:03 PDT 2021


Author: Florian Mayer
Date: 2021-08-13T09:04:48+01:00
New Revision: bae9527c204406cacad42b97f524ae51ffbd8823

URL: https://github.com/llvm/llvm-project/commit/bae9527c204406cacad42b97f524ae51ffbd8823
DIFF: https://github.com/llvm/llvm-project/commit/bae9527c204406cacad42b97f524ae51ffbd8823.diff

LOG: [hwasan] Add report for wild frees.

Reviewed By: eugenis

Differential Revision: https://reviews.llvm.org/D107577

Added: 
    compiler-rt/test/hwasan/TestCases/wild-free-close.c
    compiler-rt/test/hwasan/TestCases/wild-free-realloc.c
    compiler-rt/test/hwasan/TestCases/wild-free-shadow.c
    compiler-rt/test/hwasan/TestCases/wild-free.c

Modified: 
    compiler-rt/lib/hwasan/hwasan_allocator.cpp
    compiler-rt/lib/hwasan/hwasan_report.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp
index ef6d4d6c7678..7d8b9f9212a9 100644
--- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp
@@ -201,21 +201,35 @@ 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 (!allocator.PointerIsMine(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));
-
   void *untagged_ptr = InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr))
                            ? UntagPtr(tagged_ptr)
                            : tagged_ptr;
+  if (CheckInvalidFree(stack, untagged_ptr, tagged_ptr))
+    return;
+
   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;
@@ -278,13 +292,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 +321,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/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp
index e2be7596c8c2..8e7f3bbf26bf 100644
--- a/compiler-rt/lib/hwasan/hwasan_report.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_report.cpp
@@ -372,6 +372,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()) {
@@ -559,8 +565,15 @@ void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) {
 
   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 = GetTopPc(stack);
@@ -574,14 +587,16 @@ void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) {
            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/lib/sanitizer_common/sanitizer_allocator_primary64.h b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h
index 316a36385e17..81477aa74112 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h
@@ -282,6 +282,8 @@ class SizeClassAllocator64 {
     CHECK(kMetadataSize);
     uptr class_id = GetSizeClass(p);
     uptr size = ClassIdToSize(class_id);
+    if (!size)
+      return nullptr;
     uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), size);
     uptr region_beg = GetRegionBeginBySizeClass(class_id);
     return reinterpret_cast<void *>(GetMetadataEnd(region_beg) -

diff  --git a/compiler-rt/test/hwasan/TestCases/wild-free-close.c b/compiler-rt/test/hwasan/TestCases/wild-free-close.c
new file mode 100644
index 000000000000..5c4c0863899e
--- /dev/null
+++ b/compiler-rt/test/hwasan/TestCases/wild-free-close.c
@@ -0,0 +1,21 @@
+// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sanitizer/hwasan_interface.h>
+
+int main() {
+  __hwasan_enable_allocator_tagging();
+  char *p = (char *)malloc(1);
+  fprintf(stderr, "ALLOC %p\n", __hwasan_tag_pointer(p, 0));
+  // CHECK: ALLOC {{[0x]+}}[[ADDR:.*]]
+  free(p - 8);
+  // 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-close.c:[[@LINE-3]]
+  // CHECK: is located 8 bytes to the left of 1-byte region [{{[0x]+}}{{.*}}[[ADDR]]
+  // CHECK-NOT: Segmentation fault
+  // CHECK-NOT: SIGSEGV
+  return 0;
+}

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
index 000000000000..e87cd8caa703
--- /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 <stdlib.h>
+
+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
index 000000000000..c2c512cf94eb
--- /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 <stdlib.h>
+
+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
index 000000000000..7cb98f1a1d8c
--- /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 <stdlib.h>
+
+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;
+}


        


More information about the llvm-commits mailing list