Skip to content

Commit c10e568

Browse files
happyCoder92vitalybuka
authored andcommitted
Add API to temporalily disable usage of ASAN's fake stack
Intended use-case is for threads that use (or switch to) stack with special properties e.g. backed by MADV_DONTDUMP memory.
1 parent f98b955 commit c10e568

File tree

9 files changed

+76
-3
lines changed

9 files changed

+76
-3
lines changed

compiler-rt/include/sanitizer/asan_interface.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,13 @@ void SANITIZER_CDECL __asan_handle_no_return(void);
333333
/// trace. Returns 1 if successful, 0 if not.
334334
int SANITIZER_CDECL __asan_update_allocation_context(void *addr);
335335

336+
/// Disables fake stack for the current thread.
337+
/// Temporarily disables use-after-return detection for current thread.
338+
void SANITIZER_CDECL __asan_disable_fake_stack(void);
339+
340+
/// (Re)enables fake stack for the current thread.
341+
void SANITIZER_CDECL __asan_enable_fake_stack(void);
342+
336343
#ifdef __cplusplus
337344
} // extern "C"
338345
#endif

compiler-rt/lib/asan/asan_fake_stack.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,17 +217,33 @@ void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void* arg) {
217217
static THREADLOCAL FakeStack* fake_stack_tls;
218218

219219
static FakeStack* GetTLSFakeStack() { return fake_stack_tls; }
220-
static void SetTLSFakeStack(FakeStack* fs) { fake_stack_tls = fs; }
220+
static void SetTLSFakeStack(FakeStack* fs) {
221+
fake_stack_tls = fs;
222+
}
221223
void ResetTLSFakeStack() { fake_stack_tls = nullptr; }
222224
#else
223225
static FakeStack* GetTLSFakeStack() { return nullptr; }
224-
static void SetTLSFakeStack(FakeStack*) {}
226+
static void SetTLSFakeStack(FakeStack* fs) {}
225227
void ResetTLSFakeStack() {}
226228
#endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA
227229

230+
static void DisableFakeStack() {
231+
AsanThread* t = GetCurrentThread();
232+
if (t) {
233+
t->SetFakeStackEnabled(false);
234+
}
235+
}
236+
237+
static void EnableFakeStack() {
238+
AsanThread* t = GetCurrentThread();
239+
if (t) {
240+
t->SetFakeStackEnabled(true);
241+
}
242+
}
243+
228244
static FakeStack* GetFakeStack() {
229245
AsanThread* t = GetCurrentThread();
230-
if (!t)
246+
if (!t || !t->IsFakeStackEnabled())
231247
return nullptr;
232248
return t->get_or_create_fake_stack();
233249
}
@@ -362,4 +378,9 @@ void __asan_allocas_unpoison(uptr top, uptr bottom) {
362378
REAL(memset)(reinterpret_cast<void*>(MemToShadow(top)), 0,
363379
(bottom - top) / ASAN_SHADOW_GRANULARITY);
364380
}
381+
382+
SANITIZER_INTERFACE_ATTRIBUTE
383+
void __asan_disable_fake_stack() { return DisableFakeStack(); }
384+
SANITIZER_INTERFACE_ATTRIBUTE
385+
void __asan_enable_fake_stack() { return EnableFakeStack(); }
365386
} // extern "C"

compiler-rt/lib/asan/asan_interface.inc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ INTERFACE_FUNCTION(__asan_alloca_poison)
1515
INTERFACE_FUNCTION(__asan_allocas_unpoison)
1616
INTERFACE_FUNCTION(__asan_before_dynamic_init)
1717
INTERFACE_FUNCTION(__asan_describe_address)
18+
INTERFACE_FUNCTION(__asan_disable_fake_stack)
19+
INTERFACE_FUNCTION(__asan_enable_fake_stack)
1820
INTERFACE_FUNCTION(__asan_exp_load1)
1921
INTERFACE_FUNCTION(__asan_exp_load2)
2022
INTERFACE_FUNCTION(__asan_exp_load4)

