[hwasan] simplify the thread hangling: instead of the ThreadRegistry (too heavy) simply maintain a linked list of Threads

llvm-svn: 341111
This commit is contained in:
Kostya Serebryany 2018-08-30 20:15:39 +00:00
parent 0b2a541b90
commit c359d9b8fa
7 changed files with 90 additions and 84 deletions

View File

@ -183,7 +183,6 @@ void __hwasan_init() {
if (hwasan_inited) return;
hwasan_init_is_running = 1;
SanitizerToolName = "HWAddressSanitizer";
GetThreadRegistry();
InitTlsSize();

View File

@ -292,29 +292,28 @@ 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;
// TODO: something crazy is going on with pthread_create overwriting parts
// of the stack, hense the padding.
char padding[1000];
};
static void *HwasanThreadStartFunc(void *arg) {
__hwasan_thread_enter();
return ((Thread *)arg)->ThreadStart();
ThreadStartArg *A = reinterpret_cast<ThreadStartArg*>(arg);
return A->callback(A->param);
}
INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
void * param) {
ENSURE_HWASAN_INITED(); // for GetTlsSize()
__sanitizer_pthread_attr_t myattr;
ScopedTaggingDisabler disabler;
if (!attr) {
pthread_attr_init(&myattr);
attr = &myattr;
}
AdjustStackSize(attr);
Thread *t = Thread::Create(callback, param);
ThreadStartArg A;
A.callback = callback;
A.param = param;
int res = REAL(pthread_create)(UntagPtr(th), UntagPtr(attr),
HwasanThreadStartFunc, UntagPtr(t));
if (attr == &myattr)
pthread_attr_destroy(&myattr);
&HwasanThreadStartFunc, &A);
return res;
}
#endif // HWASAN_WITH_INTERCEPTORS

View File

@ -238,6 +238,7 @@ void HwasanTSDDtor(void *tsd) {
CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
return;
}
t->Destroy();
__hwasan_thread_exit();
}

View File

@ -210,7 +210,6 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
if (FindHeapAllocation(t->heap_allocations(), tagged_addr, &har))
Printf("Address found in the ring buffer: %p %u %u\n", har.tagged_addr,
har.free_context_id, har.requested_size);
Printf("Current thread: tid: %d\n", t->context()->tid);
PrintTagsAroundAddr(tag_ptr);

View File

