diff options
author | Kuba Mracek <mracek@apple.com> | 2017-03-30 15:44:57 +0000 |
---|---|---|
committer | Kuba Mracek <mracek@apple.com> | 2017-03-30 15:44:57 +0000 |
commit | e17862e22900583883fc7f1b97b561aa4e18593e (patch) | |
tree | 72ef94037e23b1b1df0f3875c9e3c803f688d222 /lib | |
parent | fa43e8248dacd7956934c66ab803d00f713b96cd (diff) |
[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
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299085 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/asan/asan_allocator.cc | 12 | ||||
-rw-r--r-- | lib/asan/asan_flags.cc | 12 | ||||
-rw-r--r-- | lib/asan/asan_flags.inc | 6 |
3 files changed, 30 insertions, 0 deletions
diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index 6db2b4db5..7010b6023 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -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), diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc index 74c441a04..555cc04db 100644 --- a/lib/asan/asan_flags.cc +++ b/lib/asan/asan_flags.cc @@ -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); diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc index f316afdb3..65a1d173f 100644 --- a/lib/asan/asan_flags.inc +++ b/lib/asan/asan_flags.inc @@ -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.") |