[compiler-rt] r347116 - [hwasan] implement free_checks_tail_magic=1

Kostya Serebryany via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 16 16:25:17 PST 2018


Author: kcc
Date: Fri Nov 16 16:25:17 2018
New Revision: 347116

URL: http://llvm.org/viewvc/llvm-project?rev=347116&view=rev
Log:
[hwasan] implement free_checks_tail_magic=1

Summary:
With free_checks_tail_magic=1 (default) HWASAN
writes magic bytes to the tail of every heap allocation
(last bytes of the last granule, if the last granule is not fully used)
and checks these bytes on free().

This feature will detect buffer overwires within the last granule
at the time of free().

This is an alternative to malloc_align_right=[1289] that should have
fewer compatibility issues. It is also weaker since it doesn't
detect read overflows and reports bugs at free() instead of at access.

Reviewers: eugenis

Subscribers: kubamracek, delcypher, #sanitizers, llvm-commits

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

Added:
    compiler-rt/trunk/test/hwasan/TestCases/tail-magic.c
Modified:
    compiler-rt/trunk/lib/hwasan/hwasan_allocator.cc
    compiler-rt/trunk/lib/hwasan/hwasan_flags.inc
    compiler-rt/trunk/lib/hwasan/hwasan_report.cc
    compiler-rt/trunk/lib/hwasan/hwasan_report.h

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=347116&r1=347115&r2=347116&view=diff
==============================================================================
--- compiler-rt/trunk/lib/hwasan/hwasan_allocator.cc (original)
+++ compiler-rt/trunk/lib/hwasan/hwasan_allocator.cc Fri Nov 16 16:25:17 2018
@@ -42,6 +42,8 @@ enum RightAlignMode {
 static RightAlignMode right_align_mode = kRightAlignNever;
 static bool right_align_8 = false;
 
+// Initialized in HwasanAllocatorInit, an never changed.
+static ALIGNED(16) u8 tail_magic[kShadowAlignment];
 
 bool HwasanChunkView::IsAllocated() const {
   return metadata_ && metadata_->alloc_context_id && metadata_->requested_size;
@@ -111,7 +113,8 @@ void HwasanAllocatorInit() {
              flags()->malloc_align_right);
       Die();
   }
-
+  for (uptr i = 0; i < kShadowAlignment; i++)
+    tail_magic[i] = GetCurrentThread()->GenerateRandomTag();
 }
 
 void AllocatorSwallowThreadLocalCache(AllocatorCache *cache) {
@@ -164,6 +167,9 @@ static void *HwasanAllocate(StackTrace *
     uptr fill_size = Min(size, (uptr)flags()->max_malloc_fill_size);
     internal_memset(allocated, flags()->malloc_fill_byte, fill_size);
   }
+  if (!right_align_mode)
+    internal_memcpy(reinterpret_cast<u8 *>(allocated) + orig_size, tail_magic,
+                    size - orig_size);
 
   void *user_ptr = allocated;
   if (flags()->tag_in_malloc &&
@@ -208,6 +214,19 @@ void HwasanDeallocate(StackTrace *stack,
   uptr orig_size = meta->requested_size;
   u32 free_context_id = StackDepotPut(*stack);
   u32 alloc_context_id = meta->alloc_context_id;
+
+  // Check tail magic.
+  uptr tagged_size = TaggedSize(orig_size);
+  if (flags()->free_checks_tail_magic && !meta->right_aligned && orig_size) {
+    uptr tail_size = tagged_size - orig_size;
+    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))
+      ReportTailOverwritten(stack, reinterpret_cast<uptr>(tagged_ptr),
+                            orig_size, tail_size, tail_magic);
+  }
+
   meta->requested_size = 0;
   meta->alloc_context_id = 0;
   // This memory will not be reused by anyone else, so we are free to keep it

Modified: compiler-rt/trunk/lib/hwasan/hwasan_flags.inc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_flags.inc?rev=347116&r1=347115&r2=347116&view=diff
==============================================================================
--- compiler-rt/trunk/lib/hwasan/hwasan_flags.inc (original)
+++ compiler-rt/trunk/lib/hwasan/hwasan_flags.inc Fri Nov 16 16:25:17 2018
@@ -64,6 +64,10 @@ HWASAN_FLAG(
     "8: allocations are sometimes aligned right to 8-byte boundary; "
     "9: allocations are always aligned right to 8-byte boundary."
   )
+HWASAN_FLAG(bool, free_checks_tail_magic, 1,
+    "If set, free() will check the magic values "
+    "to the right of the allocated object "
+    "if the allocation size is not a divident of the granule size")
 HWASAN_FLAG(
     int, max_free_fill_size, 0,
     "HWASan allocator flag. max_free_fill_size is the maximal amount of "

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=347116&r1=347115&r2=347116&view=diff
==============================================================================
--- compiler-rt/trunk/lib/hwasan/hwasan_report.cc (original)
+++ compiler-rt/trunk/lib/hwasan/hwasan_report.cc Fri Nov 16 16:25:17 2018
@@ -323,6 +323,66 @@ void ReportInvalidFree(StackTrace *stack
   ReportErrorSummary(bug_type, stack);
 }
 
+void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size,
+                           uptr tail_size, const u8 *expected) {
+  ScopedReport R(flags()->halt_on_error);
+  Decorator d;
+  uptr untagged_addr = UntagAddr(tagged_addr);
+  Printf("%s", d.Error());
+  const char *bug_type = "alocation-tail-overwritten";
+  Report("ERROR: %s: %s; heap object [%p,%p) of size %zd\n", SanitizerToolName,
+         bug_type, untagged_addr, untagged_addr + orig_size, orig_size);
+  Printf("\n%s", d.Default());
+  stack->Print();
+  HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr);
+  if (chunk.Beg()) {
+    Printf("%s", d.Allocation());
+    Printf("allocated here:\n");
+    Printf("%s", d.Default());
+    GetStackTraceFromId(chunk.GetAllocStackId()).Print();
+  }
+
+  InternalScopedString s(GetPageSizeCached() * 8);
+  CHECK_GT(tail_size, 0U);
+  CHECK_LT(tail_size, kShadowAlignment);
+  u8 *tail = reinterpret_cast<u8*>(untagged_addr + orig_size);
+  s.append("Tail contains: ");
+  for (uptr i = 0; i < kShadowAlignment - tail_size; i++)
+    s.append(".. ");
+  for (uptr i = 0; i < tail_size; i++)
+    s.append("%02x ", tail[i]);
+  s.append("\n");
+  s.append("Expected:      ");
+  for (uptr i = 0; i < kShadowAlignment - tail_size; i++)
+    s.append(".. ");
+  for (uptr i = 0; i < tail_size; i++)
+    s.append("%02x ", expected[i]);
+  s.append("\n");
+  s.append("               ");
+  for (uptr i = 0; i < kShadowAlignment - tail_size; i++)
+    s.append("   ");
+  for (uptr i = 0; i < tail_size; i++)
+    s.append("%s ", expected[i] != tail[i] ? "^^" : "  ");
+
+  s.append("\nThis error occurs when a buffer overflow overwrites memory\n"
+    "to the right of a heap object, but within the %zd-byte granule, e.g.\n"
+    "   char *x = new char[20];\n"
+    "   x[25] = 42;\n"
+    "By default %s does not detect such bugs at the time of write,\n"
+    "but can detect them at the time of free/delete.\n"
+    "To disable this feature set HWASAN_OPTIONS=free_checks_tail_magic=0;\n"
+    "To enable checking at the time of access, set "
+    "HWASAN_OPTIONS=malloc_align_right to non-zero\n\n",
+    kShadowAlignment, SanitizerToolName);
+  Printf("%s", s.data());
+  GetCurrentThread()->Announce();
+
+  tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
+  PrintTagsAroundAddr(tag_ptr);
+
+  ReportErrorSummary(bug_type, stack);
+}
+
 void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
                        bool is_store, bool fatal) {
   ScopedReport R(fatal);

Modified: compiler-rt/trunk/lib/hwasan/hwasan_report.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_report.h?rev=347116&r1=347115&r2=347116&view=diff
==============================================================================
--- compiler-rt/trunk/lib/hwasan/hwasan_report.h (original)
+++ compiler-rt/trunk/lib/hwasan/hwasan_report.h Fri Nov 16 16:25:17 2018
@@ -25,6 +25,8 @@ void ReportStats();
 void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size,
                        bool is_store, bool fatal);
 void ReportInvalidFree(StackTrace *stack, uptr addr);
