From cc819c46f26de10634a9b2755b616c6209b7f195 Mon Sep 17 00:00:00 2001 From: MrLop Date: Mon, 13 Jan 2025 17:01:54 +0800 Subject: [PATCH 01/11] [Huawei][HWASAN] The heap_history_size of The Main Thread Is Separately Configured Signed-off-by: MrLop --- compiler-rt/lib/hwasan/hwasan_flags.inc | 5 +++++ compiler-rt/lib/hwasan/hwasan_thread.cpp | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler-rt/lib/hwasan/hwasan_flags.inc b/compiler-rt/lib/hwasan/hwasan_flags.inc index 18ea47f981be..b80f28ebd459 100644 --- a/compiler-rt/lib/hwasan/hwasan_flags.inc +++ b/compiler-rt/lib/hwasan/hwasan_flags.inc @@ -53,6 +53,11 @@ HWASAN_FLAG(int, heap_history_size, 1023, "The number of heap (de)allocations remembered per thread. " "Affects the quality of heap-related reports, but not the ability " "to find bugs.") +HWASAN_FLAG( + int, heap_history_size_main_thread, 102300, + "The number of heap (de)allocations remembered for the main thread. " + "Affects the quality of heap-related reports, but not the ability " + "to find bugs.") HWASAN_FLAG(bool, export_memory_stats, true, "Export up-to-date memory stats through /proc") HWASAN_FLAG(int, stack_history_size, 1024, diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp index c776ae179cec..feb7f5c70b02 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.cpp +++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp @@ -44,7 +44,8 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size, static atomic_uint64_t unique_id; unique_id_ = atomic_fetch_add(&unique_id, 1, memory_order_relaxed); - if (auto sz = flags()->heap_history_size) + if (auto sz = IsMainThread() ? flags()->heap_history_size_main_thread + : flags()->heap_history_size) heap_allocations_ = HeapAllocationsRingBuffer::New(sz); #if !SANITIZER_FUCHSIA -- Gitee From 8c713bdb6796ad47444d1dc21a343c00a175d945 Mon Sep 17 00:00:00 2001 From: MrLop Date: Mon, 13 Jan 2025 17:05:59 +0800 Subject: [PATCH 02/11] [Huawei][HWASAN] Print Chunk's Allocated Stack If the target address of the hwasan tag-mismatch found in a chunk is allocated, print the stack of the chunk allocated. Signed-off-by: MrLop --- compiler-rt/lib/hwasan/hwasan_report.cpp | 6 ++++++ compiler-rt/test/hwasan/TestCases/heap-buffer-overflow.c | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp index a59d5fef9791..dd374a01033c 100644 --- a/compiler-rt/lib/hwasan/hwasan_report.cpp +++ b/compiler-rt/lib/hwasan/hwasan_report.cpp @@ -393,6 +393,12 @@ void PrintAddressDescription( chunk.IsAllocated() ? "allocated" : "unallocated", size, untagged_addr - beg, d.Default()); + if (chunk.IsAllocated() && chunk.GetAllocStackId()) { + Printf("%s", d.Allocation()); + Printf("Currently allocated here:\n"); + Printf("%s", d.Default()); + GetStackTraceFromId(chunk.GetAllocStackId()).Print(); + } } tag_t addr_tag = GetTagFromPointer(tagged_addr); diff --git a/compiler-rt/test/hwasan/TestCases/heap-buffer-overflow.c b/compiler-rt/test/hwasan/TestCases/heap-buffer-overflow.c index ff52a4bf298c..425b8a405411 100644 --- a/compiler-rt/test/hwasan/TestCases/heap-buffer-overflow.c +++ b/compiler-rt/test/hwasan/TestCases/heap-buffer-overflow.c @@ -50,10 +50,14 @@ int main(int argc, char **argv) { // CHECKm30: is located 30 bytes to the left of 30-byte region // // CHECKMm30: is a large allocated heap chunk; size: 1003520 offset: -30 +// CHECKMm30: Currently allocated here: +// CHECKMm30: #0 {{[0x]+}}{{.*}} // CHECKMm30: Cause: heap-buffer-overflow // CHECKMm30: is located 30 bytes to the left of 1000000-byte region // // CHECKM: is a large allocated heap chunk; size: 1003520 offset: 1000000 +// CHECKM: Currently allocated here: +// CHECKM: #0 {{[0x]+}}{{.*}} // CHECKM: Cause: heap-buffer-overflow // CHECKM: is located 0 bytes to the right of 1000000-byte region // -- Gitee From 7b6c00644e306384bdf85a82e9cb0678352fa879 Mon Sep 17 00:00:00 2001 From: MrLop Date: Mon, 13 Jan 2025 20:48:52 +0800 Subject: [PATCH 03/11] [Huawei][HWASAN] Support Print All UAF Stacks If hwasan tag-mismatch contains multiple UAF stacks, a flag needs to be added to determin whether to print only the same tag or all of the stacks. By default, this flag is enabled. Signed-off-by: MrLop --- compiler-rt/lib/hwasan/hwasan_allocator.cpp | 8 +- compiler-rt/lib/hwasan/hwasan_flags.inc | 5 + compiler-rt/lib/hwasan/hwasan_report.cpp | 126 ++++++++---------- compiler-rt/lib/hwasan/hwasan_thread.cpp | 2 +- compiler-rt/lib/hwasan/hwasan_thread.h | 6 + .../sanitizer_common/sanitizer_ring_buffer.h | 18 ++- .../TestCases/use-after-free-and-overflow.c | 2 +- 7 files changed, 86 insertions(+), 81 deletions(-) diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp index 842455150c7b..e8d407442f44 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp +++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp @@ -297,9 +297,11 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { } if (t) { allocator.Deallocate(t->allocator_cache(), aligned_ptr); - if (auto *ha = t->heap_allocations()) - ha->push({reinterpret_cast(tagged_ptr), alloc_context_id, - free_context_id, static_cast(orig_size)}); + if (t->AllowTracingHeapAllocation()) { + if (auto *ha = t->heap_allocations()) + ha->push({reinterpret_cast(tagged_ptr), alloc_context_id, + free_context_id, static_cast(orig_size)}); + } } else { SpinMutexLock l(&fallback_mutex); AllocatorCache *cache = &fallback_allocator_cache; diff --git a/compiler-rt/lib/hwasan/hwasan_flags.inc b/compiler-rt/lib/hwasan/hwasan_flags.inc index b80f28ebd459..30ae39eff9ab 100644 --- a/compiler-rt/lib/hwasan/hwasan_flags.inc +++ b/compiler-rt/lib/hwasan/hwasan_flags.inc @@ -86,3 +86,8 @@ HWASAN_FLAG(bool, malloc_bisect_dump, false, // are untagged before the call. HWASAN_FLAG(bool, fail_without_syscall_abi, true, "Exit if fail to request relaxed syscall ABI.") + +HWASAN_FLAG( + bool, print_uaf_stacks_with_same_tag, true, + "Control the output content of use-after-free, deciding whether to print " + "all stack traces of matched allocations with the same tag restriction.") \ No newline at end of file diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp index dd374a01033c..36dec60ebb16 100644 --- a/compiler-rt/lib/hwasan/hwasan_report.cpp +++ b/compiler-rt/lib/hwasan/hwasan_report.cpp @@ -139,45 +139,6 @@ class Decorator: public __sanitizer::SanitizerCommonDecorator { const char *Thread() { return Green(); } }; -static bool FindHeapAllocation(HeapAllocationsRingBuffer *rb, uptr tagged_addr, - HeapAllocationRecord *har, uptr *ring_index, - uptr *num_matching_addrs, - uptr *num_matching_addrs_4b) { - if (!rb) return false; - - *num_matching_addrs = 0; - *num_matching_addrs_4b = 0; - for (uptr i = 0, size = rb->size(); i < size; i++) { - auto h = (*rb)[i]; - if (h.tagged_addr <= tagged_addr && - h.tagged_addr + h.requested_size > tagged_addr) { - *har = h; - *ring_index = i; - return true; - } - - // Measure the number of heap ring buffer entries that would have matched - // if we had only one entry per address (e.g. if the ring buffer data was - // stored at the address itself). This will help us tune the allocator - // implementation for MTE. - if (UntagAddr(h.tagged_addr) <= UntagAddr(tagged_addr) && - UntagAddr(h.tagged_addr) + h.requested_size > UntagAddr(tagged_addr)) { - ++*num_matching_addrs; - } - - // Measure the number of heap ring buffer entries that would have matched - // if we only had 4 tag bits, which is the case for MTE. - auto untag_4b = [](uptr p) { - return p & ((1ULL << 60) - 1); - }; - if (untag_4b(h.tagged_addr) <= untag_4b(tagged_addr) && - untag_4b(h.tagged_addr) + h.requested_size > untag_4b(tagged_addr)) { - ++*num_matching_addrs_4b; - } - } - return false; -} - static void PrintStackAllocations(StackAllocationsRingBuffer *sa, tag_t addr_tag, uptr untagged_addr) { uptr frames = Min((uptr)flags()->stack_history_size, sa->size()); @@ -453,47 +414,68 @@ void PrintAddressDescription( if (!on_stack && candidate && candidate_distance <= kCloseCandidateDistance) { ShowHeapOrGlobalCandidate(untagged_addr, candidate, left, right); + candidate = nullptr; num_descriptions_printed++; } + auto PrintUAF = [&](Thread *t, uptr ring_index, HeapAllocationRecord &har) { + uptr ha_untagged_addr = UntagAddr(har.tagged_addr); + Printf("%s", d.Error()); + Printf("\nPotential Cause: use-after-free\n"); + Printf("%s", d.Location()); + Printf( + "%p (rb[%d] tags:%02x) is located %zd bytes inside of %zd-byte region " + "[%p,%p)\n", + untagged_addr, ring_index, GetTagFromPointer(har.tagged_addr), + untagged_addr - ha_untagged_addr, har.requested_size, ha_untagged_addr, + ha_untagged_addr + har.requested_size); + Printf("%s", d.Allocation()); + Printf("freed by thread T%zd here:\n", t->unique_id()); + 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(); + t->Announce(); + Printf("hwasan_dev_note_heap_rb_distance: %zd %zd\n", ring_index + 1, + t->IsMainThread() ? flags()->heap_history_size_main_thread + : flags()->heap_history_size); + num_descriptions_printed++; + }; + u64 record_searched = 0; + u64 record_matched = 0; hwasanThreadList().VisitAllLiveThreads([&](Thread *t) { // Scan all threads' ring buffers to find if it's a heap-use-after-free. - HeapAllocationRecord har; - uptr ring_index, num_matching_addrs, num_matching_addrs_4b; - if (FindHeapAllocation(t->heap_allocations(), tagged_addr, &har, - &ring_index, &num_matching_addrs, - &num_matching_addrs_4b)) { - Printf("%s", d.Error()); - Printf("\nCause: use-after-free\n"); - 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 T%zd here:\n", t->unique_id()); - 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(); - - // Print a developer note: the index of this heap object - // in the thread's deallocation ring buffer. - Printf("hwasan_dev_note_heap_rb_distance: %zd %zd\n", ring_index + 1, - flags()->heap_history_size); - Printf("hwasan_dev_note_num_matching_addrs: %zd\n", num_matching_addrs); - Printf("hwasan_dev_note_num_matching_addrs_4b: %zd\n", - num_matching_addrs_4b); - - t->Announce(); - num_descriptions_printed++; + auto *rb = t->heap_allocations(); + if (!rb) + return; + t->DisableTracingHeapAllocation(); + for (uptr i = 0, size = rb->realsize(); i < size; i++) { + auto h = (*rb)[i]; + record_searched++; + if (flags()->print_uaf_stacks_with_same_tag) { + if (h.tagged_addr <= tagged_addr && + h.tagged_addr + h.requested_size > tagged_addr) { + record_matched++; + PrintUAF(t, i, h); + } + } else { + uptr ha_untagged_addr = UntagAddr(h.tagged_addr); + if (ha_untagged_addr <= untagged_addr && + ha_untagged_addr + h.requested_size > untagged_addr) { + record_matched++; + PrintUAF(t, i, h); + } + } } + t->EnableTracingHeapAllocation(); }); - if (candidate && num_descriptions_printed == 0) { + Printf("Searched %lu records, find %lu with same addr %p\n\n", + record_searched, record_matched, untagged_addr); + if (!on_stack && candidate) { ShowHeapOrGlobalCandidate(untagged_addr, candidate, left, right); num_descriptions_printed++; } diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp index feb7f5c70b02..852730d5e0a6 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.cpp +++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp @@ -47,7 +47,7 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size, if (auto sz = IsMainThread() ? flags()->heap_history_size_main_thread : flags()->heap_history_size) heap_allocations_ = HeapAllocationsRingBuffer::New(sz); - + trace_heap_allocation_ = true; #if !SANITIZER_FUCHSIA // Do not initialize the stack ring buffer just yet on Fuchsia. Threads will // be initialized before we enter the thread itself, so we will instead call diff --git a/compiler-rt/lib/hwasan/hwasan_thread.h b/compiler-rt/lib/hwasan/hwasan_thread.h index 3db7c1a9454f..b7941019aa98 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.h +++ b/compiler-rt/lib/hwasan/hwasan_thread.h @@ -61,6 +61,10 @@ class Thread { void DisableTagging() { tagging_disabled_++; } void EnableTagging() { tagging_disabled_--; } + void EnableTracingHeapAllocation() { trace_heap_allocation_ = true; } + void DisableTracingHeapAllocation() { trace_heap_allocation_ = false; } + bool AllowTracingHeapAllocation() { return trace_heap_allocation_; } + u64 unique_id() const { return unique_id_; } void Announce() { if (announced_) return; @@ -97,6 +101,8 @@ class Thread { bool random_state_inited_; // Whether InitRandomState() has been called. + bool trace_heap_allocation_; + friend struct ThreadListHead; }; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_ring_buffer.h b/compiler-rt/lib/sanitizer_common/sanitizer_ring_buffer.h index f22e40cac284..3e44ca4e867b 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_ring_buffer.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_ring_buffer.h @@ -35,11 +35,17 @@ class RingBuffer { uptr size() const { return last_ + 1 - reinterpret_cast(reinterpret_cast(this) + - 2 * sizeof(T *)); + sizeof(RingBuffer) - sizeof(T)); + } + + uptr realsize() const { + if (full_) + return size(); + return reinterpret_cast((uptr)last_ - (uptr)next_) / sizeof(T); } static uptr SizeInBytes(uptr Size) { - return Size * sizeof(T) + 2 * sizeof(T*); + return Size * sizeof(T) + sizeof(RingBuffer) - sizeof(T); } uptr SizeInBytes() { return SizeInBytes(size()); } @@ -48,8 +54,10 @@ class RingBuffer { *next_ = t; next_--; // The condition below works only if sizeof(T) is divisible by sizeof(T*). - if (next_ <= reinterpret_cast(&next_)) + if (next_ <= reinterpret_cast(&next_)) { next_ = last_; + full_ = true; + } } T operator[](uptr Idx) const { @@ -66,11 +74,13 @@ class RingBuffer { RingBuffer(const RingBuffer&) = delete; // Data layout: - // LNDDDDDDDD + // FLNDDDDDDDD + // F: indicates whether the ring buffer is full // D: data elements. // L: last_, always points to the last data element. // N: next_, initially equals to last_, is decremented on every push, // wraps around if it's less or equal than its own address. + bool full_; T *last_; T *next_; T data_[1]; // flexible array. diff --git a/compiler-rt/test/hwasan/TestCases/use-after-free-and-overflow.c b/compiler-rt/test/hwasan/TestCases/use-after-free-and-overflow.c index c08b00fc35ac..2c288561b03c 100644 --- a/compiler-rt/test/hwasan/TestCases/use-after-free-and-overflow.c +++ b/compiler-rt/test/hwasan/TestCases/use-after-free-and-overflow.c @@ -58,4 +58,4 @@ int main(int argc, char **argv) { // CHECK-NOT: Cause: heap-buffer-overflow // CHECK: Cause: use-after-free -// CHECK-NOT: Cause: heap-buffer-overflow +// CHECK: Cause: heap-buffer-overflow -- Gitee From 984326a898190842355e1ec707c2dd6c0ca2cfb7 Mon Sep 17 00:00:00 2001 From: MrLop Date: Mon, 13 Jan 2025 20:55:16 +0800 Subject: [PATCH 04/11] [Huawei][HWASAN] Support HWASAN Sigchain on OHOS The hwasan signal handler function can be registered in sigchain mode on OHOS. Signed-off-by: MrLop --- .../sanitizer_posix_libcdep.cpp | 17 +++++++++++++++++ compiler-rt/test/hwasan/TestCases/stack-uar.c | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index ec874e50adc4..f192047fe950 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -36,6 +36,10 @@ #include #include +#if SANITIZER_OHOS +#include +#endif + #if SANITIZER_FREEBSD // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before // that, it was never implemented. So just define it to zero. @@ -195,6 +199,7 @@ static void MaybeInstallSigaction(int signum, SignalHandlerType handler) { if (GetHandleSignalMode(signum) == kHandleSignalNo) return; +#if !SANITIZER_OHOS struct sigaction sigact; internal_memset(&sigact, 0, sizeof(sigact)); sigact.sa_sigaction = (sa_sigaction_t)handler; @@ -204,6 +209,18 @@ static void MaybeInstallSigaction(int signum, if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; CHECK_EQ(0, internal_sigaction(signum, &sigact, nullptr)); VReport(1, "Installed the sigaction for signal %d\n", signum); +#else + typedef bool (*sc)(int, siginfo_t *, void *); + sc h = (sc)handler; + struct signal_chain_action sigchain = { + .sca_sigaction = h, + .sca_mask = {}, + .sca_flags = SA_SIGINFO | SA_NODEFER, + }; + // This is a void function for OHOS. When there are too many registered + // functions, an internal error is reported. CHECK is not required. + add_special_signal_handler(signum, &sigchain); +#endif } void InstallDeadlySignalHandlers(SignalHandlerType handler) { diff --git a/compiler-rt/test/hwasan/TestCases/stack-uar.c b/compiler-rt/test/hwasan/TestCases/stack-uar.c index 3663eac5d268..b8b103fd8532 100644 --- a/compiler-rt/test/hwasan/TestCases/stack-uar.c +++ b/compiler-rt/test/hwasan/TestCases/stack-uar.c @@ -38,14 +38,14 @@ int main() { // CHECK: is located in stack of thread // CHECK: Potentially referenced stack objects: // CHECK-NEXT: zzz in buggy {{.*}}stack-uar.c:[[@LINE-20]] - // CHECK-NEXT: Memory tags around the buggy address + // CHECK: Memory tags around the buggy address // NOSYM: Previously allocated frames: // NOSYM-NEXT: record_addr:0x{{.*}} record:0x{{.*}} ({{.*}}/stack-uar.c.tmp+0x{{.*}}){{$}} // NOSYM-NEXT: record_addr:0x{{.*}} record:0x{{.*}} ({{.*}}/stack-uar.c.tmp+0x{{.*}}){{$}} // NOSYM-NEXT: record_addr:0x{{.*}} record:0x{{.*}} ({{.*}}/stack-uar.c.tmp+0x{{.*}}){{$}} // NOSYM-NEXT: record_addr:0x{{.*}} record:0x{{.*}} ({{.*}}/stack-uar.c.tmp+0x{{.*}}){{$}} - // NOSYM-NEXT: Memory tags around the buggy address + // NOSYM: Memory tags around the buggy address // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main } -- Gitee From e0e7cf66d8287eac61ddd33c8156828861a05edc Mon Sep 17 00:00:00 2001 From: MrLop Date: Mon, 13 Jan 2025 21:02:27 +0800 Subject: [PATCH 05/11] [Huawei][HWASAN] Support HWASAN Limit Range of Record Heap Mem Size Add HWASAN flags heap_record_min/heap_record_max to set range so that only recording Heap Mem size within range. Signed-off-by: MrLop --- compiler-rt/lib/hwasan/hwasan_allocator.cpp | 12 +++++++++--- compiler-rt/lib/hwasan/hwasan_flags.inc | 12 +++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp index e8d407442f44..59da6de6b466 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp +++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp @@ -298,9 +298,15 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { if (t) { allocator.Deallocate(t->allocator_cache(), aligned_ptr); if (t->AllowTracingHeapAllocation()) { - if (auto *ha = t->heap_allocations()) - ha->push({reinterpret_cast(tagged_ptr), alloc_context_id, - free_context_id, static_cast(orig_size)}); + if (auto *ha = t->heap_allocations()) { + if ((flags()->heap_record_max == 0 || + orig_size <= flags()->heap_record_max) && + (flags()->heap_record_min == 0 || + orig_size >= flags()->heap_record_min)) { + ha->push({reinterpret_cast(tagged_ptr), alloc_context_id, + free_context_id, static_cast(orig_size)}); + } + } } } else { SpinMutexLock l(&fallback_mutex); diff --git a/compiler-rt/lib/hwasan/hwasan_flags.inc b/compiler-rt/lib/hwasan/hwasan_flags.inc index 30ae39eff9ab..191e086c69b9 100644 --- a/compiler-rt/lib/hwasan/hwasan_flags.inc +++ b/compiler-rt/lib/hwasan/hwasan_flags.inc @@ -90,4 +90,14 @@ HWASAN_FLAG(bool, fail_without_syscall_abi, true, HWASAN_FLAG( bool, print_uaf_stacks_with_same_tag, true, "Control the output content of use-after-free, deciding whether to print " - "all stack traces of matched allocations with the same tag restriction.") \ No newline at end of file + "all stack traces of matched allocations with the same tag restriction.") + +// Limits the size of the heap memory allocated to be recorded in order to +// reduce the data. As a result, information may be missing. By default, the +// minimum/maximum threshold is not set. +HWASAN_FLAG(int, heap_record_min, 0, + "Only recording the heap memory allocation information that is >= " + "heap_record_min.") +HWASAN_FLAG(int, heap_record_max, 0, + "Only recording the heap memory allocation information that is <= " + "heap_record_max.") \ No newline at end of file -- Gitee From 7f1ef9fc0e505ecb0a1ce5cebdb1855068f7f15b Mon Sep 17 00:00:00 2001 From: MrLop Date: Tue, 14 Jan 2025 10:14:52 +0800 Subject: [PATCH 06/11] [Huawei][HWASAN] Support HWASAN Record Info of Thread ID in System Signed-off-by: MrLop --- compiler-rt/lib/hwasan/hwasan_allocator.cpp | 14 +++++++++- compiler-rt/lib/hwasan/hwasan_allocator.h | 4 +++ compiler-rt/lib/hwasan/hwasan_report.cpp | 26 ++++++++++--------- compiler-rt/lib/hwasan/hwasan_thread.cpp | 7 ++--- compiler-rt/lib/hwasan/hwasan_thread.h | 9 +++---- .../test/hwasan/TestCases/rich-stack.c | 2 +- .../test/hwasan/TestCases/thread-uaf.c | 6 ++--- .../test/hwasan/TestCases/wild-free-close.c | 2 +- .../test/hwasan/TestCases/wild-free-realloc.c | 2 +- .../test/hwasan/TestCases/wild-free-shadow.c | 2 +- compiler-rt/test/hwasan/TestCases/wild-free.c | 2 +- 11 files changed, 47 insertions(+), 29 deletions(-) diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp index 59da6de6b466..7e60d3daca08 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp +++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp @@ -53,6 +53,12 @@ static uptr AlignRight(uptr addr, uptr requested_size) { return addr + kShadowAlignment - tail_size; } +int HwasanChunkView::AllocatedByThread() const { + if (metadata_) + return metadata_->thread_id; + return -1; +} + uptr HwasanChunkView::Beg() const { if (metadata_ && metadata_->right_aligned) return AlignRight(block_, metadata_->get_requested_size()); @@ -160,6 +166,10 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment, meta->set_requested_size(orig_size); meta->alloc_context_id = StackDepotPut(*stack); meta->right_aligned = false; + if (t) + meta->thread_id = t->tid(); + else + meta->thread_id = -1; if (zeroise) { internal_memset(allocated, 0, size); } else if (flags()->max_malloc_fill_size > 0) { @@ -295,6 +305,8 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { TagMemoryAligned(reinterpret_cast(aligned_ptr), TaggedSize(orig_size), tag); } + + int aid = meta->thread_id; if (t) { allocator.Deallocate(t->allocator_cache(), aligned_ptr); if (t->AllowTracingHeapAllocation()) { @@ -304,7 +316,7 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { (flags()->heap_record_min == 0 || orig_size >= flags()->heap_record_min)) { ha->push({reinterpret_cast(tagged_ptr), alloc_context_id, - free_context_id, static_cast(orig_size)}); + free_context_id, static_cast(orig_size), aid, t->tid()}); } } } diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.h b/compiler-rt/lib/hwasan/hwasan_allocator.h index 35c3d6b4bf43..4681c17ff7ab 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocator.h +++ b/compiler-rt/lib/hwasan/hwasan_allocator.h @@ -35,6 +35,7 @@ struct Metadata { u32 requested_size_high : 31; u32 right_aligned : 1; u32 alloc_context_id; + int thread_id; u64 get_requested_size() { return (static_cast(requested_size_high) << 32) + requested_size_low; } @@ -88,6 +89,7 @@ class HwasanChunkView { uptr ActualSize() const; // Size allocated by the allocator. u32 GetAllocStackId() const; bool FromSmallHeap() const; + int AllocatedByThread() const; private: uptr block_; Metadata *const metadata_; @@ -104,6 +106,8 @@ struct HeapAllocationRecord { u32 alloc_context_id; u32 free_context_id; u32 requested_size; + int alloc_thread; + int free_thread; }; typedef RingBuffer HeapAllocationsRingBuffer; diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp index 36dec60ebb16..eb27371c8d48 100644 --- a/compiler-rt/lib/hwasan/hwasan_report.cpp +++ b/compiler-rt/lib/hwasan/hwasan_report.cpp @@ -347,12 +347,13 @@ void PrintAddressDescription( if (uptr beg = chunk.Beg()) { uptr size = chunk.ActualSize(); Printf("%s[%p,%p) is a %s %s heap chunk; " - "size: %zd offset: %zd\n%s", + "size: %zd offset: %zd, Allocated By %u\n%s", d.Location(), beg, beg + size, chunk.FromSmallHeap() ? "small" : "large", chunk.IsAllocated() ? "allocated" : "unallocated", size, untagged_addr - beg, + chunk.AllocatedByThread(), d.Default()); if (chunk.IsAllocated() && chunk.GetAllocStackId()) { Printf("%s", d.Allocation()); @@ -375,8 +376,8 @@ void PrintAddressDescription( Printf("%s", d.Error()); Printf("\nCause: stack tag-mismatch\n"); Printf("%s", d.Location()); - Printf("Address %p is located in stack of thread T%zd\n", untagged_addr, - t->unique_id()); + Printf("Address %p is located in stack of thread %d\n", untagged_addr, + t->tid()); Printf("%s", d.Default()); t->Announce(); @@ -430,18 +431,19 @@ void PrintAddressDescription( untagged_addr - ha_untagged_addr, har.requested_size, ha_untagged_addr, ha_untagged_addr + har.requested_size); Printf("%s", d.Allocation()); - Printf("freed by thread T%zd here:\n", t->unique_id()); + Printf("freed by thread %d here:\n", t->tid()); Printf("%s", d.Default()); GetStackTraceFromId(har.free_context_id).Print(); Printf("%s", d.Allocation()); - Printf("previously allocated here:\n", t); + Printf("previously allocated by thread %d here:\n", har.alloc_thread); Printf("%s", d.Default()); GetStackTraceFromId(har.alloc_context_id).Print(); - t->Announce(); + Printf("hwasan_dev_note_heap_rb_distance: %zd %zd\n", ring_index + 1, t->IsMainThread() ? flags()->heap_history_size_main_thread : flags()->heap_history_size); + t->Announce(); num_descriptions_printed++; }; u64 record_searched = 0; @@ -571,8 +573,8 @@ void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) { const char *bug_type = "invalid-free"; const Thread *thread = GetCurrentThread(); if (thread) { - Report("ERROR: %s: %s on address %p at pc %p on thread T%zd\n", - SanitizerToolName, bug_type, untagged_addr, pc, thread->unique_id()); + Report("ERROR: %s: %s on address %p at pc %p on thread %d\n", + SanitizerToolName, bug_type, untagged_addr, pc, thread->tid()); } else { Report("ERROR: %s: %s on address %p at pc %p on unknown thread\n", SanitizerToolName, bug_type, untagged_addr, pc); @@ -708,13 +710,13 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size, } } Printf( - "%s of size %zu at %p tags: %02x/%02x(%02x) (ptr/mem) in thread T%zd\n", + "%s of size %zu at %p tags: %02x/%02x(%02x) (ptr/mem) in thread %d\n", is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag, - mem_tag, short_tag, t->unique_id()); + mem_tag, short_tag, t->tid()); } else { - Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem) in thread T%zd\n", + Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem) in thread %d\n", is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag, - mem_tag, t->unique_id()); + mem_tag, t->tid()); } if (offset != 0) Printf("Invalid access starting at offset %zu\n", offset); diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp index 852730d5e0a6..aa007561117e 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.cpp +++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp @@ -55,6 +55,7 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size, InitStackRingBuffer(stack_buffer_start, stack_buffer_size); #endif InitStackAndTls(state); + tid_ = GetTid(); } void Thread::InitStackRingBuffer(uptr stack_buffer_start, @@ -111,9 +112,9 @@ void Thread::Destroy() { } void Thread::Print(const char *Prefix) { - Printf("%sT%zd %p stack: [%p,%p) sz: %zd tls: [%p,%p)\n", Prefix, unique_id_, - (void *)this, stack_bottom(), stack_top(), - stack_top() - stack_bottom(), tls_begin(), tls_end()); + Printf("%sT%zd %p stack: [%p,%p) sz: %zd tls: [%p,%p) tid: %d\n", Prefix, + unique_id_, (void *)this, stack_bottom(), stack_top(), + stack_top() - stack_bottom(), tls_begin(), tls_end(), tid_); } static u32 xorshift(u32 state) { diff --git a/compiler-rt/lib/hwasan/hwasan_thread.h b/compiler-rt/lib/hwasan/hwasan_thread.h index b7941019aa98..67b014cdee6b 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.h +++ b/compiler-rt/lib/hwasan/hwasan_thread.h @@ -66,11 +66,8 @@ class Thread { bool AllowTracingHeapAllocation() { return trace_heap_allocation_; } u64 unique_id() const { return unique_id_; } - void Announce() { - if (announced_) return; - announced_ = true; - Print("Thread: "); - } + int tid() const { return tid_; } + void Announce() { Print("Thread: "); } uptr &vfork_spill() { return vfork_spill_; } @@ -103,6 +100,8 @@ class Thread { bool trace_heap_allocation_; + int tid_ = -1; // Thread ID + friend struct ThreadListHead; }; diff --git a/compiler-rt/test/hwasan/TestCases/rich-stack.c b/compiler-rt/test/hwasan/TestCases/rich-stack.c index c6c2f9bca669..c7403c6156c2 100644 --- a/compiler-rt/test/hwasan/TestCases/rich-stack.c +++ b/compiler-rt/test/hwasan/TestCases/rich-stack.c @@ -64,4 +64,4 @@ int main(int argc, char **argv) { // R321: in BAR // R321-NEXT: in FOO // R321-NEXT: in main -// R321: is located in stack of thread T0 +// R321: is located in stack of thread {{.*}} diff --git a/compiler-rt/test/hwasan/TestCases/thread-uaf.c b/compiler-rt/test/hwasan/TestCases/thread-uaf.c index c368882f4589..1a2bd7e8efeb 100644 --- a/compiler-rt/test/hwasan/TestCases/thread-uaf.c +++ b/compiler-rt/test/hwasan/TestCases/thread-uaf.c @@ -28,12 +28,12 @@ void *Deallocate(void *arg) { void *Use(void *arg) { x[5] = 42; // CHECK: ERROR: HWAddressSanitizer: tag-mismatch on address - // CHECK: WRITE of size 1 {{.*}} in thread T3 + // CHECK: WRITE of size 1 {{.*}} in thread {{.*}} // CHECK: thread-uaf.c:[[@LINE-3]] // CHECK: Cause: use-after-free - // CHECK: freed by thread T2 here + // CHECK: freed by thread {{.*}} here // CHECK: in Deallocate - // CHECK: previously allocated here: + // CHECK: previously allocated by thread {{.*}} here: // CHECK: in Allocate // CHECK-DAG: Thread: T2 0x // CHECK-DAG: Thread: T3 0x diff --git a/compiler-rt/test/hwasan/TestCases/wild-free-close.c b/compiler-rt/test/hwasan/TestCases/wild-free-close.c index 51eb949dcdc9..c23b60739345 100644 --- a/compiler-rt/test/hwasan/TestCases/wild-free-close.c +++ b/compiler-rt/test/hwasan/TestCases/wild-free-close.c @@ -11,7 +11,7 @@ int main() { fprintf(stderr, "ALLOC %p\n", __hwasan_tag_pointer(p, 0)); // CHECK: ALLOC {{[0x]+}}[[ADDR:.*]] free(p - 8); - // CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread T{{[0-9]+}} + // CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread {{.*}} // CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in {{.*}}free // CHECK: #1 {{.*}} in main {{.*}}wild-free-close.c:[[@LINE-3]] // CHECK: is located 8 bytes to the left of 1-byte region [{{[0x]+}}{{.*}}[[ADDR]] diff --git a/compiler-rt/test/hwasan/TestCases/wild-free-realloc.c b/compiler-rt/test/hwasan/TestCases/wild-free-realloc.c index 19d2943e4c51..ab28b88c6104 100644 --- a/compiler-rt/test/hwasan/TestCases/wild-free-realloc.c +++ b/compiler-rt/test/hwasan/TestCases/wild-free-realloc.c @@ -7,7 +7,7 @@ int main() { __hwasan_enable_allocator_tagging(); char *p = (char *)malloc(1); realloc(p + 0x10000000000, 2); - // CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread T{{[0-9]+}} + // CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread {{.*}} // CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in {{.*}}realloc // CHECK: #1 {{.*}} in main {{.*}}wild-free-realloc.c:[[@LINE-3]] // CHECK-NOT: Segmentation fault diff --git a/compiler-rt/test/hwasan/TestCases/wild-free-shadow.c b/compiler-rt/test/hwasan/TestCases/wild-free-shadow.c index 7810e26dfffd..7e4edc163e6b 100644 --- a/compiler-rt/test/hwasan/TestCases/wild-free-shadow.c +++ b/compiler-rt/test/hwasan/TestCases/wild-free-shadow.c @@ -7,7 +7,7 @@ extern void *__hwasan_shadow_memory_dynamic_address; int main() { char *p = (char *)malloc(1); free(__hwasan_shadow_memory_dynamic_address); - // CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{[0x]+}}[[PTR:.*]] at pc {{[0x]+}}[[PC:.*]] on thread T{{[0-9]+}} + // CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{[0x]+}}[[PTR:.*]] at pc {{[0x]+}}[[PC:.*]] on thread {{.*}} // CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in {{.*}}free // CHECK: #1 {{.*}} in main {{.*}}wild-free-shadow.c:[[@LINE-3]] // CHECK: {{[0x]+}}{{.*}}[[PTR]] is HWAsan shadow memory. diff --git a/compiler-rt/test/hwasan/TestCases/wild-free.c b/compiler-rt/test/hwasan/TestCases/wild-free.c index a38822c2f860..5110170da446 100644 --- a/compiler-rt/test/hwasan/TestCases/wild-free.c +++ b/compiler-rt/test/hwasan/TestCases/wild-free.c @@ -7,7 +7,7 @@ int main() { __hwasan_enable_allocator_tagging(); char *p = (char *)malloc(1); free(p + 0x10000000000); - // CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread T{{[0-9]+}} + // CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread {{.*}} // CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in {{.*}}free // CHECK: #1 {{.*}} in main {{.*}}wild-free.c:[[@LINE-3]] // CHECK-NOT: Segmentation fault -- Gitee From 95a0baa9c14f5308c4880f9170b14415fd340b43 Mon Sep 17 00:00:00 2001 From: MrLop Date: Tue, 14 Jan 2025 10:26:18 +0800 Subject: [PATCH 07/11] [Huawei][HWASAN] Support HWASAN Thread Record More Info Recording the amount of information allocated to threads is added. Can be printed using Thread::Print. Signed-off-by: MrLop --- compiler-rt/lib/hwasan/hwasan_thread.cpp | 12 +++++++++--- compiler-rt/lib/hwasan/hwasan_thread.h | 10 ++++++++++ .../lib/sanitizer_common/sanitizer_ring_buffer.h | 1 + 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp index aa007561117e..b576b9a119ba 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.cpp +++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp @@ -112,9 +112,15 @@ void Thread::Destroy() { } void Thread::Print(const char *Prefix) { - Printf("%sT%zd %p stack: [%p,%p) sz: %zd tls: [%p,%p) tid: %d\n", Prefix, - unique_id_, (void *)this, stack_bottom(), stack_top(), - stack_top() - stack_bottom(), tls_begin(), tls_end(), tid_); + Printf( + "%sT%zd %p stack: [%p,%p) sz: %zd tls: [%p,%p) rb:(%zd/%u) " + "records(%llu/o:%llu) tid: %d\n", + Prefix, unique_id_, (void *)this, stack_bottom(), stack_top(), + stack_top() - stack_bottom(), tls_begin(), tls_end(), + heap_allocations() ? heap_allocations()->realsize() : 0, + IsMainThread() ? flags()->heap_history_size_main_thread + : flags()->heap_history_size, + all_record_count_, all_record_count_overflow_, tid_); } static u32 xorshift(u32 state) { diff --git a/compiler-rt/lib/hwasan/hwasan_thread.h b/compiler-rt/lib/hwasan/hwasan_thread.h index 67b014cdee6b..1e1b3fed6f2d 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.h +++ b/compiler-rt/lib/hwasan/hwasan_thread.h @@ -48,6 +48,13 @@ class Thread { uptr tls_end() { return tls_end_; } bool IsMainThread() { return unique_id_ == 0; } + void inc_record(void) { + all_record_count_++; + if (all_record_count_ == 0) { + all_record_count_overflow_++; + } + } + bool AddrIsInStack(uptr addr) { return addr >= stack_bottom_ && addr < stack_top_; } @@ -102,6 +109,9 @@ class Thread { int tid_ = -1; // Thread ID + u64 all_record_count_ = 0; // Count record + u64 all_record_count_overflow_ = 0; // Whether all_record_count_ overflow. + friend struct ThreadListHead; }; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_ring_buffer.h b/compiler-rt/lib/sanitizer_common/sanitizer_ring_buffer.h index 3e44ca4e867b..6cf3c0d25513 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_ring_buffer.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_ring_buffer.h @@ -27,6 +27,7 @@ class RingBuffer { RingBuffer *RB = reinterpret_cast(Ptr); uptr End = reinterpret_cast(Ptr) + SizeInBytes(Size); RB->last_ = RB->next_ = reinterpret_cast(End - sizeof(T)); + RB->full_ = false; return RB; } void Delete() { -- Gitee From d2884bd010d7f5d3850921b411360cb8d50e8e7b Mon Sep 17 00:00:00 2001 From: MrLop Date: Tue, 14 Jan 2025 14:50:22 +0800 Subject: [PATCH 08/11] [Huawei][HWASAN] Don't Release Heap Alloc Info When Thread Is Freed Don't release heap alloc info when thread is freed. When a thread is freed, copy its heap allocation information to the public list. Signed-off-by: MrLop --- compiler-rt/lib/hwasan/hwasan_allocator.cpp | 11 +++ compiler-rt/lib/hwasan/hwasan_flags.inc | 6 ++ compiler-rt/lib/hwasan/hwasan_report.cpp | 43 ++++++++++ compiler-rt/lib/hwasan/hwasan_thread_list.h | 92 +++++++++++++++++++++ 4 files changed, 152 insertions(+) diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp index 7e60d3daca08..7d76e46c61a5 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp +++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp @@ -20,6 +20,7 @@ #include "hwasan_mapping.h" #include "hwasan_malloc_bisect.h" #include "hwasan_thread.h" +#include "hwasan_thread_list.h" #include "hwasan_report.h" namespace __hwasan { @@ -323,6 +324,16 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { } else { SpinMutexLock l(&fallback_mutex); AllocatorCache *cache = &fallback_allocator_cache; + if (hwasanThreadList().AllowTracingHeapAllocation()) { + if ((flags()->heap_record_max == 0 || + orig_size <= flags()->heap_record_max) && + (flags()->heap_record_min == 0 || + orig_size >= flags()->heap_record_min)) { + hwasanThreadList().RecordFallBack( + {reinterpret_cast(tagged_ptr), alloc_context_id, + free_context_id, static_cast(orig_size), aid, 0}); + } + } allocator.Deallocate(cache, aligned_ptr); } } diff --git a/compiler-rt/lib/hwasan/hwasan_flags.inc b/compiler-rt/lib/hwasan/hwasan_flags.inc index 191e086c69b9..2d7b2ac9ba38 100644 --- a/compiler-rt/lib/hwasan/hwasan_flags.inc +++ b/compiler-rt/lib/hwasan/hwasan_flags.inc @@ -92,6 +92,12 @@ HWASAN_FLAG( "Control the output content of use-after-free, deciding whether to print " "all stack traces of matched allocations with the same tag restriction.") +// Heap allocation information for freed threads +HWASAN_FLAG(uptr, freed_threads_history_size, 100, + "The number of freed threads can be recorded.") +HWASAN_FLAG(bool, verbose_freed_threads, false, + "Print the heap allocation information of freed threads.") + // Limits the size of the heap memory allocated to be recorded in order to // reduce the data. As a result, information may be missing. By default, the // minimum/maximum threshold is not set. diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp index eb27371c8d48..aeef8334a632 100644 --- a/compiler-rt/lib/hwasan/hwasan_report.cpp +++ b/compiler-rt/lib/hwasan/hwasan_report.cpp @@ -475,6 +475,41 @@ void PrintAddressDescription( t->EnableTracingHeapAllocation(); }); + auto PrintUAFinFreedThread = [&](HeapAllocationRecord &har) { + uptr ha_untagged_addr = UntagAddr(har.tagged_addr); + Printf( + "%p (Previously freed thread ptr tags: %02x) is located %zd " + "bytes inside of %zd-byte region [%p,%p)\n", + untagged_addr, GetTagFromPointer(har.tagged_addr), + untagged_addr - ha_untagged_addr, har.requested_size, ha_untagged_addr, + ha_untagged_addr + har.requested_size); + Printf("freed by thread %d here:\n", har.free_thread); + GetStackTraceFromId(har.free_context_id).Print(); + Printf("previously allocated by thread %d here:\n", har.alloc_thread); + GetStackTraceFromId(har.alloc_context_id).Print(); + num_descriptions_printed++; + }; + hwasanThreadList().VisitAllFreedRingBuffer( + [&](HeapAllocationsRingBuffer *rb) { + for (uptr i = 0, size = rb->realsize(); i < size; i++) { + auto har = (*rb)[i]; + record_searched++; + if (flags()->print_uaf_stacks_with_same_tag) { + if (har.tagged_addr <= tagged_addr && + har.tagged_addr + har.requested_size > tagged_addr) { + record_matched++; + PrintUAFinFreedThread(har); + } + } else { + if (UntagAddr(har.tagged_addr) <= untagged_addr && + UntagAddr(har.tagged_addr) + har.requested_size > + untagged_addr) { + record_matched++; + PrintUAFinFreedThread(har); + } + } + } + }); Printf("Searched %lu records, find %lu with same addr %p\n\n", record_searched, record_matched, untagged_addr); if (!on_stack && candidate) { @@ -484,6 +519,14 @@ void PrintAddressDescription( // Print the remaining threads, as an extra information, 1 line per thread. hwasanThreadList().VisitAllLiveThreads([&](Thread *t) { t->Announce(); }); + hwasanThreadList().PrintFreedRingBufferSummary(); + if (flags()->verbose_freed_threads) { + u32 freed_idx = 0; + hwasanThreadList().VisitAllFreedRingBuffer( + [&](HeapAllocationsRingBuffer *rb) { + Printf("RB %u: (%zd/%zu)\n", freed_idx++, rb->realsize(), rb->size()); + }); + } if (!num_descriptions_printed) // We exhausted our possibilities. Bail out. diff --git a/compiler-rt/lib/hwasan/hwasan_thread_list.h b/compiler-rt/lib/hwasan/hwasan_thread_list.h index 15916a802d6e..7792e1e5fcef 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread_list.h +++ b/compiler-rt/lib/hwasan/hwasan_thread_list.h @@ -83,6 +83,14 @@ class HwasanThreadList { ring_buffer_size_ = RingBufferSize(); thread_alloc_size_ = RoundUpTo(ring_buffer_size_ + sizeof(Thread), ring_buffer_size_ * 2); + freed_rb_fallback_ = + HeapAllocationsRingBuffer::New(flags()->heap_history_size_main_thread); + + freed_rb_list_ = nullptr; + freed_rb_list_size_ = 0; + freed_rb_count_ = 0; + freed_rb_count_overflow_ = 0; + trace_heap_allocation_ = true; } Thread *CreateCurrentThread(const Thread::InitState *state = nullptr) { @@ -127,7 +135,53 @@ class HwasanThreadList { CHECK(0 && "thread not found in live list"); } + void AddFreedRingBuffer(Thread *t) { + if (t->heap_allocations() == nullptr || + t->heap_allocations()->realsize() == 0) + return; + + SpinMutexLock l(&freed_rb_mutex_); + if (!freed_rb_list_) { + size_t sz = flags()->freed_threads_history_size * + sizeof(HeapAllocationsRingBuffer *); + freed_rb_list_ = reinterpret_cast( + MmapOrDie(sz, "FreedRingBufferList")); + if (UNLIKELY(freed_rb_list_ == nullptr)) { + return; + } + } + if (freed_rb_list_size_ >= flags()->freed_threads_history_size) { + auto sz = flags()->freed_threads_history_size / 3; + for (uptr i = 0; i < sz; i++) { + if (freed_rb_list_[i]) + freed_rb_list_[i]->Delete(); + } + auto left = flags()->freed_threads_history_size - sz; + for (uptr i = 0; i < left; i++) { + freed_rb_list_[i] = freed_rb_list_[i + sz]; + } + freed_rb_list_size_ = left; + } + HeapAllocationsRingBuffer *freed_allocations_; + freed_allocations_ = HeapAllocationsRingBuffer::New( + t->IsMainThread() ? flags()->heap_history_size_main_thread + : flags()->heap_history_size); + + HeapAllocationsRingBuffer *rb = t->heap_allocations(); + for (uptr i = 0, size = rb->realsize(); i < size; i++) { + HeapAllocationRecord h = (*rb)[i]; + freed_allocations_->push({h.tagged_addr, h.alloc_context_id, + h.free_context_id, h.requested_size}); + } + freed_rb_list_[freed_rb_list_size_] = freed_allocations_; + freed_rb_list_size_++; + freed_rb_count_++; + if (freed_rb_count_ == 0) + freed_rb_count_overflow_++; + } + void ReleaseThread(Thread *t) { + AddFreedRingBuffer(t); RemoveThreadStats(t); t->Destroy(); DontNeedThread(t); @@ -154,6 +208,26 @@ class HwasanThreadList { for (Thread *t : live_list_) cb(t); } + template + void VisitAllFreedRingBuffer(CB cb) { + DisableTracingHeapAllocation(); + SpinMutexLock l(&freed_rb_mutex_); + for (size_t i = 0; i < freed_rb_list_size_; i++) { + cb(freed_rb_list_[i]); + } + if (freed_rb_fallback_) + cb(freed_rb_fallback_); + EnableTracingHeapAllocation(); + } + + void PrintFreedRingBufferSummary(void) { + SpinMutexLock l(&freed_rb_mutex_); + Printf("freed thread count: %llu, overflow %llu, %zd left\n", + freed_rb_count_, freed_rb_count_overflow_, freed_rb_list_size_); + if (freed_rb_fallback_) + Printf("fallback count: %llu\n", freed_rb_fallback_->realsize()); + } + void AddThreadStats(Thread *t) { SpinMutexLock l(&stats_mutex_); stats_.n_live_threads++; @@ -173,6 +247,16 @@ class HwasanThreadList { uptr GetRingBufferSize() const { return ring_buffer_size_; } + void RecordFallBack(HeapAllocationRecord h) { + SpinMutexLock l(&freed_rb_mutex_); + if (freed_rb_fallback_) + freed_rb_fallback_->push(h); + } + + void EnableTracingHeapAllocation() { trace_heap_allocation_ = true; } + void DisableTracingHeapAllocation() { trace_heap_allocation_ = false; } + bool AllowTracingHeapAllocation() { return trace_heap_allocation_; } + private: Thread *AllocThread() { SpinMutexLock l(&free_space_mutex_); @@ -195,6 +279,14 @@ class HwasanThreadList { SpinMutex live_list_mutex_; InternalMmapVector live_list_; + SpinMutex freed_rb_mutex_; + HeapAllocationsRingBuffer **freed_rb_list_; + HeapAllocationsRingBuffer *freed_rb_fallback_; + size_t freed_rb_list_size_; + u64 freed_rb_count_; + u64 freed_rb_count_overflow_; + bool trace_heap_allocation_; + ThreadStats stats_; SpinMutex stats_mutex_; }; -- Gitee From 39240d7ab44bee9381219166774ba93c6db95031 Mon Sep 17 00:00:00 2001 From: MrLop Date: Tue, 14 Jan 2025 15:30:41 +0800 Subject: [PATCH 09/11] [Huawei][HWASAN] Print Memory Around Register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When reporting, the memory content of the address in register ±memory_around_register_size is printed. Signed-off-by: MrLop --- compiler-rt/lib/hwasan/hwasan_flags.inc | 6 ++- compiler-rt/lib/hwasan/hwasan_report.cpp | 48 +++++++++++++++++++++++- compiler-rt/lib/hwasan/hwasan_report.h | 5 ++- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/compiler-rt/lib/hwasan/hwasan_flags.inc b/compiler-rt/lib/hwasan/hwasan_flags.inc index 2d7b2ac9ba38..5dd1cdecd054 100644 --- a/compiler-rt/lib/hwasan/hwasan_flags.inc +++ b/compiler-rt/lib/hwasan/hwasan_flags.inc @@ -106,4 +106,8 @@ HWASAN_FLAG(int, heap_record_min, 0, "heap_record_min.") HWASAN_FLAG(int, heap_record_max, 0, "Only recording the heap memory allocation information that is <= " - "heap_record_max.") \ No newline at end of file + "heap_record_max.") + +HWASAN_FLAG(int, memory_around_register_size, 128, + "When reporting, the memory content of the address in register " + "±memory_around_register_size is printed.") \ No newline at end of file diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp index aeef8334a632..ac893e962367 100644 --- a/compiler-rt/lib/hwasan/hwasan_report.cpp +++ b/compiler-rt/lib/hwasan/hwasan_report.cpp @@ -773,12 +773,58 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size, PrintTagsAroundAddr(tag_ptr); - if (registers_frame) + if (registers_frame) { ReportRegisters(registers_frame, pc); + ReportMemoryNearRegisters(registers_frame, pc); + } ReportErrorSummary(bug_type, stack); } +void PrintMemoryAroundAddress(MemoryMappingLayout &proc_maps, int reg_num, + uptr addr, uptr len, bool is_pc) { + const sptr kBufSize = 4095; + char *filename = (char *)MmapOrDie(kBufSize, __func__); + MemoryMappedSegment segment(filename, kBufSize); + while (proc_maps.Next(&segment)) { + if (segment.start <= addr && addr < segment.end && segment.IsReadable()) { + if (!is_pc) { + if (reg_num < 31) + Printf("x%d(%s):\n", reg_num, segment.filename); + else + Printf("sp(%s):\n", segment.filename); + } else { + Printf("pc(%s):\n", segment.filename); + } + uptr beg = RoundDownTo(addr - (addr < len ? addr : len), 8); + if (segment.start > beg) + beg = segment.start; + uptr end = RoundUpTo(addr + len, 8); + if (segment.end < end) + end = segment.end; + for (uptr pos = beg; pos < end; pos += 8) { + if (pos <= addr && addr < pos + 8) + Printf("==>\t\t%p %016llx\n", pos, *(uptr *)(pos)); + else + Printf("\t\t%p %016llx\n", pos, *(uptr *)(pos)); + } + break; + } + } +} + +void ReportMemoryNearRegisters(uptr *frame, uptr pc) { + Printf("Memory near registers:\n"); + MemoryMappingLayout proc_maps(/*cache_enabled*/ true); + for (int i = 0; i <= 31; ++i) { + PrintMemoryAroundAddress(proc_maps, i, UntagAddr(frame[i]), + flags()->memory_around_register_size); + proc_maps.Reset(); + } + PrintMemoryAroundAddress(proc_maps, -1, pc, + flags()->memory_around_register_size, true); +} + // See the frame breakdown defined in __hwasan_tag_mismatch (from // hwasan_tag_mismatch_aarch64.S). void ReportRegisters(uptr *frame, uptr pc) { diff --git a/compiler-rt/lib/hwasan/hwasan_report.h b/compiler-rt/lib/hwasan/hwasan_report.h index de86c38fc01f..3fd9603a87da 100644 --- a/compiler-rt/lib/hwasan/hwasan_report.h +++ b/compiler-rt/lib/hwasan/hwasan_report.h @@ -16,6 +16,7 @@ #define HWASAN_REPORT_H #include "sanitizer_common/sanitizer_internal_defs.h" +#include "sanitizer_common/sanitizer_procmaps.h" #include "sanitizer_common/sanitizer_stacktrace.h" namespace __hwasan { @@ -27,9 +28,11 @@ void ReportInvalidFree(StackTrace *stack, uptr addr); void ReportTailOverwritten(StackTrace *stack, uptr addr, uptr orig_size, const u8 *expected); void ReportRegisters(uptr *registers_frame, uptr pc); +void ReportMemoryNearRegisters(uptr *registers_frame, uptr pc); +void PrintMemoryAroundAddress(MemoryMappingLayout &proc_maps, int reg_num, + uptr addr, uptr len, bool is_pc = false); void ReportAtExitStatistics(); - } // namespace __hwasan #endif // HWASAN_REPORT_H -- Gitee From 3c6e8e2731ad85f4eca025c52dd46af222ce115b Mon Sep 17 00:00:00 2001 From: MrLop Date: Tue, 14 Jan 2025 17:12:30 +0800 Subject: [PATCH 10/11] [Huawei][HWASAN] Provide allocation quarantine ability Signed-off-by: MrLop --- compiler-rt/lib/hwasan/CMakeLists.txt | 2 + compiler-rt/lib/hwasan/hwasan_allocator.cpp | 12 +- compiler-rt/lib/hwasan/hwasan_allocator.h | 2 + compiler-rt/lib/hwasan/hwasan_flags.inc | 34 +++-- compiler-rt/lib/hwasan/hwasan_quarantine.cpp | 117 ++++++++++++++++++ compiler-rt/lib/hwasan/hwasan_quarantine.h | 49 ++++++++ compiler-rt/lib/hwasan/hwasan_thread.cpp | 8 ++ compiler-rt/lib/hwasan/hwasan_thread.h | 9 ++ .../lib/sanitizer_common/sanitizer_common.h | 1 + .../lib/sanitizer_common/sanitizer_printf.cpp | 6 + 10 files changed, 227 insertions(+), 13 deletions(-) create mode 100644 compiler-rt/lib/hwasan/hwasan_quarantine.cpp create mode 100644 compiler-rt/lib/hwasan/hwasan_quarantine.h diff --git a/compiler-rt/lib/hwasan/CMakeLists.txt b/compiler-rt/lib/hwasan/CMakeLists.txt index 9082f60058ee..5879080cedef 100644 --- a/compiler-rt/lib/hwasan/CMakeLists.txt +++ b/compiler-rt/lib/hwasan/CMakeLists.txt @@ -14,6 +14,7 @@ set(HWASAN_RTL_SOURCES hwasan_linux.cpp hwasan_memintrinsics.cpp hwasan_poisoning.cpp + hwasan_quarantine.cpp hwasan_report.cpp hwasan_setjmp_aarch64.S hwasan_setjmp_x86_64.S @@ -42,6 +43,7 @@ set(HWASAN_RTL_HEADERS hwasan_malloc_bisect.h hwasan_mapping.h hwasan_poisoning.h + hwasan_quarantine.h hwasan_report.h hwasan_thread.h hwasan_thread_list.h diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp index 7d76e46c61a5..44433a07938d 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp +++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp @@ -87,6 +87,12 @@ void GetAllocatorStats(AllocatorStatCounters s) { allocator.GetStats(s); } +void SimpleThreadDeallocate(void *ptr, AllocatorCache *cache) { + CHECK(ptr); + CHECK(cache); + allocator.Deallocate(cache, ptr); +} + uptr GetAliasRegionStart() { #if defined(HWASAN_ALIASING_MODE) constexpr uptr kAliasRegionOffset = 1ULL << (kTaggableRegionCheckShift - 1); @@ -309,7 +315,11 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { int aid = meta->thread_id; if (t) { - allocator.Deallocate(t->allocator_cache(), aligned_ptr); + if (!t->TryPutInQuarantineWithDealloc(reinterpret_cast(aligned_ptr), + TaggedSize(orig_size), + alloc_context_id, free_context_id)) { + allocator.Deallocate(t->allocator_cache(), aligned_ptr); + } if (t->AllowTracingHeapAllocation()) { if (auto *ha = t->heap_allocations()) { if ((flags()->heap_record_max == 0 || diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.h b/compiler-rt/lib/hwasan/hwasan_allocator.h index 4681c17ff7ab..1510395bf6f2 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocator.h +++ b/compiler-rt/lib/hwasan/hwasan_allocator.h @@ -114,6 +114,8 @@ typedef RingBuffer HeapAllocationsRingBuffer; void GetAllocatorStats(AllocatorStatCounters s); +void SimpleThreadDeallocate(void *ptr, AllocatorCache *cache); + inline bool InTaggableRegion(uptr addr) { #if defined(HWASAN_ALIASING_MODE) // Aliases are mapped next to shadow so that the upper bits match the shadow diff --git a/compiler-rt/lib/hwasan/hwasan_flags.inc b/compiler-rt/lib/hwasan/hwasan_flags.inc index 5dd1cdecd054..efbebff62617 100644 --- a/compiler-rt/lib/hwasan/hwasan_flags.inc +++ b/compiler-rt/lib/hwasan/hwasan_flags.inc @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// #ifndef HWASAN_FLAG -# error "Define HWASAN_FLAG prior to including this file!" +# error "Define HWASAN_FLAG prior to including this file!" #endif // HWASAN_FLAG(Type, Name, DefaultValue, Description) @@ -38,21 +38,20 @@ HWASAN_FLAG( "bytes that will be filled with malloc_fill_byte on malloc.") 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") + "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 " "bytes that will be filled with free_fill_byte during free.") HWASAN_FLAG(int, malloc_fill_byte, 0xbe, - "Value used to fill the newly allocated memory.") -HWASAN_FLAG(int, free_fill_byte, 0x55, - "Value used to fill deallocated memory.") + "Value used to fill the newly allocated memory.") +HWASAN_FLAG(int, free_fill_byte, 0x55, "Value used to fill deallocated memory.") HWASAN_FLAG(int, heap_history_size, 1023, - "The number of heap (de)allocations remembered per thread. " - "Affects the quality of heap-related reports, but not the ability " - "to find bugs.") + "The number of heap (de)allocations remembered per thread. " + "Affects the quality of heap-related reports, but not the ability " + "to find bugs.") HWASAN_FLAG( int, heap_history_size_main_thread, 102300, "The number of heap (de)allocations remembered for the main thread. " @@ -78,7 +77,6 @@ HWASAN_FLAG(bool, malloc_bisect_dump, false, "Print all allocations within [malloc_bisect_left, " "malloc_bisect_right] range ") - // Exit if we fail to enable the AArch64 kernel ABI relaxation which allows // tagged pointers in syscalls. This is the default, but being able to disable // that behaviour is useful for running the testsuite on more platforms (the @@ -110,4 +108,16 @@ HWASAN_FLAG(int, heap_record_max, 0, HWASAN_FLAG(int, memory_around_register_size, 128, "When reporting, the memory content of the address in register " - "±memory_around_register_size is printed.") \ No newline at end of file + "±memory_around_register_size is printed.") + +// Set the quarantine area for freed heap, which is used to detect UAF-Write and +// Overflow-Write. Provide the detection capability for dynamic libraries +// compiled without hwasan option. +HWASAN_FLAG(int, heap_quarantine_thread_max_count, 128, + "Set the maximum count for heap quarantine per thread.") +HWASAN_FLAG(int, heap_quarantine_min, 0, + "The freed heap size should be larger than the minimum size before " + "it is placed into the heap quarantine.") +HWASAN_FLAG(int, heap_quarantine_max, 0, + "The freed heap size should be smaller than the maximum size before " + "it is placed into the heap quarantine.") diff --git a/compiler-rt/lib/hwasan/hwasan_quarantine.cpp b/compiler-rt/lib/hwasan/hwasan_quarantine.cpp new file mode 100644 index 000000000000..ad4488670d0a --- /dev/null +++ b/compiler-rt/lib/hwasan/hwasan_quarantine.cpp @@ -0,0 +1,117 @@ +//===-- hwasan_quarantine.cpp -----------------------------------*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file is a part of HWAddressSanitizer. Provide allocation quarantine +/// ability. +/// +//===----------------------------------------------------------------------===// +#include "hwasan_quarantine.h" + +#include "hwasan_allocator.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_stackdepot.h" +namespace __hwasan { + +void HeapQuarantineController::ClearHeapQuarantine(AllocatorCache *cache) { + CHECK(cache); + if (heap_quarantine_list_) { + DeallocateWithHeapQuarantcheck(heap_quarantine_tail_, cache); + size_t sz = RoundUpTo( + flags()->heap_quarantine_thread_max_count * sizeof(HeapQuarantine), + GetPageSizeCached()); + UnmapOrDie(heap_quarantine_list_, sz); + heap_quarantine_tail_ = 0; + heap_quarantine_list_ = nullptr; + } + heap_quarantine_list_ = nullptr; +} + +bool HeapQuarantineController::TryPutInQuarantineWithDealloc( + uptr ptr, size_t s, u32 aid, u32 fid, AllocatorCache *cache) { + if (IsInPrintf()) { + return false; + } + if ((flags()->heap_quarantine_max > 0) && + (flags()->heap_quarantine_max > s && flags()->heap_quarantine_min <= s)) { + if (UNLIKELY(flags()->heap_quarantine_thread_max_count == 0)) { + return false; + } + if (UNLIKELY(heap_quarantine_list_ == nullptr)) { + size_t sz = RoundUpTo( + flags()->heap_quarantine_thread_max_count * sizeof(HeapQuarantine), + GetPageSizeCached()); + heap_quarantine_list_ = reinterpret_cast( + MmapOrDie(sz, "HeapQuarantine", 0)); + if (UNLIKELY(heap_quarantine_list_ == nullptr)) { + return false; + } + } + PutInQuarantineWithDealloc(ptr, s, aid, fid, cache); + return true; + } + return false; +} + +void HeapQuarantineController::PutInQuarantineWithDealloc( + uptr ptr, size_t s, u32 aid, u32 fid, AllocatorCache *cache) { + if (UNLIKELY(heap_quarantine_tail_ >= + flags()->heap_quarantine_thread_max_count)) { + // free 1/3 heap_quarantine_list + u32 free_count = heap_quarantine_tail_ / 3; + u32 left_count = heap_quarantine_tail_ - free_count; + DeallocateWithHeapQuarantcheck(free_count, cache); + internal_memcpy( + (char *)heap_quarantine_list_, + (char *)heap_quarantine_list_ + free_count * sizeof(HeapQuarantine), + left_count * sizeof(HeapQuarantine)); + internal_memset( + (char *)heap_quarantine_list_ + left_count * sizeof(HeapQuarantine), 0, + free_count * sizeof(HeapQuarantine)); + heap_quarantine_tail_ -= free_count; + } + + heap_quarantine_list_[heap_quarantine_tail_].ptr = ptr; + heap_quarantine_list_[heap_quarantine_tail_].s = s; + heap_quarantine_list_[heap_quarantine_tail_].alloc_context_id = aid; + heap_quarantine_list_[heap_quarantine_tail_].free_context_id = fid; + heap_quarantine_tail_++; + return; +} + +void HeapQuarantineController::DeallocateWithHeapQuarantcheck( + u32 free_count, AllocatorCache *cache) { + static u64 magic; + internal_memset(&magic, flags()->free_fill_byte, sizeof(magic)); + for (u32 i = 0; i < free_count; i++) { + u64 *ptrBeg = reinterpret_cast(heap_quarantine_list_[i].ptr); + if (heap_quarantine_list_[i].s > sizeof(u64)) { + if (flags()->max_free_fill_size > 0) { + uptr fill_size = + Min(heap_quarantine_list_[i].s, (uptr)flags()->max_free_fill_size); + for (size_t j = 0; j < (fill_size - 1) / sizeof(u64); j++) { + if (ptrBeg[j] != magic) { + Printf( + "ptrBeg was re-written after free %p[%zu], %p " + "%016llx:%016llx, freed by:\n", + ptrBeg, j, &ptrBeg[j], ptrBeg[j], magic); + StackDepotGet(heap_quarantine_list_[i].free_context_id).Print(); + Printf("allocated by:\n"); + StackDepotGet(heap_quarantine_list_[i].alloc_context_id).Print(); + break; + } + } + } + } + SimpleThreadDeallocate((void *)ptrBeg, cache); + } +} + +} // namespace __hwasan \ No newline at end of file diff --git a/compiler-rt/lib/hwasan/hwasan_quarantine.h b/compiler-rt/lib/hwasan/hwasan_quarantine.h new file mode 100644 index 000000000000..1c4c86a26168 --- /dev/null +++ b/compiler-rt/lib/hwasan/hwasan_quarantine.h @@ -0,0 +1,49 @@ +//===-- hwasan_quarantine.cpp -----------------------------------*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file is a part of HWAddressSanitizer. Provide allocation quarantine +/// ability header. +/// +//===----------------------------------------------------------------------===// +#ifndef HWASAN_QUARANTINE_H +#define HWASAN_QUARANTINE_H +#include "hwasan_allocator.h" +namespace __hwasan { +struct HeapQuarantine { + uptr ptr; + size_t s; + u32 alloc_context_id; + u32 free_context_id; +}; +// provide heap quarant for per thread, no data race. +class HeapQuarantineController { + private: + u32 heap_quarantine_tail_; + HeapQuarantine *heap_quarantine_list_; + void PutInQuarantineWithDealloc(uptr ptr, size_t s, u32 aid, u32 fid, + AllocatorCache *cache); + void DeallocateWithHeapQuarantcheck(u32 free_count, AllocatorCache *cache); + + public: + void Init() { + heap_quarantine_tail_ = 0; + heap_quarantine_list_ = nullptr; + } + + void ClearHeapQuarantine(AllocatorCache *cache); + + bool TryPutInQuarantineWithDealloc(uptr ptr, size_t s, u32 aid, u32 fid, + AllocatorCache *cache); +}; + +} // namespace __hwasan + +#endif // HWASAN_QUARANTINE_H \ No newline at end of file diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp index b576b9a119ba..fa46df43631e 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.cpp +++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp @@ -56,6 +56,7 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size, #endif InitStackAndTls(state); tid_ = GetTid(); + heap_quarantine_controller()->Init(); } void Thread::InitStackRingBuffer(uptr stack_buffer_start, @@ -98,6 +99,7 @@ void Thread::ClearShadowForThreadStackAndTLS() { void Thread::Destroy() { if (flags()->verbose_threads) Print("Destroying: "); + heap_quarantine_controller()->ClearHeapQuarantine(allocator_cache()); AllocatorSwallowThreadLocalCache(allocator_cache()); ClearShadowForThreadStackAndTLS(); if (heap_allocations_) @@ -155,4 +157,10 @@ tag_t Thread::GenerateRandomTag(uptr num_bits) { return tag; } +bool Thread::TryPutInQuarantineWithDealloc(uptr ptr, size_t s, u32 aid, + u32 fid) { + return heap_quarantine_controller()->TryPutInQuarantineWithDealloc( + ptr, s, aid, fid, allocator_cache()); +} + } // namespace __hwasan diff --git a/compiler-rt/lib/hwasan/hwasan_thread.h b/compiler-rt/lib/hwasan/hwasan_thread.h index 1e1b3fed6f2d..26441fe0410d 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.h +++ b/compiler-rt/lib/hwasan/hwasan_thread.h @@ -14,6 +14,7 @@ #define HWASAN_THREAD_H #include "hwasan_allocator.h" +#include "hwasan_quarantine.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_ring_buffer.h" @@ -78,6 +79,12 @@ class Thread { uptr &vfork_spill() { return vfork_spill_; } + HeapQuarantineController *heap_quarantine_controller() { + return &heap_quarantine_controller_; + } + + bool TryPutInQuarantineWithDealloc(uptr ptr, size_t s, u32 aid, u32 fid); + private: // NOTE: There is no Thread constructor. It is allocated // via mmap() and *must* be valid in zero-initialized state. @@ -97,6 +104,8 @@ class Thread { HeapAllocationsRingBuffer *heap_allocations_; StackAllocationsRingBuffer *stack_allocations_; + HeapQuarantineController heap_quarantine_controller_; + u64 unique_id_; // counting from zero. u32 tagging_disabled_; // if non-zero, malloc uses zero tag in this thread. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h index ed20388016fb..c94dc041e50e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -229,6 +229,7 @@ bool ColorizeReports(); void RemoveANSIEscapeSequencesFromString(char *buffer); void Printf(const char *format, ...) FORMAT(1, 2); void Report(const char *format, ...) FORMAT(1, 2); +bool IsInPrintf(); void SetPrintfAndReportCallback(void (*callback)(const char *)); #define VReport(level, ...) \ do { \ diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp index 3a9e366d2df9..1a86ffd0d13c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp @@ -310,10 +310,16 @@ static void NOINLINE SharedPrintfCode(bool append_pid, const char *format, format, args); } +static thread_local bool is_in_printf; + +bool IsInPrintf() { return is_in_printf; } + void Printf(const char *format, ...) { va_list args; va_start(args, format); + is_in_printf = true; SharedPrintfCode(false, format, args); + is_in_printf =false; va_end(args); } -- Gitee From c9a45c197c40fa2f7cc929b6b0efb4f4f63d465b Mon Sep 17 00:00:00 2001 From: MrLop Date: Wed, 22 Jan 2025 11:13:32 +0800 Subject: [PATCH 11/11] [Compier-RT][HWASAN] Format OHOS LLVM Mark Mark OHOS related changed `OHOS_LOCAL` related commit: commit 3c6e8e2731ad85f4eca025c52dd46af222ce115b commit 39240d7ab44bee9381219166774ba93c6db95031 commit d2884bd010d7f5d3850921b411360cb8d50e8e7b commit 95a0baa9c14f5308c4880f9170b14415fd340b43 commit 7f1ef9fc0e505ecb0a1ce5cebdb1855068f7f15b commit e0e7cf66d8287eac61ddd33c8156828861a05edc commit 984326a898190842355e1ec707c2dd6c0ca2cfb7 commit 7b6c00644e306384bdf85a82e9cb0678352fa879 commit 8c713bdb6796ad47444d1dc21a343c00a175d945 commit cc819c46f26de10634a9b2755b616c6209b7f195 Signed-off-by: MrLop --- compiler-rt/lib/hwasan/CMakeLists.txt | 4 ++-- compiler-rt/lib/hwasan/hwasan_allocator.cpp | 10 ++++++++- compiler-rt/lib/hwasan/hwasan_allocator.h | 10 ++++----- compiler-rt/lib/hwasan/hwasan_flags.inc | 4 ++++ compiler-rt/lib/hwasan/hwasan_report.cpp | 22 ++++++++++++++----- compiler-rt/lib/hwasan/hwasan_report.h | 4 +++- compiler-rt/lib/hwasan/hwasan_thread.cpp | 13 ++++++++--- compiler-rt/lib/hwasan/hwasan_thread.h | 14 +++++++++++- compiler-rt/lib/hwasan/hwasan_thread_list.h | 12 +++++++++- .../lib/sanitizer_common/sanitizer_common.h | 2 +- .../sanitizer_posix_libcdep.cpp | 4 ++++ .../lib/sanitizer_common/sanitizer_printf.cpp | 8 +++---- .../sanitizer_common/sanitizer_ring_buffer.h | 10 +++++---- .../hwasan/TestCases/heap-buffer-overflow.c | 4 ++++ .../test/hwasan/TestCases/rich-stack.c | 1 + compiler-rt/test/hwasan/TestCases/stack-uar.c | 2 ++ compiler-rt/test/hwasan/TestCases/stack-uas.c | 6 +++-- .../test/hwasan/TestCases/thread-uaf.c | 5 ++++- .../TestCases/use-after-free-and-overflow.c | 1 + .../test/hwasan/TestCases/wild-free-close.c | 3 ++- .../test/hwasan/TestCases/wild-free-realloc.c | 3 ++- .../test/hwasan/TestCases/wild-free-shadow.c | 3 ++- compiler-rt/test/hwasan/TestCases/wild-free.c | 3 ++- 23 files changed, 113 insertions(+), 35 deletions(-) diff --git a/compiler-rt/lib/hwasan/CMakeLists.txt b/compiler-rt/lib/hwasan/CMakeLists.txt index 5879080cedef..a9f6006ac05c 100644 --- a/compiler-rt/lib/hwasan/CMakeLists.txt +++ b/compiler-rt/lib/hwasan/CMakeLists.txt @@ -14,7 +14,7 @@ set(HWASAN_RTL_SOURCES hwasan_linux.cpp hwasan_memintrinsics.cpp hwasan_poisoning.cpp - hwasan_quarantine.cpp + hwasan_quarantine.cpp # OHOS_LOCAL hwasan_report.cpp hwasan_setjmp_aarch64.S hwasan_setjmp_x86_64.S @@ -43,7 +43,7 @@ set(HWASAN_RTL_HEADERS hwasan_malloc_bisect.h hwasan_mapping.h hwasan_poisoning.h - hwasan_quarantine.h + hwasan_quarantine.h # OHOS_LOCAL hwasan_report.h hwasan_thread.h hwasan_thread_list.h diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp index 44433a07938d..ebb5b4923ba6 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp +++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp @@ -20,7 +20,7 @@ #include "hwasan_mapping.h" #include "hwasan_malloc_bisect.h" #include "hwasan_thread.h" -#include "hwasan_thread_list.h" +#include "hwasan_thread_list.h" // OHOS_LOCAL #include "hwasan_report.h" namespace __hwasan { @@ -54,11 +54,13 @@ static uptr AlignRight(uptr addr, uptr requested_size) { return addr + kShadowAlignment - tail_size; } +// OHOS_LOCAL begin int HwasanChunkView::AllocatedByThread() const { if (metadata_) return metadata_->thread_id; return -1; } +// OHOS_LOCAL end uptr HwasanChunkView::Beg() const { if (metadata_ && metadata_->right_aligned) @@ -87,11 +89,13 @@ void GetAllocatorStats(AllocatorStatCounters s) { allocator.GetStats(s); } +// OHOS_LOCAL begin void SimpleThreadDeallocate(void *ptr, AllocatorCache *cache) { CHECK(ptr); CHECK(cache); allocator.Deallocate(cache, ptr); } +// OHOS_LOCAL end uptr GetAliasRegionStart() { #if defined(HWASAN_ALIASING_MODE) @@ -173,10 +177,12 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment, meta->set_requested_size(orig_size); meta->alloc_context_id = StackDepotPut(*stack); meta->right_aligned = false; + // OHOS_LOCAL begin if (t) meta->thread_id = t->tid(); else meta->thread_id = -1; + // OHOS_LOCAL end if (zeroise) { internal_memset(allocated, 0, size); } else if (flags()->max_malloc_fill_size > 0) { @@ -313,6 +319,7 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { tag); } +// OHOS_LOCAL begin int aid = meta->thread_id; if (t) { if (!t->TryPutInQuarantineWithDealloc(reinterpret_cast(aligned_ptr), @@ -346,6 +353,7 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { } allocator.Deallocate(cache, aligned_ptr); } +// OHOS_LOCAL end } static void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old, diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.h b/compiler-rt/lib/hwasan/hwasan_allocator.h index 1510395bf6f2..28f4f74bdb93 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocator.h +++ b/compiler-rt/lib/hwasan/hwasan_allocator.h @@ -35,7 +35,7 @@ struct Metadata { u32 requested_size_high : 31; u32 right_aligned : 1; u32 alloc_context_id; - int thread_id; + int thread_id; // OHOS_LOCAL u64 get_requested_size() { return (static_cast(requested_size_high) << 32) + requested_size_low; } @@ -89,7 +89,7 @@ class HwasanChunkView { uptr ActualSize() const; // Size allocated by the allocator. u32 GetAllocStackId() const; bool FromSmallHeap() const; - int AllocatedByThread() const; + int AllocatedByThread() const; // OHOS_LOCAL private: uptr block_; Metadata *const metadata_; @@ -106,15 +106,15 @@ struct HeapAllocationRecord { u32 alloc_context_id; u32 free_context_id; u32 requested_size; - int alloc_thread; - int free_thread; + int alloc_thread; // OHOS_LOCAL + int free_thread; // OHOS_LOCAL }; typedef RingBuffer HeapAllocationsRingBuffer; void GetAllocatorStats(AllocatorStatCounters s); -void SimpleThreadDeallocate(void *ptr, AllocatorCache *cache); +void SimpleThreadDeallocate(void *ptr, AllocatorCache *cache); // OHOS_LOCAL inline bool InTaggableRegion(uptr addr) { #if defined(HWASAN_ALIASING_MODE) diff --git a/compiler-rt/lib/hwasan/hwasan_flags.inc b/compiler-rt/lib/hwasan/hwasan_flags.inc index efbebff62617..15f399a0a7f0 100644 --- a/compiler-rt/lib/hwasan/hwasan_flags.inc +++ b/compiler-rt/lib/hwasan/hwasan_flags.inc @@ -52,11 +52,13 @@ HWASAN_FLAG(int, heap_history_size, 1023, "The number of heap (de)allocations remembered per thread. " "Affects the quality of heap-related reports, but not the ability " "to find bugs.") +// OHOS_LOCAL begin HWASAN_FLAG( int, heap_history_size_main_thread, 102300, "The number of heap (de)allocations remembered for the main thread. " "Affects the quality of heap-related reports, but not the ability " "to find bugs.") +// OHOS_LOCAL end HWASAN_FLAG(bool, export_memory_stats, true, "Export up-to-date memory stats through /proc") HWASAN_FLAG(int, stack_history_size, 1024, @@ -85,6 +87,7 @@ HWASAN_FLAG(bool, malloc_bisect_dump, false, HWASAN_FLAG(bool, fail_without_syscall_abi, true, "Exit if fail to request relaxed syscall ABI.") +// OHOS_LOCAL begin HWASAN_FLAG( bool, print_uaf_stacks_with_same_tag, true, "Control the output content of use-after-free, deciding whether to print " @@ -121,3 +124,4 @@ HWASAN_FLAG(int, heap_quarantine_min, 0, HWASAN_FLAG(int, heap_quarantine_max, 0, "The freed heap size should be smaller than the maximum size before " "it is placed into the heap quarantine.") +// OHOS_LOCAL end \ No newline at end of file diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp index ac893e962367..051c68ee2e84 100644 --- a/compiler-rt/lib/hwasan/hwasan_report.cpp +++ b/compiler-rt/lib/hwasan/hwasan_report.cpp @@ -347,20 +347,22 @@ void PrintAddressDescription( if (uptr beg = chunk.Beg()) { uptr size = chunk.ActualSize(); Printf("%s[%p,%p) is a %s %s heap chunk; " - "size: %zd offset: %zd, Allocated By %u\n%s", + "size: %zd offset: %zd, Allocated By %u\n%s", // OHOS_LOCAL d.Location(), beg, beg + size, chunk.FromSmallHeap() ? "small" : "large", chunk.IsAllocated() ? "allocated" : "unallocated", size, untagged_addr - beg, - chunk.AllocatedByThread(), + chunk.AllocatedByThread(), // OHOS_LOCAL d.Default()); +// OHOS_LOCAL begin if (chunk.IsAllocated() && chunk.GetAllocStackId()) { Printf("%s", d.Allocation()); Printf("Currently allocated here:\n"); Printf("%s", d.Default()); GetStackTraceFromId(chunk.GetAllocStackId()).Print(); } +// OHOS_LOCAL end } tag_t addr_tag = GetTagFromPointer(tagged_addr); @@ -377,7 +379,7 @@ void PrintAddressDescription( Printf("\nCause: stack tag-mismatch\n"); Printf("%s", d.Location()); Printf("Address %p is located in stack of thread %d\n", untagged_addr, - t->tid()); + t->tid()); // OHOS_LOCAL Printf("%s", d.Default()); t->Announce(); @@ -415,10 +417,11 @@ void PrintAddressDescription( if (!on_stack && candidate && candidate_distance <= kCloseCandidateDistance) { ShowHeapOrGlobalCandidate(untagged_addr, candidate, left, right); - candidate = nullptr; + candidate = nullptr; // OHOS_LOCAL num_descriptions_printed++; } +// OHOS_LOCAL begin auto PrintUAF = [&](Thread *t, uptr ring_index, HeapAllocationRecord &har) { uptr ha_untagged_addr = UntagAddr(har.tagged_addr); Printf("%s", d.Error()); @@ -527,6 +530,7 @@ void PrintAddressDescription( Printf("RB %u: (%zd/%zu)\n", freed_idx++, rb->realsize(), rb->size()); }); } +// OHOS_LOCAL end if (!num_descriptions_printed) // We exhausted our possibilities. Bail out. @@ -616,8 +620,10 @@ void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) { const char *bug_type = "invalid-free"; const Thread *thread = GetCurrentThread(); if (thread) { +// OHOS_LOCAL begin Report("ERROR: %s: %s on address %p at pc %p on thread %d\n", SanitizerToolName, bug_type, untagged_addr, pc, thread->tid()); +// OHOS_LOCAL end } else { Report("ERROR: %s: %s on address %p at pc %p on unknown thread\n", SanitizerToolName, bug_type, untagged_addr, pc); @@ -752,14 +758,18 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size, offset += mem_tag - in_granule_offset; } } +// OHOS_LOCAL begin Printf( "%s of size %zu at %p tags: %02x/%02x(%02x) (ptr/mem) in thread %d\n", is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag, mem_tag, short_tag, t->tid()); +// OHOS_LOCAL end } else { +// OHOS_LOCAL begin Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem) in thread %d\n", is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag, mem_tag, t->tid()); +// OHOS_LOCAL end } if (offset != 0) Printf("Invalid access starting at offset %zu\n", offset); @@ -775,12 +785,13 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size, if (registers_frame) { ReportRegisters(registers_frame, pc); - ReportMemoryNearRegisters(registers_frame, pc); + ReportMemoryNearRegisters(registers_frame, pc); // OHOS_LOCAL } ReportErrorSummary(bug_type, stack); } +// OHOS_LOCAL begin void PrintMemoryAroundAddress(MemoryMappingLayout &proc_maps, int reg_num, uptr addr, uptr len, bool is_pc) { const sptr kBufSize = 4095; @@ -824,6 +835,7 @@ void ReportMemoryNearRegisters(uptr *frame, uptr pc) { PrintMemoryAroundAddress(proc_maps, -1, pc, flags()->memory_around_register_size, true); } +// OHOS_LOCAL end // See the frame breakdown defined in __hwasan_tag_mismatch (from // hwasan_tag_mismatch_aarch64.S). diff --git a/compiler-rt/lib/hwasan/hwasan_report.h b/compiler-rt/lib/hwasan/hwasan_report.h index 3fd9603a87da..9ba8a1f6658b 100644 --- a/compiler-rt/lib/hwasan/hwasan_report.h +++ b/compiler-rt/lib/hwasan/hwasan_report.h @@ -16,7 +16,7 @@ #define HWASAN_REPORT_H #include "sanitizer_common/sanitizer_internal_defs.h" -#include "sanitizer_common/sanitizer_procmaps.h" +#include "sanitizer_common/sanitizer_procmaps.h" // OHOS_LOCAL #include "sanitizer_common/sanitizer_stacktrace.h" namespace __hwasan { @@ -28,9 +28,11 @@ void ReportInvalidFree(StackTrace *stack, uptr addr); void ReportTailOverwritten(StackTrace *stack, uptr addr, uptr orig_size, const u8 *expected); void ReportRegisters(uptr *registers_frame, uptr pc); +// OHOS_LOCAL begin void ReportMemoryNearRegisters(uptr *registers_frame, uptr pc); void PrintMemoryAroundAddress(MemoryMappingLayout &proc_maps, int reg_num, uptr addr, uptr len, bool is_pc = false); +// OHOS_LOCAL end void ReportAtExitStatistics(); } // namespace __hwasan diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp index fa46df43631e..4be4929284d9 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.cpp +++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp @@ -44,10 +44,12 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size, static atomic_uint64_t unique_id; unique_id_ = atomic_fetch_add(&unique_id, 1, memory_order_relaxed); +// OHOS_LOCAL begin if (auto sz = IsMainThread() ? flags()->heap_history_size_main_thread : flags()->heap_history_size) +// OHOS_LOCAL end heap_allocations_ = HeapAllocationsRingBuffer::New(sz); - trace_heap_allocation_ = true; + trace_heap_allocation_ = true; // OHOS_LOCAL #if !SANITIZER_FUCHSIA // Do not initialize the stack ring buffer just yet on Fuchsia. Threads will // be initialized before we enter the thread itself, so we will instead call @@ -55,8 +57,8 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size, InitStackRingBuffer(stack_buffer_start, stack_buffer_size); #endif InitStackAndTls(state); - tid_ = GetTid(); - heap_quarantine_controller()->Init(); + tid_ = GetTid(); // OHOS_LOCAL + heap_quarantine_controller()->Init(); // OHOS_LOCAL } void Thread::InitStackRingBuffer(uptr stack_buffer_start, @@ -99,6 +101,7 @@ void Thread::ClearShadowForThreadStackAndTLS() { void Thread::Destroy() { if (flags()->verbose_threads) Print("Destroying: "); + // OHOS_LOCAL heap_quarantine_controller()->ClearHeapQuarantine(allocator_cache()); AllocatorSwallowThreadLocalCache(allocator_cache()); ClearShadowForThreadStackAndTLS(); @@ -114,6 +117,7 @@ void Thread::Destroy() { } void Thread::Print(const char *Prefix) { +// OHOS_LOCAL begin Printf( "%sT%zd %p stack: [%p,%p) sz: %zd tls: [%p,%p) rb:(%zd/%u) " "records(%llu/o:%llu) tid: %d\n", @@ -123,6 +127,7 @@ void Thread::Print(const char *Prefix) { IsMainThread() ? flags()->heap_history_size_main_thread : flags()->heap_history_size, all_record_count_, all_record_count_overflow_, tid_); +// OHOS_LOCAL end } static u32 xorshift(u32 state) { @@ -157,10 +162,12 @@ tag_t Thread::GenerateRandomTag(uptr num_bits) { return tag; } +// OHOS_LOCAL begin bool Thread::TryPutInQuarantineWithDealloc(uptr ptr, size_t s, u32 aid, u32 fid) { return heap_quarantine_controller()->TryPutInQuarantineWithDealloc( ptr, s, aid, fid, allocator_cache()); } +// OHOS_LOCAL end } // namespace __hwasan diff --git a/compiler-rt/lib/hwasan/hwasan_thread.h b/compiler-rt/lib/hwasan/hwasan_thread.h index 26441fe0410d..8f1126877aa9 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.h +++ b/compiler-rt/lib/hwasan/hwasan_thread.h @@ -14,7 +14,7 @@ #define HWASAN_THREAD_H #include "hwasan_allocator.h" -#include "hwasan_quarantine.h" +#include "hwasan_quarantine.h" // OHOS_LOCAL #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_ring_buffer.h" @@ -49,12 +49,14 @@ class Thread { uptr tls_end() { return tls_end_; } bool IsMainThread() { return unique_id_ == 0; } +// OHOS_LOCAL begin void inc_record(void) { all_record_count_++; if (all_record_count_ == 0) { all_record_count_overflow_++; } } +// OHOS_LOCAL end bool AddrIsInStack(uptr addr) { return addr >= stack_bottom_ && addr < stack_top_; @@ -69,21 +71,28 @@ class Thread { void DisableTagging() { tagging_disabled_++; } void EnableTagging() { tagging_disabled_--; } +// OHOS_LOCAL begin void EnableTracingHeapAllocation() { trace_heap_allocation_ = true; } void DisableTracingHeapAllocation() { trace_heap_allocation_ = false; } bool AllowTracingHeapAllocation() { return trace_heap_allocation_; } +// OHOS_LOCAL end u64 unique_id() const { return unique_id_; } + +// OHOS_LOCAL begin int tid() const { return tid_; } void Announce() { Print("Thread: "); } +// OHOS_LOCAL end uptr &vfork_spill() { return vfork_spill_; } +// OHOS_LOCAL begin HeapQuarantineController *heap_quarantine_controller() { return &heap_quarantine_controller_; } bool TryPutInQuarantineWithDealloc(uptr ptr, size_t s, u32 aid, u32 fid); +// OHOS_LOCAL end private: // NOTE: There is no Thread constructor. It is allocated @@ -104,6 +113,7 @@ class Thread { HeapAllocationsRingBuffer *heap_allocations_; StackAllocationsRingBuffer *stack_allocations_; +// OHOS_LOCAL HeapQuarantineController heap_quarantine_controller_; u64 unique_id_; // counting from zero. @@ -114,12 +124,14 @@ class Thread { bool random_state_inited_; // Whether InitRandomState() has been called. +// OHOS_LOCAL begin bool trace_heap_allocation_; int tid_ = -1; // Thread ID u64 all_record_count_ = 0; // Count record u64 all_record_count_overflow_ = 0; // Whether all_record_count_ overflow. +// OHOS_LOCAL end friend struct ThreadListHead; }; diff --git a/compiler-rt/lib/hwasan/hwasan_thread_list.h b/compiler-rt/lib/hwasan/hwasan_thread_list.h index 7792e1e5fcef..e039854ccaf8 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread_list.h +++ b/compiler-rt/lib/hwasan/hwasan_thread_list.h @@ -83,6 +83,7 @@ class HwasanThreadList { ring_buffer_size_ = RingBufferSize(); thread_alloc_size_ = RoundUpTo(ring_buffer_size_ + sizeof(Thread), ring_buffer_size_ * 2); +// OHOS_LOCAL begin freed_rb_fallback_ = HeapAllocationsRingBuffer::New(flags()->heap_history_size_main_thread); @@ -91,6 +92,7 @@ class HwasanThreadList { freed_rb_count_ = 0; freed_rb_count_overflow_ = 0; trace_heap_allocation_ = true; +// OHOS_LOCAL end } Thread *CreateCurrentThread(const Thread::InitState *state = nullptr) { @@ -135,6 +137,7 @@ class HwasanThreadList { CHECK(0 && "thread not found in live list"); } +// OHOS_LOCAL begin void AddFreedRingBuffer(Thread *t) { if (t->heap_allocations() == nullptr || t->heap_allocations()->realsize() == 0) @@ -179,9 +182,10 @@ class HwasanThreadList { if (freed_rb_count_ == 0) freed_rb_count_overflow_++; } +// OHOS_LOCAL end void ReleaseThread(Thread *t) { - AddFreedRingBuffer(t); + AddFreedRingBuffer(t); // OHOS_LOCAL RemoveThreadStats(t); t->Destroy(); DontNeedThread(t); @@ -208,6 +212,7 @@ class HwasanThreadList { for (Thread *t : live_list_) cb(t); } +// OHOS_LOCAL begin template void VisitAllFreedRingBuffer(CB cb) { DisableTracingHeapAllocation(); @@ -227,6 +232,7 @@ class HwasanThreadList { if (freed_rb_fallback_) Printf("fallback count: %llu\n", freed_rb_fallback_->realsize()); } +// OHOS_LOCAL end void AddThreadStats(Thread *t) { SpinMutexLock l(&stats_mutex_); @@ -247,6 +253,7 @@ class HwasanThreadList { uptr GetRingBufferSize() const { return ring_buffer_size_; } +// OHOS_LOCAL begin void RecordFallBack(HeapAllocationRecord h) { SpinMutexLock l(&freed_rb_mutex_); if (freed_rb_fallback_) @@ -256,6 +263,7 @@ class HwasanThreadList { void EnableTracingHeapAllocation() { trace_heap_allocation_ = true; } void DisableTracingHeapAllocation() { trace_heap_allocation_ = false; } bool AllowTracingHeapAllocation() { return trace_heap_allocation_; } +// OHOS_LOCAL end private: Thread *AllocThread() { @@ -279,6 +287,7 @@ class HwasanThreadList { SpinMutex live_list_mutex_; InternalMmapVector live_list_; +// OHOS_LOCAL begin SpinMutex freed_rb_mutex_; HeapAllocationsRingBuffer **freed_rb_list_; HeapAllocationsRingBuffer *freed_rb_fallback_; @@ -286,6 +295,7 @@ class HwasanThreadList { u64 freed_rb_count_; u64 freed_rb_count_overflow_; bool trace_heap_allocation_; +// OHOS_LOCAL end ThreadStats stats_; SpinMutex stats_mutex_; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h index c94dc041e50e..1b4f1bf45084 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -229,7 +229,7 @@ bool ColorizeReports(); void RemoveANSIEscapeSequencesFromString(char *buffer); void Printf(const char *format, ...) FORMAT(1, 2); void Report(const char *format, ...) FORMAT(1, 2); -bool IsInPrintf(); +bool IsInPrintf(); // OHOS_LOCAL void SetPrintfAndReportCallback(void (*callback)(const char *)); #define VReport(level, ...) \ do { \ diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index f192047fe950..689a94deccc0 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -36,9 +36,11 @@ #include #include +// OHOS_LOCAL begin #if SANITIZER_OHOS #include #endif +// OHOS_LOCAL end #if SANITIZER_FREEBSD // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before @@ -210,6 +212,7 @@ static void MaybeInstallSigaction(int signum, CHECK_EQ(0, internal_sigaction(signum, &sigact, nullptr)); VReport(1, "Installed the sigaction for signal %d\n", signum); #else +// OHOS_LOCAL begin typedef bool (*sc)(int, siginfo_t *, void *); sc h = (sc)handler; struct signal_chain_action sigchain = { @@ -220,6 +223,7 @@ static void MaybeInstallSigaction(int signum, // This is a void function for OHOS. When there are too many registered // functions, an internal error is reported. CHECK is not required. add_special_signal_handler(signum, &sigchain); +// OHOS_LOCAL end #endif } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp index 1a86ffd0d13c..53cc149f662c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp @@ -310,16 +310,16 @@ static void NOINLINE SharedPrintfCode(bool append_pid, const char *format, format, args); } -static thread_local bool is_in_printf; +static thread_local bool is_in_printf; // OHOS_LOCAL -bool IsInPrintf() { return is_in_printf; } +bool IsInPrintf() { return is_in_printf; } // OHOS_LOCAL void Printf(const char *format, ...) { va_list args; va_start(args, format); - is_in_printf = true; + is_in_printf = true; // OHOS_LOCAL SharedPrintfCode(false, format, args); - is_in_printf =false; + is_in_printf =false; // OHOS_LOCAL va_end(args); } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_ring_buffer.h b/compiler-rt/lib/sanitizer_common/sanitizer_ring_buffer.h index 6cf3c0d25513..d2356d69cf9b 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_ring_buffer.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_ring_buffer.h @@ -27,7 +27,7 @@ class RingBuffer { RingBuffer *RB = reinterpret_cast(Ptr); uptr End = reinterpret_cast(Ptr) + SizeInBytes(Size); RB->last_ = RB->next_ = reinterpret_cast(End - sizeof(T)); - RB->full_ = false; + RB->full_ = false; // OHOS_LOCAL return RB; } void Delete() { @@ -36,17 +36,19 @@ class RingBuffer { uptr size() const { return last_ + 1 - reinterpret_cast(reinterpret_cast(this) + - sizeof(RingBuffer) - sizeof(T)); + sizeof(RingBuffer) - sizeof(T)); // OHOS_LOCAL } +// OHOS_LOCAL begin uptr realsize() const { if (full_) return size(); return reinterpret_cast((uptr)last_ - (uptr)next_) / sizeof(T); } +// OHOS_LOCAL end static uptr SizeInBytes(uptr Size) { - return Size * sizeof(T) + sizeof(RingBuffer) - sizeof(T); + return Size * sizeof(T) + sizeof(RingBuffer) - sizeof(T); // OHOS_LOCAL } uptr SizeInBytes() { return SizeInBytes(size()); } @@ -57,7 +59,7 @@ class RingBuffer { // The condition below works only if sizeof(T) is divisible by sizeof(T*). if (next_ <= reinterpret_cast(&next_)) { next_ = last_; - full_ = true; + full_ = true; // OHOS_LOCAL } } diff --git a/compiler-rt/test/hwasan/TestCases/heap-buffer-overflow.c b/compiler-rt/test/hwasan/TestCases/heap-buffer-overflow.c index 425b8a405411..8bbf1eb9a396 100644 --- a/compiler-rt/test/hwasan/TestCases/heap-buffer-overflow.c +++ b/compiler-rt/test/hwasan/TestCases/heap-buffer-overflow.c @@ -50,14 +50,18 @@ int main(int argc, char **argv) { // CHECKm30: is located 30 bytes to the left of 30-byte region // // CHECKMm30: is a large allocated heap chunk; size: 1003520 offset: -30 +// OHOS_LOCAL begin // CHECKMm30: Currently allocated here: // CHECKMm30: #0 {{[0x]+}}{{.*}} +// OHOS_LOCAL end // CHECKMm30: Cause: heap-buffer-overflow // CHECKMm30: is located 30 bytes to the left of 1000000-byte region // // CHECKM: is a large allocated heap chunk; size: 1003520 offset: 1000000 +// OHOS_LOCAL begin // CHECKM: Currently allocated here: // CHECKM: #0 {{[0x]+}}{{.*}} +// OHOS_LOCAL end // CHECKM: Cause: heap-buffer-overflow // CHECKM: is located 0 bytes to the right of 1000000-byte region // diff --git a/compiler-rt/test/hwasan/TestCases/rich-stack.c b/compiler-rt/test/hwasan/TestCases/rich-stack.c index c7403c6156c2..8f9f0834d56b 100644 --- a/compiler-rt/test/hwasan/TestCases/rich-stack.c +++ b/compiler-rt/test/hwasan/TestCases/rich-stack.c @@ -64,4 +64,5 @@ int main(int argc, char **argv) { // R321: in BAR // R321-NEXT: in FOO // R321-NEXT: in main +// OHOS_LOCAL // R321: is located in stack of thread {{.*}} diff --git a/compiler-rt/test/hwasan/TestCases/stack-uar.c b/compiler-rt/test/hwasan/TestCases/stack-uar.c index b8b103fd8532..8d01fdecc8f5 100644 --- a/compiler-rt/test/hwasan/TestCases/stack-uar.c +++ b/compiler-rt/test/hwasan/TestCases/stack-uar.c @@ -38,6 +38,7 @@ int main() { // CHECK: is located in stack of thread // CHECK: Potentially referenced stack objects: // CHECK-NEXT: zzz in buggy {{.*}}stack-uar.c:[[@LINE-20]] + // OHOS_LOCAL // CHECK: Memory tags around the buggy address // NOSYM: Previously allocated frames: @@ -45,6 +46,7 @@ int main() { // NOSYM-NEXT: record_addr:0x{{.*}} record:0x{{.*}} ({{.*}}/stack-uar.c.tmp+0x{{.*}}){{$}} // NOSYM-NEXT: record_addr:0x{{.*}} record:0x{{.*}} ({{.*}}/stack-uar.c.tmp+0x{{.*}}){{$}} // NOSYM-NEXT: record_addr:0x{{.*}} record:0x{{.*}} ({{.*}}/stack-uar.c.tmp+0x{{.*}}){{$}} + // OHOS_LOCAL // NOSYM: Memory tags around the buggy address // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main diff --git a/compiler-rt/test/hwasan/TestCases/stack-uas.c b/compiler-rt/test/hwasan/TestCases/stack-uas.c index 7f5a6f26d067..096347479dcf 100644 --- a/compiler-rt/test/hwasan/TestCases/stack-uas.c +++ b/compiler-rt/test/hwasan/TestCases/stack-uas.c @@ -58,14 +58,16 @@ int main() { // CHECK: is located in stack of thread // CHECK: Potentially referenced stack objects: // CHECK-NEXT: zzz in buggy {{.*}}stack-uas.c:[[@LINE-17]] - // CHECK-NEXT: Memory tags around the buggy address + // OHOS_LOCAL + // CHECK: Memory tags around the buggy address // NOSYM: Previously allocated frames: // NOSYM-NEXT: record_addr:0x{{.*}} record:0x{{.*}} ({{.*}}/stack-uas.c.tmp+0x{{.*}}){{$}} // NOSYM-NEXT: record_addr:0x{{.*}} record:0x{{.*}} ({{.*}}/stack-uas.c.tmp+0x{{.*}}){{$}} // NOSYM-NEXT: record_addr:0x{{.*}} record:0x{{.*}} ({{.*}}/stack-uas.c.tmp+0x{{.*}}){{$}} // NOSYM-NEXT: record_addr:0x{{.*}} record:0x{{.*}} ({{.*}}/stack-uas.c.tmp+0x{{.*}}){{$}} - // NOSYM-NEXT: Memory tags around the buggy address + // OHOS_LOCAL + // NOSYM: Memory tags around the buggy address // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in buggy } diff --git a/compiler-rt/test/hwasan/TestCases/thread-uaf.c b/compiler-rt/test/hwasan/TestCases/thread-uaf.c index 1a2bd7e8efeb..dd98013b388f 100644 --- a/compiler-rt/test/hwasan/TestCases/thread-uaf.c +++ b/compiler-rt/test/hwasan/TestCases/thread-uaf.c @@ -28,11 +28,14 @@ void *Deallocate(void *arg) { void *Use(void *arg) { x[5] = 42; // CHECK: ERROR: HWAddressSanitizer: tag-mismatch on address + // OHOS_LOCAL // CHECK: WRITE of size 1 {{.*}} in thread {{.*}} - // CHECK: thread-uaf.c:[[@LINE-3]] + // CHECK: thread-uaf.c:[[@LINE-4]] // CHECK: Cause: use-after-free + // OHOS_LOCAL // CHECK: freed by thread {{.*}} here // CHECK: in Deallocate + // OHOS_LOCAL // CHECK: previously allocated by thread {{.*}} here: // CHECK: in Allocate // CHECK-DAG: Thread: T2 0x diff --git a/compiler-rt/test/hwasan/TestCases/use-after-free-and-overflow.c b/compiler-rt/test/hwasan/TestCases/use-after-free-and-overflow.c index 2c288561b03c..acdee4762df9 100644 --- a/compiler-rt/test/hwasan/TestCases/use-after-free-and-overflow.c +++ b/compiler-rt/test/hwasan/TestCases/use-after-free-and-overflow.c @@ -58,4 +58,5 @@ int main(int argc, char **argv) { // CHECK-NOT: Cause: heap-buffer-overflow // CHECK: Cause: use-after-free +// OHOS_LOCAL // CHECK: Cause: heap-buffer-overflow diff --git a/compiler-rt/test/hwasan/TestCases/wild-free-close.c b/compiler-rt/test/hwasan/TestCases/wild-free-close.c index c23b60739345..34bc0192bf15 100644 --- a/compiler-rt/test/hwasan/TestCases/wild-free-close.c +++ b/compiler-rt/test/hwasan/TestCases/wild-free-close.c @@ -11,9 +11,10 @@ int main() { fprintf(stderr, "ALLOC %p\n", __hwasan_tag_pointer(p, 0)); // CHECK: ALLOC {{[0x]+}}[[ADDR:.*]] free(p - 8); + // OHOS_LOCAL // CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread {{.*}} // CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in {{.*}}free - // CHECK: #1 {{.*}} in main {{.*}}wild-free-close.c:[[@LINE-3]] + // CHECK: #1 {{.*}} in main {{.*}}wild-free-close.c:[[@LINE-4]] // CHECK: is located 8 bytes to the left of 1-byte region [{{[0x]+}}{{.*}}[[ADDR]] // CHECK-NOT: Segmentation fault // CHECK-NOT: SIGSEGV diff --git a/compiler-rt/test/hwasan/TestCases/wild-free-realloc.c b/compiler-rt/test/hwasan/TestCases/wild-free-realloc.c index ab28b88c6104..8f47e46fca1f 100644 --- a/compiler-rt/test/hwasan/TestCases/wild-free-realloc.c +++ b/compiler-rt/test/hwasan/TestCases/wild-free-realloc.c @@ -7,9 +7,10 @@ int main() { __hwasan_enable_allocator_tagging(); char *p = (char *)malloc(1); realloc(p + 0x10000000000, 2); + // OHOS_LOCAL // CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread {{.*}} // CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in {{.*}}realloc - // CHECK: #1 {{.*}} in main {{.*}}wild-free-realloc.c:[[@LINE-3]] + // CHECK: #1 {{.*}} in main {{.*}}wild-free-realloc.c:[[@LINE-4]] // CHECK-NOT: Segmentation fault // CHECK-NOT: SIGSEGV return 0; diff --git a/compiler-rt/test/hwasan/TestCases/wild-free-shadow.c b/compiler-rt/test/hwasan/TestCases/wild-free-shadow.c index 7e4edc163e6b..a6cd82443247 100644 --- a/compiler-rt/test/hwasan/TestCases/wild-free-shadow.c +++ b/compiler-rt/test/hwasan/TestCases/wild-free-shadow.c @@ -7,9 +7,10 @@ extern void *__hwasan_shadow_memory_dynamic_address; int main() { char *p = (char *)malloc(1); free(__hwasan_shadow_memory_dynamic_address); + // OHOS_LOCAL // CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{[0x]+}}[[PTR:.*]] at pc {{[0x]+}}[[PC:.*]] on thread {{.*}} // CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in {{.*}}free - // CHECK: #1 {{.*}} in main {{.*}}wild-free-shadow.c:[[@LINE-3]] + // CHECK: #1 {{.*}} in main {{.*}}wild-free-shadow.c:[[@LINE-4]] // CHECK: {{[0x]+}}{{.*}}[[PTR]] is HWAsan shadow memory. // CHECK-NOT: Segmentation fault // CHECK-NOT: SIGSEGV diff --git a/compiler-rt/test/hwasan/TestCases/wild-free.c b/compiler-rt/test/hwasan/TestCases/wild-free.c index 5110170da446..50678142089b 100644 --- a/compiler-rt/test/hwasan/TestCases/wild-free.c +++ b/compiler-rt/test/hwasan/TestCases/wild-free.c @@ -7,9 +7,10 @@ int main() { __hwasan_enable_allocator_tagging(); char *p = (char *)malloc(1); free(p + 0x10000000000); + // OHOS_LOCAL // CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread {{.*}} // CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in {{.*}}free - // CHECK: #1 {{.*}} in main {{.*}}wild-free.c:[[@LINE-3]] + // CHECK: #1 {{.*}} in main {{.*}}wild-free.c:[[@LINE-4]] // CHECK-NOT: Segmentation fault // CHECK-NOT: SIGSEGV return 0; -- Gitee