[compiler-rt] r341133 - [hwasan] use thread-local ring buffers to properly report heap-use-after-free

Kostya Serebryany via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 30 15:11:56 PDT 2018


Author: kcc
Date: Thu Aug 30 15:11:56 2018
New Revision: 341133

URL: http://llvm.org/viewvc/llvm-project?rev=341133&view=rev
Log:
[hwasan] use thread-local ring buffers to properly report heap-use-after-free

Modified:
    compiler-rt/trunk/lib/hwasan/hwasan_allocator.cc
    compiler-rt/trunk/lib/hwasan/hwasan_allocator.h
    compiler-rt/trunk/lib/hwasan/hwasan_report.cc
    compiler-rt/trunk/lib/hwasan/hwasan_thread.cc
    compiler-rt/trunk/lib/hwasan/hwasan_thread.h
    compiler-rt/trunk/test/hwasan/TestCases/double-free.c
    compiler-rt/trunk/test/hwasan/TestCases/realloc-after-free.c
    compiler-rt/trunk/test/hwasan/TestCases/use-after-free.c

Modified: compiler-rt/trunk/lib/hwasan/hwasan_allocator.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_allocator.cc?rev=341133&r1=341132&r2=341133&view=diff
==============================================================================
--- compiler-rt/trunk/lib/hwasan/hwasan_allocator.cc (original)
+++ compiler-rt/trunk/lib/hwasan/hwasan_allocator.cc Thu Aug 30 15:11:56 2018
@@ -36,9 +36,8 @@ enum {
 
 struct Metadata {
   u64 state : 2;
-  u32 requested_size;  // Current use cases of hwasan do not expect sizes > 4G.
-  u32 alloc_context_id;
-  u32 free_context_id;
+  u64 requested_size : 31;  // sizes are < 4G.
+  u32 alloc_context_id : 31;
 };
 
 bool HwasanChunkView::IsValid() const {
@@ -59,9 +58,6 @@ uptr HwasanChunkView::UsedSize() const {
 u32 HwasanChunkView::GetAllocStackId() const {
   return metadata_->alloc_context_id;
 }
-u32 HwasanChunkView::GetFreeStackId() const {
-  return metadata_->free_context_id;
-}
 
 struct HwasanMapUnmapCallback {
   void OnMap(uptr p, uptr size) const {}
@@ -197,7 +193,7 @@ void HwasanDeallocate(StackTrace *stack,
   meta->state = CHUNK_FREE;
   meta->requested_size = 0;
   u32 free_context_id = StackDepotPut(*stack);
-  meta->free_context_id = free_context_id;
+  u32 alloc_context_id = meta->alloc_context_id;
   // This memory will not be reused by anyone else, so we are free to keep it
   // poisoned.
   Thread *t = GetCurrentThread();
@@ -213,8 +209,8 @@ void HwasanDeallocate(StackTrace *stack,
     AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
     allocator.Deallocate(cache, untagged_ptr);
     if (auto *ha = t->heap_allocations())
-      ha->push({reinterpret_cast<uptr>(tagged_ptr), free_context_id,
-                static_cast<u32>(size)});
+      ha->push({reinterpret_cast<uptr>(tagged_ptr), alloc_context_id,
+                free_context_id, static_cast<u32>(size)});
   } else {
     SpinMutexLock l(&fallback_mutex);
     AllocatorCache *cache = &fallback_allocator_cache;

Modified: compiler-rt/trunk/lib/hwasan/hwasan_allocator.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_allocator.h?rev=341133&r1=341132&r2=341133&view=diff
==============================================================================
--- compiler-rt/trunk/lib/hwasan/hwasan_allocator.h (original)
+++ compiler-rt/trunk/lib/hwasan/hwasan_allocator.h Thu Aug 30 15:11:56 2018
@@ -42,7 +42,6 @@ class HwasanChunkView {
   uptr End() const;            // Last byte of user memory
   uptr UsedSize() const;       // Size requested by the user
   u32 GetAllocStackId() const;
-  u32 GetFreeStackId() const;
  private:
   uptr block_;
   Metadata *const metadata_;
@@ -54,6 +53,7 @@ HwasanChunkView FindHeapChunkByAddress(u
 // These are recorded in a thread-local ring buffer.
 struct HeapAllocationRecord {
   uptr tagged_addr;
+  u32  alloc_context_id;
   u32  free_context_id;
   u32  requested_size;
 };

Modified: compiler-rt/trunk/lib/hwasan/hwasan_report.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_report.cc?rev=341133&r1=341132&r2=341133&view=diff
==============================================================================
--- compiler-rt/trunk/lib/hwasan/hwasan_report.cc (original)
+++ compiler-rt/trunk/lib/hwasan/hwasan_report.cc Thu Aug 30 15:11:56 2018
@@ -42,24 +42,7 @@ class Decorator: public __sanitizer::San
   const char *Allocation() const { return Magenta(); }
   const char *Origin() const { return Magenta(); }
   const char *Name() const { return Green(); }
-};
-
-struct HeapAddressDescription {
-  uptr addr;
-  u32 alloc_stack_id;
-  u32 free_stack_id;
-
-  void Print() const {
-    Decorator d;
-    if (free_stack_id) {
-      Printf("%sfreed here:%s\n", d.Allocation(), d.Default());
-      GetStackTraceFromId(free_stack_id).Print();
-      Printf("%spreviously allocated here:%s\n", d.Allocation(), d.Default());
-    } else {
-      Printf("%sallocated here:%s\n", d.Allocation(), d.Default());
-    }
-    GetStackTraceFromId(alloc_stack_id).Print();
-  }
+  const char *Location() { return Green(); }
 };
 
 bool FindHeapAllocation(HeapAllocationsRingBuffer *rb,
@@ -77,25 +60,35 @@ bool FindHeapAllocation(HeapAllocationsR
   return false;
 }
 
-bool GetHeapAddressInformation(uptr addr, uptr access_size,
-                               HeapAddressDescription *description) {
-  HwasanChunkView chunk = FindHeapChunkByAddress(addr);
-  if (!chunk.IsValid())
-    return false;
-  description->addr = addr;
-  description->alloc_stack_id = chunk.GetAllocStackId();
-  description->free_stack_id = chunk.GetFreeStackId();
-  return true;
-}
-
-void PrintAddressDescription(uptr addr, uptr access_size) {
-  HeapAddressDescription heap_description;
-  if (GetHeapAddressInformation(addr, access_size, &heap_description)) {
-    heap_description.Print();
-    return;
-  }
-  // We exhausted our possibilities. Bail out.
-  Printf("HWAddressSanitizer can not describe address in more detail.\n");
+void PrintAddressDescription(uptr tagged_addr, uptr access_size) {
+  int num_descriptions_printed = 0;
+  uptr untagged_addr = UntagAddr(tagged_addr);
+  Thread::VisitAllLiveThreads([&](Thread *t) {
+    Decorator d;
+    HeapAllocationRecord har;
+    if (FindHeapAllocation(t->heap_allocations(), tagged_addr, &har)) {
+      Printf("%s", d.Location());
+      Printf("%p is located %zd bytes inside of %zd-byte region [%p,%p)\n",
+             untagged_addr, untagged_addr - UntagAddr(har.tagged_addr),
+             har.requested_size, UntagAddr(har.tagged_addr),
+             UntagAddr(har.tagged_addr) + har.requested_size);
+      Printf("%s", d.Allocation());
+      Printf("freed by thread %p here:\n", t);
+      Printf("%s", d.Default());
+      GetStackTraceFromId(har.free_context_id).Print();
+
+      Printf("%s", d.Allocation());
+      Printf("previously allocated here:\n", t);
+      Printf("%s", d.Default());
+      GetStackTraceFromId(har.alloc_context_id).Print();
+
+      num_descriptions_printed++;
+    }
+  });
+
+  if (!num_descriptions_printed)
+    // We exhausted our possibilities. Bail out.
+    Printf("HWAddressSanitizer can not describe address in more detail.\n");
 }
 
 void ReportInvalidAccess(StackTrace *stack, u32 origin) {
@@ -165,7 +158,7 @@ void ReportInvalidFree(StackTrace *stack
 
   stack->Print();
 
-  PrintAddressDescription(untagged_addr, 0);
+  PrintAddressDescription(tagged_addr, 0);
 
   PrintTagsAroundAddr(tag_ptr);
 
@@ -197,20 +190,7 @@ void ReportTagMismatch(StackTrace *stack
 
   stack->Print();
 
-  PrintAddressDescription(untagged_addr, access_size);
-
-  // Temporary functionality; to be folded into PrintAddressDescription.
-  // TODOs:
-  // * implement ThreadRegistry
-  // * check all threads, not just the current one.
-  // * remove reduntant fields from the allocator metadata
-  // * use the allocations found in the ring buffer for the main report.
-  HeapAllocationRecord har;
-  Thread *t = GetCurrentThread();
-  if (FindHeapAllocation(t->heap_allocations(), tagged_addr, &har))
-    Printf("Address found in the ring buffer: %p %u %u\n", har.tagged_addr,
-           har.free_context_id, har.requested_size);
-
+  PrintAddressDescription(tagged_addr, access_size);
 
   PrintTagsAroundAddr(tag_ptr);
 

Modified: compiler-rt/trunk/lib/hwasan/hwasan_thread.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_thread.cc?rev=341133&r1=341132&r2=341133&view=diff
==============================================================================
--- compiler-rt/trunk/lib/hwasan/hwasan_thread.cc (original)
+++ compiler-rt/trunk/lib/hwasan/hwasan_thread.cc Thu Aug 30 15:11:56 2018
@@ -24,8 +24,8 @@ static u32 RandomSeed() {
   return seed;
 }
 
-static Thread *main_thread;
-static SpinMutex thread_list_mutex;
+Thread *Thread::main_thread;
+SpinMutex Thread::thread_list_mutex;
 
 void Thread::InsertIntoThreadList(Thread *t) {
   CHECK(!t->next_);

Modified: compiler-rt/trunk/lib/hwasan/hwasan_thread.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_thread.h?rev=341133&r1=341132&r2=341133&view=diff
==============================================================================
--- compiler-rt/trunk/lib/hwasan/hwasan_thread.h (original)
+++ compiler-rt/trunk/lib/hwasan/hwasan_thread.h Thu Aug 30 15:11:56 2018
@@ -60,6 +60,16 @@ class Thread {
   void EnableTagging() { tagging_disabled_--; }
   bool TaggingIsDisabled() const { return tagging_disabled_; }
 
+  template <class CB>
+  static void VisitAllLiveThreads(CB cb) {
+    SpinMutexLock l(&thread_list_mutex);
+    Thread *t = main_thread;
+    while (t) {
+      cb(t);
+      t = t->next_;
+    }
+  }
+
  private:
   // NOTE: There is no Thread constructor. It is allocated
   // via mmap() and *must* be valid in zero-initialized state.
@@ -85,6 +95,8 @@ class Thread {
   static void InsertIntoThreadList(Thread *t);
   static void RemoveFromThreadList(Thread *t);
   Thread *next_;  // All live threads form a linked list.
+  static SpinMutex thread_list_mutex;
+  static Thread *main_thread;
 
   u32 tagging_disabled_;  // if non-zero, malloc uses zero tag in this thread.
 };

Modified: compiler-rt/trunk/test/hwasan/TestCases/double-free.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/hwasan/TestCases/double-free.c?rev=341133&r1=341132&r2=341133&view=diff
==============================================================================
--- compiler-rt/trunk/test/hwasan/TestCases/double-free.c (original)
+++ compiler-rt/trunk/test/hwasan/TestCases/double-free.c Thu Aug 30 15:11:56 2018
@@ -13,7 +13,7 @@ int main() {
   free(x);
 // CHECK: ERROR: HWAddressSanitizer: invalid-free on address
 // CHECK: tags: [[PTR_TAG:..]]/[[MEM_TAG:..]] (ptr/mem)
-// CHECK: freed here:
+// CHECK: freed by thread {{.*}} here:
 // CHECK: previously allocated here:
 // CHECK: Memory tags around the buggy address (one tag corresponds to 16 bytes):
 // CHECK: =>{{.*}}[[MEM_TAG]]

Modified: compiler-rt/trunk/test/hwasan/TestCases/realloc-after-free.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/hwasan/TestCases/realloc-after-free.c?rev=341133&r1=341132&r2=341133&view=diff
==============================================================================
--- compiler-rt/trunk/test/hwasan/TestCases/realloc-after-free.c (original)
+++ compiler-rt/trunk/test/hwasan/TestCases/realloc-after-free.c Thu Aug 30 15:11:56 2018
@@ -18,7 +18,7 @@ int main(int argc, char **argv) {
   x = realloc(x, realloc_size);
 // CHECK: ERROR: HWAddressSanitizer: invalid-free on address
 // CHECK: tags: [[PTR_TAG:..]]/[[MEM_TAG:..]] (ptr/mem)
-// CHECK: freed here:
+// CHECK: freed by thread {{.*}} here:
 // CHECK: previously allocated here:
 // CHECK: Memory tags around the buggy address (one tag corresponds to 16 bytes):
 // CHECK: =>{{.*}}[[MEM_TAG]]

Modified: compiler-rt/trunk/test/hwasan/TestCases/use-after-free.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/hwasan/TestCases/use-after-free.c?rev=341133&r1=341132&r2=341133&view=diff
==============================================================================
--- compiler-rt/trunk/test/hwasan/TestCases/use-after-free.c (original)
+++ compiler-rt/trunk/test/hwasan/TestCases/use-after-free.c Thu Aug 30 15:11:56 2018
@@ -23,7 +23,7 @@ int main() {
   // CHECK: [[TYPE]] of size 1 at {{.*}} tags: [[PTR_TAG:[0-9a-f][0-9a-f]]]/[[MEM_TAG:[0-9a-f][0-9a-f]]] (ptr/mem)
   // CHECK: #0 {{.*}} in main {{.*}}use-after-free.c:[[@LINE-2]]
 
-  // CHECK: freed here:
+  // CHECK: freed by thread {{.*}} here:
   // CHECK: #0 {{.*}} in {{.*}}free{{.*}} {{.*}}hwasan_interceptors.cc
   // CHECK: #1 {{.*}} in main {{.*}}use-after-free.c:[[@LINE-11]]
 




More information about the llvm-commits mailing list