diff options
author | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2015-01-22 13:33:16 +0000 |
---|---|---|
committer | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2015-01-22 13:33:16 +0000 |
commit | a50b9b2e06f85fef88f27724a16f6f62c5dd229f (patch) | |
tree | fdb90d4fb82539e5764d63c3b5f26dec36a0899a /lib | |
parent | cafe9a53643f3d813fa0a328a62175e19ff3a1ca (diff) |
[msan] Better use-after-free reports.
By attaching an extra integer tag to heap origins, we are able
to distinguish between uninits
- created by heap allocation,
- created by heap deallocation (i.e. use-after-free),
- created by __msan_allocated_memory call,
- etc.
See https://code.google.com/p/memory-sanitizer/issues/detail?id=35.
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@226821 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/asan/asan_debugging.cc | 4 | ||||
-rw-r--r-- | lib/lsan/lsan_common.cc | 2 | ||||
-rw-r--r-- | lib/msan/msan.cc | 1 | ||||
-rw-r--r-- | lib/msan/msan.h | 2 | ||||
-rw-r--r-- | lib/msan/msan_allocator.cc | 3 | ||||
-rw-r--r-- | lib/msan/msan_interceptors.cc | 10 | ||||
-rw-r--r-- | lib/msan/msan_report.cc | 19 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_stackdepot.cc | 9 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_stacktrace.cc | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_stacktrace.h | 24 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc | 6 |
12 files changed, 57 insertions, 27 deletions
diff --git a/lib/asan/asan_debugging.cc b/lib/asan/asan_debugging.cc index 2b66dd526..6fc5b690d 100644 --- a/lib/asan/asan_debugging.cc +++ b/lib/asan/asan_debugging.cc @@ -81,8 +81,8 @@ void AsanLocateAddress(uptr addr, AddressDescription *descr) { GetInfoForHeapAddress(addr, descr); } -uptr AsanGetStack(uptr addr, uptr *trace, uptr size, u32 *thread_id, - bool alloc_stack) { +static uptr AsanGetStack(uptr addr, uptr *trace, u32 size, u32 *thread_id, + bool alloc_stack) { AsanChunkView chunk = FindHeapChunkByAddress(addr); if (!chunk.IsValid()) return 0; diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index ff1f83b8c..7b3cd1639 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -366,7 +366,7 @@ static void CollectLeaksCb(uptr chunk, void *arg) { LsanMetadata m(chunk); if (!m.allocated()) return; if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) { - uptr resolution = flags()->resolution; + u32 resolution = flags()->resolution; u32 stack_trace_id = 0; if (resolution > 0) { StackTrace stack = StackDepotGet(m.stack_trace_id()); diff --git a/lib/msan/msan.cc b/lib/msan/msan.cc index 3ba653ba4..4adcc9eb8 100644 --- a/lib/msan/msan.cc +++ b/lib/msan/msan.cc @@ -273,6 +273,7 @@ u32 ChainOrigin(u32 id, StackTrace *stack) { return id; Origin o = Origin::FromRawId(id); + stack->tag = StackTrace::TAG_UNKNOWN; Origin chained = Origin::CreateChainedOrigin(o, stack); return chained.raw_id(); } diff --git a/lib/msan/msan.h b/lib/msan/msan.h index f4ea6ca6f..38972981e 100644 --- a/lib/msan/msan.h +++ b/lib/msan/msan.h @@ -167,6 +167,8 @@ void UnpoisonThreadLocalState(); // the previous origin id. u32 ChainOrigin(u32 id, StackTrace *stack); +const int STACK_TRACE_TAG_POISON = StackTrace::TAG_CUSTOM + 1; + #define GET_MALLOC_STACK_TRACE \ BufferedStackTrace stack; \ if (__msan_get_track_origins() && msan_inited) \ diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc index 035c2c666..698b6cddd 100644 --- a/lib/msan/msan_allocator.cc +++ b/lib/msan/msan_allocator.cc @@ -113,6 +113,7 @@ static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment, } else if (flags()->poison_in_malloc) { __msan_poison(allocated, size); if (__msan_get_track_origins()) { + stack->tag = StackTrace::TAG_ALLOC; Origin o = Origin::CreateHeapOrigin(stack); __msan_set_origin(allocated, size, o.raw_id()); } @@ -133,6 +134,7 @@ void MsanDeallocate(StackTrace *stack, void *p) { if (flags()->poison_in_free) { __msan_poison(p, size); if (__msan_get_track_origins()) { + stack->tag = StackTrace::TAG_DEALLOC; Origin o = Origin::CreateHeapOrigin(stack); __msan_set_origin(p, size, o.raw_id()); } @@ -174,6 +176,7 @@ void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size, __msan_clear_and_unpoison((char *)old_p + old_size, new_size - old_size); } else if (flags()->poison_in_malloc) { + stack->tag = StackTrace::TAG_ALLOC; PoisonMemory((char *)old_p + old_size, new_size - old_size, stack); } } diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index 0f29dd1c7..8e521b16f 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -984,13 +984,11 @@ INTERCEPTOR(void *, malloc, SIZE_T size) { return MsanReallocate(&stack, 0, size, sizeof(u64), false); } -void __msan_allocated_memory(const void* data, uptr size) { +void __msan_allocated_memory(const void *data, uptr size) { GET_MALLOC_STACK_TRACE; - if (flags()->poison_in_malloc) - __msan_poison(data, size); - if (__msan_get_track_origins()) { - Origin o = Origin::CreateHeapOrigin(&stack); - __msan_set_origin(data, size, o.raw_id()); + if (flags()->poison_in_malloc) { + stack.tag = STACK_TRACE_TAG_POISON; + PoisonMemory(data, size, &stack); } } diff --git a/lib/msan/msan_report.cc b/lib/msan/msan_report.cc index 6867ee369..33c28b2fb 100644 --- a/lib/msan/msan_report.cc +++ b/lib/msan/msan_report.cc @@ -75,8 +75,23 @@ static void DescribeOrigin(u32 id) { DescribeStackOrigin(so, pc); } else { StackTrace stack = o.getStackTraceForHeapOrigin(); - Printf(" %sUninitialized value was created by a heap allocation%s\n", - d.Origin(), d.End()); + switch (stack.tag) { + case StackTrace::TAG_ALLOC: + Printf(" %sUninitialized value was created by a heap allocation%s\n", + d.Origin(), d.End()); + break; + case StackTrace::TAG_DEALLOC: + Printf(" %sUninitialized value was created by a heap deallocation%s\n", + d.Origin(), d.End()); + break; + case STACK_TRACE_TAG_POISON: + Printf(" %sMemory was marked as uninitialized%s\n", d.Origin(), + d.End()); + break; + default: + Printf(" %sUninitialized value was created%s\n", d.Origin(), d.End()); + break; + } stack.Print(); } } diff --git a/lib/sanitizer_common/sanitizer_stackdepot.cc b/lib/sanitizer_common/sanitizer_stackdepot.cc index f10f1f973..59b53f4dc 100644 --- a/lib/sanitizer_common/sanitizer_stackdepot.cc +++ b/lib/sanitizer_common/sanitizer_stackdepot.cc @@ -22,7 +22,8 @@ struct StackDepotNode { StackDepotNode *link; u32 id; atomic_uint32_t hash_and_use_count; // hash_bits : 12; use_count : 20; - uptr size; + u32 size; + u32 tag; uptr stack[1]; // [size] static const u32 kTabSizeLog = 20; @@ -37,7 +38,8 @@ struct StackDepotNode { bool eq(u32 hash, const args_type &args) const { u32 hash_bits = atomic_load(&hash_and_use_count, memory_order_relaxed) & kHashMask; - if ((hash & kHashMask) != hash_bits || args.size != size) return false; + if ((hash & kHashMask) != hash_bits || args.size != size || args.tag != tag) + return false; uptr i = 0; for (; i < size; i++) { if (stack[i] != args.trace[i]) return false; @@ -72,10 +74,11 @@ struct StackDepotNode { void store(const args_type &args, u32 hash) { atomic_store(&hash_and_use_count, hash & kHashMask, memory_order_relaxed); size = args.size; + tag = args.tag; internal_memcpy(stack, args.trace, size * sizeof(uptr)); } args_type load() const { - return args_type(&stack[0], size); + return args_type(&stack[0], size, tag); } StackDepotHandle get_handle() { return StackDepotHandle(this); } diff --git a/lib/sanitizer_common/sanitizer_stacktrace.cc b/lib/sanitizer_common/sanitizer_stacktrace.cc index 17b2ef357..2deadb6e3 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace.cc +++ b/lib/sanitizer_common/sanitizer_stacktrace.cc @@ -68,7 +68,7 @@ static inline uhwptr *GetCanonicFrame(uptr bp, } void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top, - uptr stack_bottom, uptr max_depth) { + uptr stack_bottom, u32 max_depth) { CHECK_GE(max_depth, 2); trace_buffer[0] = pc; size = 1; diff --git a/lib/sanitizer_common/sanitizer_stacktrace.h b/lib/sanitizer_common/sanitizer_stacktrace.h index 79be28792..6c3a1511f 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace.h +++ b/lib/sanitizer_common/sanitizer_stacktrace.h @@ -17,7 +17,7 @@ namespace __sanitizer { -static const uptr kStackTraceMax = 256; +static const u32 kStackTraceMax = 256; #if SANITIZER_LINUX && (defined(__aarch64__) || defined(__powerpc__) || \ defined(__powerpc64__) || defined(__sparc__) || \ @@ -40,10 +40,18 @@ static const uptr kStackTraceMax = 256; struct StackTrace { const uptr *trace; - uptr size; + u32 size; + u32 tag; - StackTrace() : trace(nullptr), size(0) {} - StackTrace(const uptr *trace, uptr size) : trace(trace), size(size) {} + static const int TAG_UNKNOWN = 0; + static const int TAG_ALLOC = 1; + static const int TAG_DEALLOC = 2; + static const int TAG_CUSTOM = 100; // Tool specific tags start here. + + StackTrace() : trace(nullptr), size(0), tag(0) {} + StackTrace(const uptr *trace, u32 size) : trace(trace), size(size), tag(0) {} + StackTrace(const uptr *trace, u32 size, u32 tag) + : trace(trace), size(size), tag(tag) {} // Prints a symbolized stacktrace, followed by an empty line. void Print() const; @@ -88,15 +96,15 @@ struct BufferedStackTrace : public StackTrace { BufferedStackTrace() : StackTrace(trace_buffer, 0), top_frame_bp(0) {} void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0); - void Unwind(uptr max_depth, uptr pc, uptr bp, void *context, uptr stack_top, + void Unwind(u32 max_depth, uptr pc, uptr bp, void *context, uptr stack_top, uptr stack_bottom, bool request_fast_unwind); private: void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom, - uptr max_depth); - void SlowUnwindStack(uptr pc, uptr max_depth); + u32 max_depth); + void SlowUnwindStack(uptr pc, u32 max_depth); void SlowUnwindStackWithContext(uptr pc, void *context, - uptr max_depth); + u32 max_depth); void PopStackFrames(uptr count); uptr LocatePcInTrace(uptr pc); diff --git a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc index 0d90980e6..0f98c7d5a 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc @@ -44,7 +44,7 @@ void StackTrace::Print() const { Printf("\n"); } -void BufferedStackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, void *context, +void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context, uptr stack_top, uptr stack_bottom, bool request_fast_unwind) { top_frame_bp = (max_depth > 0) ? bp : 0; diff --git a/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc index a98e61771..7ab2efbd7 100644 --- a/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc @@ -96,7 +96,7 @@ uptr Unwind_GetIP(struct _Unwind_Context *ctx) { struct UnwindTraceArg { BufferedStackTrace *stack; - uptr max_depth; + u32 max_depth; }; _Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { @@ -108,7 +108,7 @@ _Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { return UNWIND_CONTINUE; } -void BufferedStackTrace::SlowUnwindStack(uptr pc, uptr max_depth) { +void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) { CHECK_GE(max_depth, 2); size = 0; UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; @@ -128,7 +128,7 @@ void BufferedStackTrace::SlowUnwindStack(uptr pc, uptr max_depth) { } void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, - uptr max_depth) { + u32 max_depth) { CHECK_GE(max_depth, 2); if (!unwind_backtrace_signal_arch) { SlowUnwindStack(pc, max_depth); |