Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions compiler-rt/include/sanitizer/asan_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,14 @@ void SANITIZER_CDECL __asan_handle_no_return(void);
/// trace. Returns 1 if successful, 0 if not.
int SANITIZER_CDECL __asan_update_allocation_context(void *addr);

/// Suppresses fake stack for the current thread.
/// Temporarily disables use-after-return detection for current thread.
void SANITIZER_CDECL __asan_suppress_fake_stack(void);

/// Unsupresses fake stack for the current thread.
/// Should be paired with a previous __asan_suppress_fake_stack() call.
void SANITIZER_CDECL __asan_unsuppress_fake_stack(void);

#ifdef __cplusplus
} // extern "C"
#endif
Expand Down
21 changes: 20 additions & 1 deletion compiler-rt/lib/asan/asan_fake_stack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,23 @@ static void SetTLSFakeStack(FakeStack*) {}
void ResetTLSFakeStack() {}
#endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA

static void SuppressFakeStack() {
AsanThread* t = GetCurrentThread();
if (t) {
t->SuppressFakeStack();
}
}

static void UnsuppressFakeStack() {
AsanThread* t = GetCurrentThread();
if (t) {
t->UnsuppressFakeStack();
}
}

static FakeStack* GetFakeStack() {
AsanThread* t = GetCurrentThread();
if (!t)
if (!t || t->IsFakeStackSuppressed())
return nullptr;
return t->get_or_create_fake_stack();
}
Expand Down Expand Up @@ -362,4 +376,9 @@ void __asan_allocas_unpoison(uptr top, uptr bottom) {
REAL(memset)(reinterpret_cast<void*>(MemToShadow(top)), 0,
(bottom - top) / ASAN_SHADOW_GRANULARITY);
}

SANITIZER_INTERFACE_ATTRIBUTE
void __asan_suppress_fake_stack() { return SuppressFakeStack(); }
SANITIZER_INTERFACE_ATTRIBUTE
void __asan_unsuppress_fake_stack() { return UnsuppressFakeStack(); }
} // extern "C"
2 changes: 2 additions & 0 deletions compiler-rt/lib/asan/asan_interface.inc
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,14 @@ INTERFACE_FUNCTION(__asan_store4_noabort)
INTERFACE_FUNCTION(__asan_store8_noabort)
INTERFACE_FUNCTION(__asan_store16_noabort)
INTERFACE_FUNCTION(__asan_storeN_noabort)
INTERFACE_FUNCTION(__asan_suppress_fake_stack)
INTERFACE_FUNCTION(__asan_unpoison_intra_object_redzone)
INTERFACE_FUNCTION(__asan_unpoison_memory_region)
INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
INTERFACE_FUNCTION(__asan_unregister_globals)
INTERFACE_FUNCTION(__asan_unregister_elf_globals)
INTERFACE_FUNCTION(__asan_unregister_image_globals)
INTERFACE_FUNCTION(__asan_unsuppress_fake_stack)
INTERFACE_FUNCTION(__asan_version_mismatch_check_v8)
INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber)
INTERFACE_FUNCTION(__sanitizer_print_stack_trace)
Expand Down
14 changes: 14 additions & 0 deletions compiler-rt/lib/asan/asan_thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
void AsanThread::Init(const InitOptions *options) {
DCHECK_NE(tid(), kInvalidTid);
next_stack_top_ = next_stack_bottom_ = 0;
fake_stack_suppression_counter_ = 0;
atomic_store(&stack_switching_, false, memory_order_release);
CHECK_EQ(this->stack_size(), 0U);
SetThreadStackAndTls(options);
Expand Down Expand Up @@ -404,6 +405,19 @@ bool AsanThread::AddrIsInStack(uptr addr) {
return addr >= bounds.bottom && addr < bounds.top;
}

void AsanThread::SuppressFakeStack() {
++fake_stack_suppression_counter_;
ResetTLSFakeStack();
}

void AsanThread::UnsuppressFakeStack() {
if (fake_stack_suppression_counter_ == 0) {
Report("ERROR: Unmatched call to __asan_unsuppress_fake_stack().\n");
Die();
}
--fake_stack_suppression_counter_;
}

static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
void *addr) {
AsanThreadContext *tctx = static_cast<AsanThreadContext *>(tctx_base);
Expand Down
7 changes: 7 additions & 0 deletions compiler-rt/lib/asan/asan_thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ class AsanThread {
GetStartData(&data, sizeof(data));
}

bool IsFakeStackSuppressed() const {
return fake_stack_suppression_counter_ > 0;
}
void SuppressFakeStack();
void UnsuppressFakeStack();

private:
// NOTE: There is no AsanThread constructor. It is allocated
// via mmap() and *must* be valid in zero-initialized state.
Expand Down Expand Up @@ -179,6 +185,7 @@ class AsanThread {
DTLS *dtls_;

FakeStack *fake_stack_;
int fake_stack_suppression_counter_;
AsanThreadLocalMallocStorage malloc_storage_;
AsanStats stats_;
bool unwinding_;
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/asan_abi/asan_abi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ void *__asan_abi_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
void **end) {
return NULL;
}
void __asan_abi_suppress_fake_stack(void) {}
void __asan_abi_unsuppress_fake_stack(void) {}

// Functions concerning poisoning and unpoisoning fake stack alloca
void __asan_abi_alloca_poison(void *addr, size_t size) {}
Expand Down
3 changes: 3 additions & 0 deletions compiler-rt/lib/asan_abi/asan_abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ void *__asan_abi_load_cxx_array_cookie(void **p);
void *__asan_abi_get_current_fake_stack();
void *__asan_abi_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
void **end);
void *__asan_abi_suppress_fake_stack();
void *__asan_abi_unsuppress_fake_stack();