@ -24,6 +24,39 @@ static u32 RandomSeed() {
return seed;
}
static Thread *main_thread;
static SpinMutex thread_list_mutex;
void Thread::InsertIntoThreadList(Thread *t) {
CHECK(!t->next_);
if (!main_thread) {
main_thread = t;
return;
}
SpinMutexLock l(&thread_list_mutex);
Thread *last = main_thread;
while (last->next_)
last = last->next_;
last->next_ = t;
}
void Thread::RemoveFromThreadList(Thread *t) {
CHECK_NE(t, main_thread);
SpinMutexLock l(&thread_list_mutex);
Thread *prev = main_thread;
Thread *cur = prev->next_;
CHECK(cur);
while (cur) {
if (cur == t) {
prev->next_ = cur->next_;
return;
}
prev = cur;
cur = cur->next_;
}
CHECK(0 && "RemoveFromThreadList: thread not found");
}
Thread *Thread::Create(thread_callback_t start_routine,
void *arg) {
uptr PageSize = GetPageSizeCached();
@ -33,11 +66,9 @@ Thread *Thread::Create(thread_callback_t start_routine,
thread->arg_ = arg;
thread->destructor_iterations_ = GetPthreadDestructorIterations();
thread->random_state_ = flags()->random_tags ? RandomSeed() : 0;
thread->context_ = nullptr;
ThreadContext::Args args = {thread};
thread->tid_ = GetThreadRegistry().CreateThread(0, false, 0, &args);
if (auto sz = flags()->heap_history_size)
thread->heap_allocations_ = RingBuffer<HeapAllocationRecord>::New(sz);
InsertIntoThreadList(thread);
return thread;
}
@ -80,6 +111,7 @@ void Thread::ClearShadowForThreadStackAndTLS() {
void Thread::Destroy() {
malloc_storage().CommitBack();
ClearShadowForThreadStackAndTLS();
RemoveFromThreadList(this);
uptr size = RoundUpTo(sizeof(Thread), GetPageSizeCached());
if (heap_allocations_)
heap_allocations_->Delete();
@ -87,10 +119,6 @@ void Thread::Destroy() {
DTLS_Destroy();
}
thread_return_t Thread::ThreadStart() {
return start_routine_(arg_);
}
static u32 xorshift(u32 state) {
state ^= state << 13;
state ^= state >> 17;
@ -115,32 +143,4 @@ tag_t Thread::GenerateRandomTag() {
return tag;
}
void ThreadContext::OnCreated(void *arg) {
Args *args = static_cast<Args*>(arg);
thread = args->thread;
thread->set_context(this);
}
void ThreadContext::OnFinished() {
thread = nullptr;
}
static const u32 kMaxLiveThreads = 1024;
static ThreadContextBase *ThreadContextFactory(u32 tid) {
static ALIGNED(16) char placeholder[sizeof(ThreadContext) * kMaxLiveThreads];
void *mem = &placeholder[0] + tid * sizeof(ThreadContext);
CHECK_LT(tid, kMaxLiveThreads);
return new (mem) ThreadContext(tid);
}
ThreadRegistry &GetThreadRegistry() {
static ALIGNED(16) char placeholder[sizeof(ThreadRegistry)];
static ThreadRegistry *registry;
if (!registry)
registry = new (placeholder)
ThreadRegistry(ThreadContextFactory, kMaxLiveThreads, kMaxLiveThreads);
return *registry;
}
} // namespace __hwasan

View File

@ -16,37 +16,15 @@
#include "hwasan_allocator.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_thread_registry.h"
namespace __hwasan {
class Thread;
class ThreadContext : public ThreadContextBase {
public:
explicit ThreadContext(int tid)
: ThreadContextBase(tid), thread(nullptr){}
Thread *thread;
void OnCreated(void *arg) override;
void OnFinished() override;
struct Args {
Thread *thread;
};
};
// We want this to be small.
COMPILER_CHECK(sizeof(ThreadContext) <= 256);
class Thread {
public:
static Thread *Create(thread_callback_t start_routine, void *arg);
void Destroy();
void Init();
thread_return_t ThreadStart();
uptr stack_top() { return stack_top_; }
uptr stack_bottom() { return stack_bottom_; }
@ -75,9 +53,6 @@ class Thread {
return heap_allocations_;
}
void set_context(ThreadContext *context) { context_ = context; }
const ThreadContext *context() const { return context_; }
tag_t GenerateRandomTag();
int destructor_iterations_;
@ -107,8 +82,9 @@ class Thread {
HwasanThreadLocalMallocStorage malloc_storage_;
HeapAllocationsRingBuffer *heap_allocations_;
u32 tid_;
ThreadContext *context_;
static void InsertIntoThreadList(Thread *t);
static void RemoveFromThreadList(Thread *t);
Thread *next_; // All live threads form a linked list.
u32 tagging_disabled_; // if non-zero, malloc uses zero tag in this thread.
};
@ -116,16 +92,11 @@ class Thread {
Thread *GetCurrentThread();
void SetCurrentThread(Thread *t);
// Returns the ThreadRegistry singleton.
ThreadRegistry &GetThreadRegistry();
struct ScopedTaggingDisabler {
ScopedTaggingDisabler() { GetCurrentThread()->DisableTagging(); }
~ScopedTaggingDisabler() { GetCurrentThread()->EnableTagging(); }
};
// Returns the ThreadRegistry singleton.
} // namespace __hwasan
#endif // HWASAN_THREAD_H

View File

@ -0,0 +1,37 @@
// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s
// REQUIRES: stable-runtime
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <sanitizer/hwasan_interface.h>
void *BoringThread(void *arg) {
char * volatile x = (char*)malloc(10);
x[5] = 0;
free(x);
return NULL;
}
void *UAFThread(void *arg) {
char * volatile x = (char*)malloc(10);
fprintf(stderr, "ZZZ %p\n", x);
free(x);
x[5] = 42;
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch on address
// CHECK: WRITE of size 1
// CHECK: many-threads-uaf.c:[[@LINE-3]]
return NULL;
}
int main() {
__hwasan_enable_allocator_tagging();
pthread_t t;
for (int i = 0; i < 1100; i++) {
pthread_create(&t, NULL, BoringThread, NULL);
pthread_join(t, NULL);
}
pthread_create(&t, NULL, UAFThread, NULL);
pthread_join(t, NULL);
}