diff options
-rw-r--r-- | lib/hwasan/hwasan_interceptors.cc | 13 | ||||
-rw-r--r-- | lib/hwasan/hwasan_report.cc | 17 | ||||
-rw-r--r-- | lib/hwasan/hwasan_thread.cc | 13 | ||||
-rw-r--r-- | lib/hwasan/hwasan_thread.h | 16 | ||||
-rw-r--r-- | test/hwasan/TestCases/many-threads-uaf.c | 13 | ||||
-rw-r--r-- | test/hwasan/TestCases/thread-uaf.c | 44 |
6 files changed, 80 insertions, 36 deletions
diff --git a/lib/hwasan/hwasan_interceptors.cc b/lib/hwasan/hwasan_interceptors.cc index 8512c049c..88edeba40 100644 --- a/lib/hwasan/hwasan_interceptors.cc +++ b/lib/hwasan/hwasan_interceptors.cc @@ -292,16 +292,23 @@ INTERCEPTOR(void *, malloc, SIZE_T size) { extern "C" int pthread_attr_init(void *attr); extern "C" int pthread_attr_destroy(void *attr); +struct ThreadStartArg { + thread_callback_t callback; + void *param; +}; + static void *HwasanThreadStartFunc(void *arg) { __hwasan_thread_enter(); - ThreadStartArg *A = reinterpret_cast<ThreadStartArg*>(arg); - return A->callback(A->param); + ThreadStartArg A = *reinterpret_cast<ThreadStartArg*>(arg); + UnmapOrDie(arg, GetPageSizeCached()); + return A.callback(A.param); } INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*), void * param) { ScopedTaggingDisabler disabler; - ThreadStartArg *A = GetCurrentThread()->thread_start_arg(); + ThreadStartArg *A = reinterpret_cast<ThreadStartArg *> (MmapOrDie( + GetPageSizeCached(), "pthread_create")); *A = {callback, param}; int res = REAL(pthread_create)(UntagPtr(th), UntagPtr(attr), &HwasanThreadStartFunc, A); diff --git a/lib/hwasan/hwasan_report.cc b/lib/hwasan/hwasan_report.cc index 9418059bc..bdc65fc97 100644 --- a/lib/hwasan/hwasan_report.cc +++ b/lib/hwasan/hwasan_report.cc @@ -43,6 +43,7 @@ class Decorator: public __sanitizer::SanitizerCommonDecorator { const char *Origin() const { return Magenta(); } const char *Name() const { return Green(); } const char *Location() { return Green(); } + const char *Thread() { return Green(); } }; bool FindHeapAllocation(HeapAllocationsRingBuffer *rb, @@ -116,7 +117,7 @@ void PrintAddressDescription(uptr tagged_addr, uptr access_size) { har.requested_size, UntagAddr(har.tagged_addr), UntagAddr(har.tagged_addr) + har.requested_size); Printf("%s", d.Allocation()); - Printf("freed by thread %p here:\n", t); + Printf("freed by thread T%zd here:\n", t->unique_id()); Printf("%s", d.Default()); GetStackTraceFromId(har.free_context_id).Print(); @@ -124,6 +125,7 @@ void PrintAddressDescription(uptr tagged_addr, uptr access_size) { Printf("previously allocated here:\n", t); Printf("%s", d.Default()); GetStackTraceFromId(har.alloc_context_id).Print(); + t->Announce(); num_descriptions_printed++; } @@ -131,8 +133,10 @@ void PrintAddressDescription(uptr tagged_addr, uptr access_size) { // Very basic check for stack memory. if (t->AddrIsInStack(untagged_addr)) { Printf("%s", d.Location()); - Printf("Address %p is located in stack of thread %p\n", untagged_addr, t); - Printf("%s", d.Default()); + Printf("Address %p is located in stack of thread T%zd\n", untagged_addr, + t->unique_id()); + t->Announce(); + num_descriptions_printed++; } }); @@ -230,18 +234,21 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size, Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type, untagged_addr, pc); + Thread *t = GetCurrentThread(); + tag_t ptr_tag = GetTagFromPointer(tagged_addr); tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr)); tag_t mem_tag = *tag_ptr; Printf("%s", d.Access()); - Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem)\n", + Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem) in thread T%zd\n", is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag, - mem_tag); + mem_tag, t->unique_id()); Printf("%s", d.Default()); stack->Print(); PrintAddressDescription(tagged_addr, access_size); + t->Announce(); PrintTagsAroundAddr(tag_ptr); diff --git a/lib/hwasan/hwasan_thread.cc b/lib/hwasan/hwasan_thread.cc index f3dc97450..ce19e16d3 100644 --- a/lib/hwasan/hwasan_thread.cc +++ b/lib/hwasan/hwasan_thread.cc @@ -63,10 +63,11 @@ void Thread::Create() { uptr size = RoundUpTo(sizeof(Thread), PageSize); Thread *thread = (Thread*)MmapOrDie(size, __func__); thread->destructor_iterations_ = GetPthreadDestructorIterations(); - thread->random_state_ = flags()->random_tags ? RandomSeed() : 0; + thread->unique_id_ = unique_id++; + thread->random_state_ = + flags()->random_tags ? RandomSeed() : thread->unique_id_; if (auto sz = flags()->heap_history_size) thread->heap_allocations_ = RingBuffer<HeapAllocationRecord>::New(sz); - thread->unique_id_ = unique_id++; InsertIntoThreadList(thread); SetCurrentThread(thread); thread->Init(); @@ -100,7 +101,7 @@ void Thread::Init() { CHECK(MemIsApp(stack_top_ - 1)); } if (flags()->verbose_threads) - Print("Creating "); + Print("Creating : "); } void Thread::ClearShadowForThreadStackAndTLS() { @@ -112,7 +113,7 @@ void Thread::ClearShadowForThreadStackAndTLS() { void Thread::Destroy() { if (flags()->verbose_threads) - Print("Destroying"); + Print("Destroying: "); malloc_storage().CommitBack(); ClearShadowForThreadStackAndTLS(); RemoveFromThreadList(this); @@ -124,8 +125,8 @@ void Thread::Destroy() { } void Thread::Print(const char *Prefix) { - Printf("%s: thread %p id: %zd stack: [%p,%p) sz: %zd tls: [%p,%p)\n", Prefix, - this, unique_id_, stack_bottom(), stack_top(), + Printf("%sT%zd %p stack: [%p,%p) sz: %zd tls: [%p,%p)\n", Prefix, + unique_id_, this, stack_bottom(), stack_top(), stack_top() - stack_bottom(), tls_begin(), tls_end()); } diff --git a/lib/hwasan/hwasan_thread.h b/lib/hwasan/hwasan_thread.h index a2bff75f1..f1d79c750 100644 --- a/lib/hwasan/hwasan_thread.h +++ b/lib/hwasan/hwasan_thread.h @@ -19,11 +19,6 @@ namespace __hwasan { -struct ThreadStartArg { - thread_callback_t callback; - void *param; -}; - class Thread { public: static void Create(); // Must be called from the thread itself. @@ -73,9 +68,12 @@ class Thread { } } - // Return a scratch ThreadStartArg object to be used in - // pthread_create interceptor. - ThreadStartArg *thread_start_arg() { return &thread_start_arg_; } + u64 unique_id() const { return unique_id_; } + void Announce() { + if (announced_) return; + announced_ = true; + Print("Thread: "); + } private: // NOTE: There is no Thread constructor. It is allocated @@ -108,7 +106,7 @@ class Thread { u32 tagging_disabled_; // if non-zero, malloc uses zero tag in this thread. - ThreadStartArg thread_start_arg_; + bool announced_; }; Thread *GetCurrentThread(); diff --git a/test/hwasan/TestCases/many-threads-uaf.c b/test/hwasan/TestCases/many-threads-uaf.c index 4f58b3e35..3a79cb37b 100644 --- a/test/hwasan/TestCases/many-threads-uaf.c +++ b/test/hwasan/TestCases/many-threads-uaf.c @@ -14,12 +14,12 @@ void *BoringThread(void *arg) { return NULL; } -// CHECK: Creating : thread {{.*}} id: 0 -// CHECK: Creating : thread {{.*}} id: 1 -// CHECK: Destroying: thread {{.*}} id: 1 -// CHECK: Creating : thread {{.*}} id: 1100 -// CHECK: Destroying: thread {{.*}} id: 1100 -// CHECK: Creating : thread {{.*}} id: 1101 +// CHECK: Creating : T0 +// CHECK: Creating : T1 +// CHECK: Destroying: T1 +// CHECK: Creating : T1100 +// CHECK: Destroying: T1100 +// CHECK: Creating : T1101 void *UAFThread(void *arg) { char * volatile x = (char*)malloc(10); @@ -29,6 +29,7 @@ void *UAFThread(void *arg) { // CHECK: ERROR: HWAddressSanitizer: tag-mismatch on address // CHECK: WRITE of size 1 // CHECK: many-threads-uaf.c:[[@LINE-3]] + // CHECK: Thread: T1101 return NULL; } diff --git a/test/hwasan/TestCases/thread-uaf.c b/test/hwasan/TestCases/thread-uaf.c index f64cebaab..200b35a79 100644 --- a/test/hwasan/TestCases/thread-uaf.c +++ b/test/hwasan/TestCases/thread-uaf.c @@ -1,3 +1,5 @@ +// Tests UAF detection where Allocate/Deallocate/Use +// happen in separate threads. // RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s // REQUIRES: stable-runtime @@ -7,20 +9,48 @@ #include <sanitizer/hwasan_interface.h> -void *Thread(void *arg) { - char * volatile x = (char*)malloc(10); - fprintf(stderr, "ZZZ %p\n", x); +char *volatile x; +int state; + +void *Allocate(void *arg) { + x = (char*)malloc(10); + __sync_fetch_and_add(&state, 1); + while (__sync_fetch_and_add(&state, 0) != 3) {} + return NULL; +} +void *Deallocate(void *arg) { + while (__sync_fetch_and_add(&state, 0) != 1) {} free(x); + __sync_fetch_and_add(&state, 1); + while (__sync_fetch_and_add(&state, 0) != 3) {} + return NULL; +} + +void *Use(void *arg) { + while (__sync_fetch_and_add(&state, 0) != 2) {} x[5] = 42; // CHECK: ERROR: HWAddressSanitizer: tag-mismatch on address - // CHECK: WRITE of size 1 + // CHECK: WRITE of size 1 {{.*}} in thread T3 // CHECK: thread-uaf.c:[[@LINE-3]] + // CHECK: freed by thread T2 here + // CHECK: in Deallocate + // CHECK: previously allocated here: + // CHECK: in Allocate + // CHECK: Thread: T2 0x + // CHECK: Thread: T3 0x + __sync_fetch_and_add(&state, 1); return NULL; } int main() { __hwasan_enable_allocator_tagging(); - pthread_t t; - pthread_create(&t, NULL, Thread, NULL); - pthread_join(t, NULL); + pthread_t t1, t2, t3; + + pthread_create(&t1, NULL, Allocate, NULL); + pthread_create(&t2, NULL, Deallocate, NULL); + pthread_create(&t3, NULL, Use, NULL); + + pthread_join(t1, NULL); + pthread_join(t2, NULL); + pthread_join(t3, NULL); } |