compiler-rt/lib/asan/asan_thread.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
251251
void AsanThread::Init(const InitOptions *options) {
252252
DCHECK_NE(tid(), kInvalidTid);
253253
next_stack_top_ = next_stack_bottom_ = 0;
254+
fake_stack_enabled_ = true;
254255
atomic_store(&stack_switching_, false, memory_order_release);
255256
CHECK_EQ(this->stack_size(), 0U);
256257
SetThreadStackAndTls(options);

compiler-rt/lib/asan/asan_thread.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@ class AsanThread {
144144
GetStartData(&data, sizeof(data));
145145
}
146146

147+
bool IsFakeStackEnabled() const { return fake_stack_enabled_; }
148+
void SetFakeStackEnabled(bool enabled) {
149+
fake_stack_enabled_ = enabled;
150+
ResetTLSFakeStack();
151+
}
152+
147153
private:
148154
// NOTE: There is no AsanThread constructor. It is allocated
149155
// via mmap() and *must* be valid in zero-initialized state.
@@ -179,6 +185,7 @@ class AsanThread {
179185
DTLS *dtls_;
180186

181187
FakeStack *fake_stack_;
188+
bool fake_stack_enabled_;
182189
AsanThreadLocalMallocStorage malloc_storage_;
183190
AsanStats stats_;
184191
bool unwinding_;

compiler-rt/lib/asan_abi/asan_abi.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ void *__asan_abi_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
7373
void **end) {
7474
return NULL;
7575
}
76+
void __asan_abi_disable_fake_stack(void) {}
77+
void __asan_abi_enable_fake_stack(void) {}
7678

7779
// Functions concerning poisoning and unpoisoning fake stack alloca
7880
void __asan_abi_alloca_poison(void *addr, size_t size) {}

compiler-rt/lib/asan_abi/asan_abi.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ void *__asan_abi_load_cxx_array_cookie(void **p);
7676
void *__asan_abi_get_current_fake_stack();
7777
void *__asan_abi_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
7878
void **end);
79+
void *__asan_abi_disable_fake_stack();
80+
void *__asan_abi_enable_fake_stack();
81+
7982
// Functions concerning poisoning and unpoisoning fake stack alloca
8083
void __asan_abi_alloca_poison(void *addr, size_t size);
8184
void __asan_abi_allocas_unpoison(void *top, void *bottom);

compiler-rt/lib/asan_abi/asan_abi_shim.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,8 @@ void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
365365
void **end) {
366366
return __asan_abi_addr_is_in_fake_stack(fake_stack, addr, beg, end);
367367
}
368+
void __asan_disable_fake_stack(void) { return __asan_abi_disable_fake_stack(); }
369+
void __asan_enable_fake_stack(void) { return __asan_abi_enable_fake_stack(); }
368370

369371
// Functions concerning poisoning and unpoisoning fake stack alloca
370372
void __asan_alloca_poison(uptr addr, uptr size) {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %clangxx_asan %s -o %t && %run %t
2+
3+
#include "defines.h"
4+
5+
#include <sanitizer/asan_interface.h>
6+
7+
volatile char *saved;
8+
9+
ATTRIBUTE_NOINLINE bool IsOnStack() {
10+
volatile char temp = ' ';
11+
void *fake_stack = __asan_get_current_fake_stack();
12+
void *real = __asan_addr_is_in_fake_stack(
13+
fake_stack, const_cast<char *>(&temp), nullptr, nullptr);
14+
saved = &temp;
15+
return real == nullptr;
16+
}
17+
18+
int main(int argc, char *argv[]) {
19+
__asan_disable_fake_stack();
20+
if (!IsOnStack()) {
21+
return 1;
22+
}
23+
__asan_enable_fake_stack();
24+
if (IsOnStack()) {
25+
return 2;
26+
}
27+
return 0;
28+
}

0 commit comments

Comments
 (0)