Skip to content

Commit 846ec2c

Browse files
committed
[HWASan] Ensure RNG is initialized in GenerateRandomTag
Fixes a CHECK-failure caused by glibc's pthread_getattr_np implementation calling realloc. Essentially, Thread::GenerateRandomTag gets called during Thread::Init and before Thread::InitRandomState: HWAddressSanitizer: CHECK failed: hwasan_thread.cpp:134 "((random_buffer_)) != (0)" (0x0, 0x0) (tid=314) #0 0x55845475a662 in __hwasan::CheckUnwind() #1 0x558454778797 in __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) #2 0x558454766461 in __hwasan::Thread::GenerateRandomTag(unsigned long) #3 0x55845475c58b in __hwasan::HwasanAllocate(__sanitizer::StackTrace*, unsigned long, unsigned long, bool) #4 0x55845475c80a in __hwasan::hwasan_realloc(void*, unsigned long, __sanitizer::StackTrace*) #5 0x5584547608aa in realloc #6 0x7f6f3a3d8c2c in pthread_getattr_np #7 0x5584547790dc in __sanitizer::GetThreadStackTopAndBottom(bool, unsigned long*, unsigned long*) #8 0x558454779651 in __sanitizer::GetThreadStackAndTls(bool, unsigned long*, unsigned long*, unsigned long*, unsigned long*) #9 0x558454761bca in __hwasan::Thread::InitStackAndTls(__hwasan::Thread::InitState const*) #10 0x558454761e5c in __hwasan::HwasanThreadList::CreateCurrentThread(__hwasan::Thread::InitState const*) #11 0x55845476184f in __hwasan_thread_enter #12 0x558454760def in HwasanThreadStartFunc(void*) #13 0x7f6f3a3d6fa2 in start_thread #14 0x7f6f3a15b4ce in __clone Also reverts 7a3fb71, as it's now unneeded. Reviewed By: vitalybuka Differential Revision: https://reviews.llvm.org/D113045
1 parent 299aa4d commit 846ec2c

File tree

7 files changed

+53
-19
lines changed

7 files changed

+53
-19
lines changed

