[compiler-rt] r299085 - [asan] Implement "scribble" flags, which overwrite free'd memory with 0x55

Kuba Mracek via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 30 08:44:57 PDT 2017


Author: kuba.brecka
Date: Thu Mar 30 10:44:57 2017
New Revision: 299085

URL: http://llvm.org/viewvc/llvm-project?rev=299085&view=rev
Log:
[asan] Implement "scribble" flags, which overwrite free'd memory with 0x55

This patch implements "Malloc Scribble" in ASan via "max_free_fill_size" and "free_fill_byte" flags, which can be used to overwrite free()'d memory. We also match the behavior of MallocScribble and MallocPreScribble env vars on macOS (see https://developer.apple.com/library/content/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html), which is a helpful tool to detect use-after-free bugs that happen in non-instrumented code.

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


Added:
    compiler-rt/trunk/test/asan/TestCases/Darwin/scribble.cc
    compiler-rt/trunk/test/asan/TestCases/scribble.cc
Modified:
    compiler-rt/trunk/lib/asan/asan_allocator.cc
    compiler-rt/trunk/lib/asan/asan_flags.cc
    compiler-rt/trunk/lib/asan/asan_flags.inc

Modified: compiler-rt/trunk/lib/asan/asan_allocator.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_allocator.cc?rev=299085&r1=299084&r2=299085&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_allocator.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_allocator.cc Thu Mar 30 10:44:57 2017
@@ -523,6 +523,18 @@ struct Allocator {
     AsanThread *t = GetCurrentThread();
     m->free_tid = t ? t->tid() : 0;
     m->free_context_id = StackDepotPut(*stack);
+
+    Flags &fl = *flags();
+    if (fl.max_free_fill_size > 0) {
+      // We have to skip the chunk header, it contains free_context_id.
+      uptr scribble_start = (uptr)m + kChunkHeaderSize + kChunkHeader2Size;
+      if (m->UsedSize() >= kChunkHeader2Size) {  // Skip Header2 in user area.
+        uptr size_to_fill = m->UsedSize() - kChunkHeader2Size;
+        size_to_fill = Min(size_to_fill, (uptr)fl.max_free_fill_size);
+        REAL(memset)((void *)scribble_start, fl.free_fill_byte, size_to_fill);
+      }
+    }
+
     // Poison the region.
     PoisonShadow(m->Beg(),
                  RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),

Modified: compiler-rt/trunk/lib/asan/asan_flags.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_flags.cc?rev=299085&r1=299084&r2=299085&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_flags.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_flags.cc Thu Mar 30 10:44:57 2017
@@ -95,6 +95,18 @@ void InitializeFlags() {
   RegisterCommonFlags(&ubsan_parser);
 #endif
 
+  if (SANITIZER_MAC) {
+    // Support macOS MallocScribble and MallocPreScribble:
+    // <https://developer.apple.com/library/content/documentation/Performance/
+    // Conceptual/ManagingMemory/Articles/MallocDebug.html>
+    if (GetEnv("MallocScribble")) {
+      f->max_free_fill_size = 0x1000;
+    }
+    if (GetEnv("MallocPreScribble")) {
+      f->malloc_fill_byte = 0xaa;
+    }
+  }
+
   // Override from ASan compile definition.
   const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition();
   asan_parser.ParseString(asan_compile_def);

Modified: compiler-rt/trunk/lib/asan/asan_flags.inc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_flags.inc?rev=299085&r1=299084&r2=299085&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_flags.inc (original)
+++ compiler-rt/trunk/lib/asan/asan_flags.inc Thu Mar 30 10:44:57 2017
@@ -63,8 +63,14 @@ ASAN_FLAG(
     int, max_malloc_fill_size, 0x1000,  // By default, fill only the first 4K.
     "ASan allocator flag. max_malloc_fill_size is the maximal amount of "
     "bytes that will be filled with malloc_fill_byte on malloc.")
+ASAN_FLAG(
+    int, max_free_fill_size, 0,
+    "ASan allocator flag. max_free_fill_size is the maximal amount of "
+    "bytes that will be filled with free_fill_byte during free.")
 ASAN_FLAG(int, malloc_fill_byte, 0xbe,
           "Value used to fill the newly allocated memory.")
+ASAN_FLAG(int, free_fill_byte, 0x55,
+          "Value used to fill deallocated memory.")
 ASAN_FLAG(bool, allow_user_poisoning, true,
           "If set, user may manually mark memory regions as poisoned or "
           "unpoisoned.")

Added: compiler-rt/trunk/test/asan/TestCases/Darwin/scribble.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Darwin/scribble.cc?rev=299085&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Darwin/scribble.cc (added)
+++ compiler-rt/trunk/test/asan/TestCases/Darwin/scribble.cc Thu Mar 30 10:44:57 2017
@@ -0,0 +1,56 @@
+// RUN: %clang_asan -O2 %s -o %t
+// RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-NOSCRIBBLE %s
+// RUN: env MallocScribble=1 MallocPreScribble=1 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s
+// RUN: %env_asan_opts=max_free_fill_size=4096 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct Isa {
+  const char *class_name;
+};
+
+struct MyClass {
+  long padding;
+  Isa *isa;
+  long data;
+
+  void print_my_class_name();
+};
+
+__attribute__((no_sanitize("address")))
+void MyClass::print_my_class_name() {
+  fprintf(stderr, "this = %p\n", this);
+  fprintf(stderr, "padding = 0x%lx\n", this->padding);
+  fprintf(stderr, "isa = %p\n", this->isa);
+
+  if ((uint32_t)(uintptr_t)this->isa != 0x55555555) {
+    fprintf(stderr, "class name: %s\n", this->isa->class_name);
+  }
+}
+
+int main() {
+  Isa *my_class_isa = (Isa *)malloc(sizeof(Isa));
+  memset(my_class_isa, 0x77, sizeof(Isa));
+  my_class_isa->class_name = "MyClass";
+
+  MyClass *my_object = (MyClass *)malloc(sizeof(MyClass));
+  memset(my_object, 0x88, sizeof(MyClass));
+  my_object->isa = my_class_isa;
+  my_object->data = 42;
+
+  my_object->print_my_class_name();
+  // CHECK-SCRIBBLE: class name: MyClass
+  // CHECK-NOSCRIBBLE: class name: MyClass
+
+  free(my_object);
+
+  my_object->print_my_class_name();
+  // CHECK-NOSCRIBBLE: class name: MyClass
+  // CHECK-SCRIBBLE: isa = {{0x5555555555555555|0x55555555}}
+
+  printf("okthxbai!\n");
+  // CHECK-SCRIBBLE: okthxbai!
+  // CHECK-NOSCRIBBLE: okthxbai!
+}

Added: compiler-rt/trunk/test/asan/TestCases/scribble.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/scribble.cc?rev=299085&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/scribble.cc (added)
+++ compiler-rt/trunk/test/asan/TestCases/scribble.cc Thu Mar 30 10:44:57 2017
@@ -0,0 +1,55 @@
+// RUN: %clang_asan -O2 %s -o %t
+// RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-NOSCRIBBLE %s
+// RUN: %env_asan_opts=max_free_fill_size=4096 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct Isa {
+  const char *class_name;
+};
+
+struct MyClass {
+  long padding;
+  Isa *isa;
+  long data;
+
+  void print_my_class_name();
+};
+
+__attribute__((no_sanitize("address")))
+void MyClass::print_my_class_name() {
+  fprintf(stderr, "this = %p\n", this);
+  fprintf(stderr, "padding = 0x%lx\n", this->padding);
+  fprintf(stderr, "isa = %p\n", this->isa);
+
+  if ((uint32_t)(uintptr_t)this->isa != 0x55555555) {
+    fprintf(stderr, "class name: %s\n", this->isa->class_name);
+  }
+}
+
+int main() {
+  Isa *my_class_isa = (Isa *)malloc(sizeof(Isa));
+  memset(my_class_isa, 0x77, sizeof(Isa));
+  my_class_isa->class_name = "MyClass";
+
+  MyClass *my_object = (MyClass *)malloc(sizeof(MyClass));
+  memset(my_object, 0x88, sizeof(MyClass));
+  my_object->isa = my_class_isa;
+  my_object->data = 42;
+
+  my_object->print_my_class_name();
+  // CHECK-SCRIBBLE: class name: MyClass
+  // CHECK-NOSCRIBBLE: class name: MyClass
+
+  free(my_object);
+
+  my_object->print_my_class_name();
+  // CHECK-NOSCRIBBLE: class name: MyClass
+  // CHECK-SCRIBBLE: isa = {{0x5555555555555555|0x55555555}}
+
+  printf("okthxbai!\n");
+  // CHECK-SCRIBBLE: okthxbai!
+  // CHECK-NOSCRIBBLE: okthxbai!
+}




More information about the llvm-commits mailing list