// Functions concerning poisoning and unpoisoning fake stack alloca
void __asan_abi_alloca_poison(void *addr, size_t size);
void __asan_abi_allocas_unpoison(void *top, void *bottom);
Expand Down
6 changes: 6 additions & 0 deletions compiler-rt/lib/asan_abi/asan_abi_shim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,12 @@ void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
void **end) {
return __asan_abi_addr_is_in_fake_stack(fake_stack, addr, beg, end);
}
void __asan_suppress_fake_stack(void) {
return __asan_abi_suppress_fake_stack();
}
void __asan_unsuppress_fake_stack(void) {
return __asan_abi_unsuppress_fake_stack();
}

// Functions concerning poisoning and unpoisoning fake stack alloca
void __asan_alloca_poison(uptr addr, uptr size) {
Expand Down
39 changes: 39 additions & 0 deletions compiler-rt/test/asan/TestCases/suppress_fake_stack.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// RUN: %clangxx_asan %s -o %t && env ASAN_OPTIONS=detect_stack_use_after_return=1 %run %t
// RUN: %clangxx_asan %s -mllvm -asan-use-after-return=runtime -o %t && env ASAN_OPTIONS=detect_stack_use_after_return=1 %run %t
// RUN: %clangxx_asan %s -mllvm -asan-use-after-return=always -o %t && %run %t

#include "defines.h"

#include <cassert>
#include <sanitizer/asan_interface.h>

volatile uintptr_t saved;

ATTRIBUTE_NOINLINE bool IsOnRealStack(uintptr_t parent_frame,
uintptr_t var_addr) {
uintptr_t this_frame =
reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
return this_frame <= var_addr && var_addr <= parent_frame;
}

ATTRIBUTE_NOINLINE bool IsOnRealStack(uintptr_t parent_frame) {
volatile char temp = ' ';
saved = reinterpret_cast<uintptr_t>(&temp);
return IsOnRealStack(parent_frame, saved);
}

ATTRIBUTE_NOINLINE bool IsOnRealStack() {
return IsOnRealStack(reinterpret_cast<uintptr_t>(__builtin_frame_address(0)));
}

int main(int argc, char *argv[]) {
assert(!IsOnRealStack());

__asan_suppress_fake_stack();
assert(IsOnRealStack());

__asan_unsuppress_fake_stack();
assert(!IsOnRealStack());

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Check unsuppressing fake stack does not reenable it if disabled via compile or runtime options.
//
// RUN: %clangxx_asan %s -mllvm -asan-use-after-return=never -o %t && %run %t
// RUN: %clangxx_asan %s -mllvm -asan-use-after-return=runtime -o %t && env ASAN_OPTIONS=detect_stack_use_after_return=0 %run %t

#include "defines.h"

#include <cassert>
#include <sanitizer/asan_interface.h>

volatile uintptr_t saved;

ATTRIBUTE_NOINLINE bool IsOnRealStack(uintptr_t parent_frame,
uintptr_t var_addr) {
uintptr_t this_frame =
reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
return this_frame <= var_addr && var_addr <= parent_frame;
}

ATTRIBUTE_NOINLINE bool IsOnRealStack(uintptr_t parent_frame) {
volatile char temp = ' ';
saved = reinterpret_cast<uintptr_t>(&temp);
return IsOnRealStack(parent_frame, saved);
}

ATTRIBUTE_NOINLINE bool IsOnRealStack() {
return IsOnRealStack(reinterpret_cast<uintptr_t>(__builtin_frame_address(0)));
}

int main(int argc, char *argv[]) {
assert(IsOnRealStack());

__asan_suppress_fake_stack();
assert(IsOnRealStack());

__asan_unsuppress_fake_stack();
assert(IsOnRealStack());

return 0;
}