compiler-rt/lib/hwasan/hwasan.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ __attribute__((constructor(0))) void __hwasan_init() {
345345

346346
// Needs to be called here because flags()->random_tags might not have been
347347
// initialized when InitInstrumentation() was called.
348-
GetCurrentThread()->InitRandomState();
348+
GetCurrentThread()->EnsureRandomStateInited();
349349

350350
SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
351351
// This may call libc -> needs initialized shadow.

compiler-rt/lib/hwasan/hwasan_fuchsia.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ static void ThreadCreateHook(void *hook, bool aborted) {
130130
static void ThreadStartHook(void *hook, thrd_t self) {
131131
Thread *thread = static_cast<Thread *>(hook);
132132
FinishThreadInitialization(thread);
133-
thread->InitRandomState();
133+
thread->EnsureRandomStateInited();
134134
}
135135

136136
// This is the function that sets up the stack ring buffer and enables us to use

compiler-rt/lib/hwasan/hwasan_linux.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ void InstallAtExitHandler() { atexit(HwasanAtExit); }
250250
// ---------------------- TSD ---------------- {{{1
251251

252252
extern "C" void __hwasan_thread_enter() {
253-
hwasanThreadList().CreateCurrentThread()->InitRandomState();
253+
hwasanThreadList().CreateCurrentThread()->EnsureRandomStateInited();
254254
}
255255

256256
extern "C" void __hwasan_thread_exit() {

compiler-rt/lib/hwasan/hwasan_thread.cpp

+14-8
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11

2+
#include "hwasan_thread.h"
3+
24
#include "hwasan.h"
5+
#include "hwasan_interface_internal.h"
36
#include "hwasan_mapping.h"
4-
#include "hwasan_thread.h"
57
#include "hwasan_poisoning.h"
6-
#include "hwasan_interface_internal.h"
7-
8+
#include "sanitizer_common/sanitizer_atomic.h"
89
#include "sanitizer_common/sanitizer_file.h"
910
#include "sanitizer_common/sanitizer_placement_new.h"
1011
#include "sanitizer_common/sanitizer_tls_get_addr.h"
1112

12-
1313
namespace __hwasan {
1414

1515
static u32 RandomSeed() {
@@ -27,6 +27,7 @@ static u32 RandomSeed() {
2727

2828
void Thread::InitRandomState() {
2929
random_state_ = flags()->random_tags ? RandomSeed() : unique_id_;
30+
random_state_inited_ = true;
3031

3132
// Push a random number of zeros onto the ring buffer so that the first stack
3233
// tag base will be random.
@@ -40,8 +41,9 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size,
4041
CHECK_EQ(0, stack_top_);
4142
CHECK_EQ(0, stack_bottom_);
4243

43-
static u64 unique_id;
44-
unique_id_ = unique_id++;
44+
static atomic_uint64_t unique_id;
45+
unique_id_ = atomic_fetch_add(&unique_id, 1, memory_order_relaxed);
46+
4547
if (auto sz = flags()->heap_history_size)
4648
heap_allocations_ = HeapAllocationsRingBuffer::New(sz);
4749

@@ -123,17 +125,21 @@ static u32 xorshift(u32 state) {
123125
// Generate a (pseudo-)random non-zero tag.
124126
tag_t Thread::GenerateRandomTag(uptr num_bits) {
125127
DCHECK_GT(num_bits, 0);
126-
if (tagging_disabled_) return 0;
128+
if (tagging_disabled_)
129+
return 0;
127130
tag_t tag;
128131
const uptr tag_mask = (1ULL << num_bits) - 1;
129132
do {
130133
if (flags()->random_tags) {
131-
if (!random_buffer_)
134+
if (!random_buffer_) {
135+
EnsureRandomStateInited();
132136
random_buffer_ = random_state_ = xorshift(random_state_);
137+
}
133138
CHECK(random_buffer_);
134139
tag = random_buffer_ & tag_mask;
135140
random_buffer_ >>= num_bits;
136141
} else {
142+
EnsureRandomStateInited();
137143
random_state_ += 1;
138144
tag = random_state_ & tag_mask;
139145
}

compiler-rt/lib/hwasan/hwasan_thread.h

+9-1
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,17 @@ class Thread {
2828

2929
void Init(uptr stack_buffer_start, uptr stack_buffer_size,
3030
const InitState *state = nullptr);
31-
void InitRandomState();
31+
3232
void InitStackAndTls(const InitState *state = nullptr);
3333

3434
// Must be called from the thread itself.
3535
void InitStackRingBuffer(uptr stack_buffer_start, uptr stack_buffer_size);
3636

37+
inline void EnsureRandomStateInited() {
38+
if (UNLIKELY(!random_state_inited_))
39+
InitRandomState();
40+
}
41+
3742
void Destroy();
3843

3944
uptr stack_top() { return stack_top_; }
@@ -70,6 +75,7 @@ class Thread {
7075
// via mmap() and *must* be valid in zero-initialized state.
7176
void ClearShadowForThreadStackAndTLS();
7277
void Print(const char *prefix);
78+
void InitRandomState();
7379
uptr vfork_spill_;
7480
uptr stack_top_;
7581
uptr stack_bottom_;
@@ -89,6 +95,8 @@ class Thread {
8995

9096
bool announced_;
9197

98+
bool random_state_inited_; // Whether InitRandomState() has been called.
99+
92100
friend struct ThreadListHead;
93101
};
94102

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Tests that our thread initialization hooks work properly with random_tags=1.
2+
// RUN: %clang_hwasan %s -o %t
3+
// RUN: %env_hwasan_opts=random_tags=1 %run %t
4+
// REQUIRES: stable-runtime
5+
6+
#include <pthread.h>
7+
8+
#include <sanitizer/hwasan_interface.h>
9+
10+
volatile int state;
11+
12+
void *Increment(void *arg) {
13+
++state;
14+
return NULL;
15+
}
16+
17+
int main() {
18+
__hwasan_enable_allocator_tagging();
19+
pthread_t t1;
20+
pthread_create(&t1, NULL, Increment, NULL);
21+
pthread_join(t1, NULL);
22+
}

compiler-rt/test/hwasan/TestCases/thread-uaf.c

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// Tests UAF detection where Allocate/Deallocate/Use
22
// happen in separate threads.
3-
// RUN: %clang_hwasan %s -o %t && not %run %t > %t.out 2>&1
4-
// RUN: cat %t.out | FileCheck %s
5-
// RUN: cat %t.out | FileCheck --check-prefix=CHECK-THREAD %s
3+
// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s
64
// REQUIRES: stable-runtime
75

86
#include <pthread.h>
@@ -37,10 +35,10 @@ void *Use(void *arg) {
3735
// CHECK: in Deallocate
3836
// CHECK: previously allocated here:
3937
// CHECK: in Allocate
40-
// CHECK-THREAD-DAG: Thread: T2 0x
41-
// CHECK-THREAD-DAG: Thread: T3 0x
42-
// CHECK-THREAD-DAG: Thread: T0 0x
43-
// CHECK-THREAD-DAG: Thread: T1 0x
38+
// CHECK-DAG: Thread: T2 0x
39+
// CHECK-DAG: Thread: T3 0x
40+
// CHECK-DAG: Thread: T0 0x
41+
// CHECK-DAG: Thread: T1 0x
4442
__sync_fetch_and_add(&state, 1);
4543
return NULL;
4644
}

0 commit comments

Comments
 (0)