+void ReportTailOverwritten(StackTrace *stack, uptr addr, uptr orig_size,
+                           uptr tail_size, const u8 *expected);
 
 void ReportAtExitStatistics();
 

Added: compiler-rt/trunk/test/hwasan/TestCases/tail-magic.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/hwasan/TestCases/tail-magic.c?rev=347116&view=auto
==============================================================================
--- compiler-rt/trunk/test/hwasan/TestCases/tail-magic.c (added)
+++ compiler-rt/trunk/test/hwasan/TestCases/tail-magic.c Fri Nov 16 16:25:17 2018
@@ -0,0 +1,28 @@
+// Tests free_checks_tail_magic=1.
+// RUN: %clang_hwasan  %s -o %t
+// RUN: %env_hwasan_opts=free_checks_tail_magic=0     %run %t
+// RUN: %env_hwasan_opts=free_checks_tail_magic=1 not %run %t 2>&1 | FileCheck %s
+// RUN:                                           not %run %t 2>&1 | FileCheck %s
+
+// REQUIRES: stable-runtime
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sanitizer/hwasan_interface.h>
+
+static volatile void *sink;
+
+int main(int argc, char **argv) {
+  __hwasan_enable_allocator_tagging();
+
+  char *p = (char*)malloc(20);
+  sink = p;
+  p[20] = 0x42;
+  p[24] = 0x66;
+  free(p);
+// CHECK: ERROR: HWAddressSanitizer: alocation-tail-overwritten; heap object [{{.*}}) of size 20
+// CHECK: in main {{.*}}tail-magic.c:[[@LINE-2]]
+// CHECK: allocated here:
+// CHECK: in main {{.*}}tail-magic.c:[[@LINE-8]]
+// CHECK: Tail contains: .. .. .. .. 42 {{.. .. ..}} 66
+}




More information about the llvm-commits mailing list