-
Notifications
You must be signed in to change notification settings - Fork 14.9k
Add API to temporalily disable usage of ASAN's fake stack #160135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-compiler-rt-sanitizer Author: None (happyCoder92) ChangesIntended use-case is for threads that use (or switch to) stack with special properties e.g. backed by MADV_DONTDUMP memory. Full diff: https://github.com/llvm/llvm-project/pull/160135.diff 10 Files Affected:
diff --git a/compiler-rt/include/sanitizer/asan_interface.h b/compiler-rt/include/sanitizer/asan_interface.h
index 37b6d08f4db19..06deb9116709f 100644
--- a/compiler-rt/include/sanitizer/asan_interface.h
+++ b/compiler-rt/include/sanitizer/asan_interface.h
@@ -333,6 +333,13 @@ 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);
+/// Disables fake stack usage for the current thread.
+/// Temporarily disables use-after-return detection for current thread.
+void SANITIZER_CDECL __asan_disable_fake_stack_usage(void);
+
+/// (Re)enables fake stack usage for the current thread.
+void SANITIZER_CDECL __asan_enable_fake_stack_usage(void);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/compiler-rt/lib/asan/asan_fake_stack.cpp b/compiler-rt/lib/asan/asan_fake_stack.cpp
index c3ed2526f0ed4..e1772997d681f 100644
--- a/compiler-rt/lib/asan/asan_fake_stack.cpp
+++ b/compiler-rt/lib/asan/asan_fake_stack.cpp
@@ -217,26 +217,44 @@ static THREADLOCAL FakeStack *fake_stack_tls;
FakeStack *GetTLSFakeStack() {
return fake_stack_tls;
}
-void SetTLSFakeStack(FakeStack *fs) {
+void SetTLSFakeStack(AsanThread* t, FakeStack *fs) {
+ if (fs && !t->fake_stack_usage_enabled()) {
+ return;
+ }
fake_stack_tls = fs;
}
#else
FakeStack *GetTLSFakeStack() { return 0; }
-void SetTLSFakeStack(FakeStack *fs) { }
+void SetTLSFakeStack(AsanThread* t, FakeStack *fs) { }
#endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA
-static FakeStack *GetFakeStack() {
+static void DisableFakeStackUsage() {
AsanThread *t = GetCurrentThread();
- if (!t) return nullptr;
+ if (t) {
+ t->set_fake_stack_usage_enabled(false);
+ }
+ SetTLSFakeStack(t, nullptr);
+}
+
+static void EnableFakeStackUsage() {
+ AsanThread *t = GetCurrentThread();
+ if (t) {
+ t->set_fake_stack_usage_enabled(true);
+ }
+}
+
+static FakeStack *GetFakeStack(bool for_allocation = true) {
+ AsanThread *t = GetCurrentThread();
+ if (!t || (for_allocation && !t->fake_stack_usage_enabled())) return nullptr;
return t->get_or_create_fake_stack();
}
-static FakeStack *GetFakeStackFast() {
+static FakeStack *GetFakeStackFast(bool for_allocation = true) {
if (FakeStack *fs = GetTLSFakeStack())
return fs;
if (!__asan_option_detect_stack_use_after_return)
return nullptr;
- return GetFakeStack();
+ return GetFakeStack(for_allocation);
}
static FakeStack *GetFakeStackFastAlways() {
@@ -311,7 +329,7 @@ extern "C" {
// -asan-use-after-return=never, after modal UAR flag lands
// (https://github.com/google/sanitizers/issues/1394)
SANITIZER_INTERFACE_ATTRIBUTE
-void *__asan_get_current_fake_stack() { return GetFakeStackFast(); }
+void *__asan_get_current_fake_stack() { return GetFakeStackFast(/*for_allocation=*/false); }
SANITIZER_INTERFACE_ATTRIBUTE
void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
@@ -349,4 +367,9 @@ void __asan_allocas_unpoison(uptr top, uptr bottom) {
(reinterpret_cast<void *>(MemToShadow(top)), 0,
(bottom - top) / ASAN_SHADOW_GRANULARITY);
}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_disable_fake_stack_usage() { return DisableFakeStackUsage(); }
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_enable_fake_stack_usage() { return EnableFakeStackUsage(); }
} // extern "C"
diff --git a/compiler-rt/lib/asan/asan_fake_stack.h b/compiler-rt/lib/asan/asan_fake_stack.h
index 50706e6e5876c..9f1f452834b97 100644
--- a/compiler-rt/lib/asan/asan_fake_stack.h
+++ b/compiler-rt/lib/asan/asan_fake_stack.h
@@ -18,6 +18,8 @@
namespace __asan {
+class AsanThread;
+
// Fake stack frame contains local variables of one function.
struct FakeFrame {
uptr magic; // Modified by the instrumented code.
@@ -196,7 +198,7 @@ class FakeStack {
};
FakeStack *GetTLSFakeStack();
-void SetTLSFakeStack(FakeStack *fs);
+void SetTLSFakeStack(AsanThread* t, FakeStack *fs);
} // namespace __asan
diff --git a/compiler-rt/lib/asan/asan_interface.inc b/compiler-rt/lib/asan/asan_interface.inc
index bfc44b4619623..a279ae834549a 100644
--- a/compiler-rt/lib/asan/asan_interface.inc
+++ b/compiler-rt/lib/asan/asan_interface.inc
@@ -15,6 +15,8 @@ INTERFACE_FUNCTION(__asan_alloca_poison)
INTERFACE_FUNCTION(__asan_allocas_unpoison)
INTERFACE_FUNCTION(__asan_before_dynamic_init)
INTERFACE_FUNCTION(__asan_describe_address)
+INTERFACE_FUNCTION(__asan_disable_fake_stack_usage)
+INTERFACE_FUNCTION(__asan_enable_fake_stack_usage)
INTERFACE_FUNCTION(__asan_exp_load1)
INTERFACE_FUNCTION(__asan_exp_load2)
INTERFACE_FUNCTION(__asan_exp_load4)
diff --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp
index 2627ae1289012..f6f54022bf377 100644
--- a/compiler-rt/lib/asan/asan_thread.cpp
+++ b/compiler-rt/lib/asan/asan_thread.cpp
@@ -163,7 +163,7 @@ void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom,
if (fake_stack_save)
*fake_stack_save = fake_stack_;
fake_stack_ = nullptr;
- SetTLSFakeStack(nullptr);
+ SetTLSFakeStack(this, nullptr);
// if fake_stack_save is null, the fiber will die, delete the fakestack
if (!fake_stack_save && current_fake_stack)
current_fake_stack->Destroy(this->tid());
@@ -177,7 +177,7 @@ void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save, uptr *bottom_old,
}
if (fake_stack_save) {
- SetTLSFakeStack(fake_stack_save);
+ SetTLSFakeStack(this, fake_stack_save);
fake_stack_ = fake_stack_save;
}
@@ -242,7 +242,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log));
fake_stack_ = FakeStack::Create(stack_size_log);
DCHECK_EQ(GetCurrentThread(), this);
- SetTLSFakeStack(fake_stack_);
+ SetTLSFakeStack(this, fake_stack_);
return fake_stack_;
}
return nullptr;
@@ -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_usage_enabled_ = true;
atomic_store(&stack_switching_, false, memory_order_release);
CHECK_EQ(this->stack_size(), 0U);
SetThreadStackAndTls(options);
diff --git a/compiler-rt/lib/asan/asan_thread.h b/compiler-rt/lib/asan/asan_thread.h
index 12f0cc7a62dae..c54bbb1c64604 100644
--- a/compiler-rt/lib/asan/asan_thread.h
+++ b/compiler-rt/lib/asan/asan_thread.h
@@ -104,7 +104,7 @@ class AsanThread {
if (!fake_stack_) return;
FakeStack *t = fake_stack_;
fake_stack_ = nullptr;
- SetTLSFakeStack(nullptr);
+ SetTLSFakeStack(this, nullptr);
t->Destroy(tid);
}
@@ -144,6 +144,11 @@ class AsanThread {
GetStartData(&data, sizeof(data));
}
+ bool fake_stack_usage_enabled() const { return fake_stack_usage_enabled_; }
+ void set_fake_stack_usage_enabled(bool enabled) {
+ fake_stack_usage_enabled_ = enabled;
+ }
+
private:
// NOTE: There is no AsanThread constructor. It is allocated
// via mmap() and *must* be valid in zero-initialized state.
@@ -179,6 +184,7 @@ class AsanThread {
DTLS *dtls_;
FakeStack *fake_stack_;
+ bool fake_stack_usage_enabled_;
AsanThreadLocalMallocStorage malloc_storage_;
AsanStats stats_;
bool unwinding_;
diff --git a/compiler-rt/lib/asan_abi/asan_abi.cpp b/compiler-rt/lib/asan_abi/asan_abi.cpp
index cf8663024eb73..c2bf2f52dd4e5 100644
--- a/compiler-rt/lib/asan_abi/asan_abi.cpp
+++ b/compiler-rt/lib/asan_abi/asan_abi.cpp
@@ -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_disable_fake_stack_usage(void) {}
+void __asan_abi_enable_fake_stack_usage(void) {}
// Functions concerning poisoning and unpoisoning fake stack alloca
void __asan_abi_alloca_poison(void *addr, size_t size) {}
diff --git a/compiler-rt/lib/asan_abi/asan_abi.h b/compiler-rt/lib/asan_abi/asan_abi.h
index 8702bcd133919..372e44e755cc5 100644
--- a/compiler-rt/lib/asan_abi/asan_abi.h
+++ b/compiler-rt/lib/asan_abi/asan_abi.h
@@ -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_disable_fake_stack_usage();
+void *__asan_abi_enable_fake_stack_usage();
+
// 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);
diff --git a/compiler-rt/lib/asan_abi/asan_abi_shim.cpp b/compiler-rt/lib/asan_abi/asan_abi_shim.cpp
index 2512abc641250..0b4a170015b61 100644
--- a/compiler-rt/lib/asan_abi/asan_abi_shim.cpp
+++ b/compiler-rt/lib/asan_abi/asan_abi_shim.cpp
@@ -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_disable_fake_stack_usage(void) {
+ return __asan_abi_disable_fake_stack_usage();
+}
+void __asan_enable_fake_stack_usage(void) {
+ return __asan_abi_enable_fake_stack_usage();
+}
// Functions concerning poisoning and unpoisoning fake stack alloca
void __asan_alloca_poison(uptr addr, uptr size) {
diff --git a/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp b/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp
new file mode 100644
index 0000000000000..b1ee8d72e2b58
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/disable_fake_stack.cpp
@@ -0,0 +1,27 @@
+// RUN: %clangxx_asan %s -o %t && %run %t
+
+#include "defines.h"
+
+#include <sanitizer/asan_interface.h>
+
+volatile char *saved;
+
+ATTRIBUTE_NOINLINE bool IsOnStack() {
+ volatile char temp = ' ';
+ void* fake_stack = __asan_get_current_fake_stack();
+ void* real = __asan_addr_is_in_fake_stack(fake_stack, const_cast<char*>(&temp), nullptr, nullptr);
+ saved = &temp;
+ return real == nullptr;
+}
+
+int main(int argc, char *argv[]) {
+ __asan_disable_fake_stack_usage();
+ if (!IsOnStack()) {
+ return 1;
+ }
+ __asan_enable_fake_stack_usage();
+ if (IsOnStack()) {
+ return 2;
+ }
+ return 0;
+}
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
I thought StartSwitchFiber was added for that I am not sure I understand what is special with MADV_DONTDUMP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comments above
Addressed the comments. |
@@ -311,7 +329,9 @@ extern "C" { | |||
// -asan-use-after-return=never, after modal UAR flag lands | |||
// (https://github.com/google/sanitizers/issues/1394) | |||
SANITIZER_INTERFACE_ATTRIBUTE | |||
void *__asan_get_current_fake_stack() { return GetFakeStackFast(); } | |||
void* __asan_get_current_fake_stack() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is TODO for to remove this one
if this is just for test, can we instead rely on __asan_get_current_fake_stack
Use __builtin_frame_address
__builtin_frame_address always return real stack address
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the argument and adjusted the test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you forget to upload the patch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have rebased and updated it
@@ -217,26 +217,44 @@ static THREADLOCAL FakeStack *fake_stack_tls; | |||
FakeStack *GetTLSFakeStack() { | |||
return fake_stack_tls; | |||
} | |||
void SetTLSFakeStack(FakeStack *fs) { | |||
void SetTLSFakeStack(AsanThread* t, FakeStack* fs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will #163481 help to simplify this patch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slightly. By only calling SetTLSFakeStack
from GetFakeStack
#163481 also indirectly ensures the tls var won't be set if fake stack is disabled. I added the thread arg and put the logic into SetTLSFakeStack
to make it more explicit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PTAL
Intended use-case is for threads that use (or switch to) stack with special properties e.g. backed by MADV_DONTDUMP memory.
Intended use-case is for threads that use (or switch to) stack with special properties e.g. backed by MADV_DONTDUMP memory.
This reverts commit 4e72801.
@happyCoder92 can you please elaborate description message? |
…SFakeStack (#163674) To simplify implementation of llvm/llvm-project#160135 To keep the logic of figuring out what should be in TLS to one place. The rest of the code should just reset it and rely on GetFakeStackFast()/GetFakeStackFastAlways().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the intended interaction of this API with -mllvm -asan-use-after-return={never,runtime,always}
and ASAN_OPTIONS=detect_stack_use_after_return={0,1}
? Please update the description and TestCases/disable_fake_stack.cpp
to clarify.
Also, if the behavior of __asan_disable_fake_stack()
/__asan_enable_fake_stack()
depends on those flags, the naming could be confusing.
The behavior does depend on the flags. Would |
Intended use-case is for threads that use (or switch to) stack with special properties e.g. backed by MADV_DONTDUMP memory.