From 5d7e930c9c52f41cd5475c638b050a0aaf3d43f8 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Fri, 26 Sep 2025 20:59:51 +0000 Subject: [PATCH 01/16] [sanitizer] Add cloak_sanitizer_signal_handlers runtime option If set, signal/sigaction will pretend that the sanitizers did not preinstall any signal handlers. If a user successfully installs a signal handler, it will not be cloaked. The flag is currently off by default, which means this patch should not affect the behavior of any sanitizers. This can be useful in an ecosystem where: 1) there exists a library that will install a signal handler iff it does not detect a preinstalled signal handler (a heuristic to prevent overriding user-installed exception handlers etc.) 2) the aforementioned library is linked in to some, but not all, apps 3) user-installed signal handlers have the highest priority, followed by the library-installed signal handler, and then the sanitizer's signal handler This patch also adds an API function, __sanitizer_uncloak_preinstalled_signal_handlers(), that can be used to effectively undo the runtime option. This makes it possible to set the cloak_sanitizer_signal_handlers option broadly, and selectively programmatically disable it for incompatible programs (e.g., allow_user_segv.cpp, which wants to manually call ASan's preinstalled handler). The flag is in sanitizer_common, though it is currently only supported in ASan, LSan and UBSan. --- .../include/sanitizer/common_interface_defs.h | 5 ++ .../lib/sanitizer_common/sanitizer_common.cpp | 8 +++ .../lib/sanitizer_common/sanitizer_common.h | 3 ++ .../sanitizer_common_interface.inc | 1 + .../lib/sanitizer_common/sanitizer_flags.inc | 5 ++ .../sanitizer_posix_libcdep.cpp | 12 ++--- .../sanitizer_signal_interceptors.inc | 45 +++++++++++++++-- .../TestCases/Linux/allow_user_segv.cpp | 5 ++ .../TestCases/Linux/cloak_sigaction.cpp | 49 +++++++++++++++++++ .../TestCases/Linux/cloak_signal.cpp | 44 +++++++++++++++++ 10 files changed, 167 insertions(+), 10 deletions(-) create mode 100644 compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp create mode 100644 compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp diff --git a/compiler-rt/include/sanitizer/common_interface_defs.h b/compiler-rt/include/sanitizer/common_interface_defs.h index 57313f9bc80e6..83b333d1f44fc 100644 --- a/compiler-rt/include/sanitizer/common_interface_defs.h +++ b/compiler-rt/include/sanitizer/common_interface_defs.h @@ -485,6 +485,11 @@ void SANITIZER_CDECL __sanitizer_finish_switch_fiber(void *fake_stack_save, int SANITIZER_CDECL __sanitizer_get_module_and_offset_for_pc( void *pc, char *module_path, size_t module_path_len, void **pc_offset); +// If cloak_sanitizer_signal_handlers() is set, signal/sigaction will pretend +// that sanitizers did not preinstall any signal handlers. This function clears +// the cloaking state. +void SANITIZER_CDECL __sanitizer_uncloak_preinstalled_signal_handlers(); + #ifdef __cplusplus } // extern "C" #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp index 6cd69a53093e7..5e39de4e8b8be 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp @@ -24,6 +24,8 @@ namespace __sanitizer { const char *SanitizerToolName = "SanitizerTool"; +bool signal_handler_is_from_sanitizer[MaxSignals] = {0}; + atomic_uint32_t current_verbosity; uptr PageSizeCached; u32 NumberOfCPUsCached; @@ -416,6 +418,12 @@ int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *, return InstallMallocFreeHooks(malloc_hook, free_hook); } +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_uncloak_preinstalled_signal_handlers() { + internal_memset(signal_handler_is_from_sanitizer, 0, + sizeof(signal_handler_is_from_sanitizer)); +} + // Provide default (no-op) implementation of malloc hooks. SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook, void *ptr, uptr size) { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h index 3e82df498572c..10bd83118e9a4 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -52,6 +52,9 @@ const u64 kExternalPCBit = 1ULL << 60; extern const char *SanitizerToolName; // Can be changed by the tool. +const int MaxSignals = 64; +extern bool signal_handler_is_from_sanitizer[MaxSignals]; + extern atomic_uint32_t current_verbosity; inline void SetVerbosity(int verbosity) { atomic_store(¤t_verbosity, verbosity, memory_order_relaxed); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc index 4ea75cdd67cb9..706b7b0d220a8 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc @@ -24,6 +24,7 @@ INTERFACE_WEAK_FUNCTION(__sanitizer_on_print) INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary) INTERFACE_WEAK_FUNCTION(__sanitizer_sandbox_on_notify) INTERFACE_WEAK_FUNCTION(__sanitizer_get_dtls_size) +INTERFACE_FUNCTION(__sanitizer_uncloak_preinstalled_signal_handlers) // Sanitizer weak hooks INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_memcmp) INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_strcmp) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc index 650a4580bbcf0..5f449907f6011 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc @@ -113,6 +113,11 @@ COMMON_FLAG(HandleSignalMode, handle_sigfpe, kHandleSignalYes, COMMON_FLAG(bool, allow_user_segv_handler, true, "Deprecated. True has no effect, use handle_sigbus=1. If false, " "handle_*=1 will be upgraded to handle_*=2.") +COMMON_FLAG(bool, cloak_sanitizer_signal_handlers, false, + "If set, signal/sigaction will pretend that sanitizers did not " + "preinstall any signal handlers. If the user subsequently installs " + "a signal handler, this will disable cloaking for the respective " + "signal.") COMMON_FLAG(bool, use_sigaltstack, true, "If set, uses alternate stack for signal handling.") COMMON_FLAG(bool, detect_deadlocks, true, diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index b1eb2009cf157..e45cc57387dc0 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -223,6 +223,9 @@ static void MaybeInstallSigaction(int signum, if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; CHECK_EQ(0, internal_sigaction(signum, &sigact, nullptr)); VReport(1, "Installed the sigaction for signal %d\n", signum); + + if (common_flags()->cloak_sanitizer_signal_handlers) + signal_handler_is_from_sanitizer[signum] = true; } void InstallDeadlySignalHandlers(SignalHandlerType handler) { @@ -230,12 +233,9 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) { // This will cause SetAlternateSignalStack to be called twice, but the stack // will be actually set only once. if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); - MaybeInstallSigaction(SIGSEGV, handler); - MaybeInstallSigaction(SIGBUS, handler); - MaybeInstallSigaction(SIGABRT, handler); - MaybeInstallSigaction(SIGFPE, handler); - MaybeInstallSigaction(SIGILL, handler); - MaybeInstallSigaction(SIGTRAP, handler); + + int signals[] = {SIGSEGV, SIGBUS, SIGABRT, SIGFPE, SIGILL, SIGTRAP}; + for (int signum : signals) MaybeInstallSigaction(signum, handler); } bool SignalContext::IsStackOverflow() const { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc index 94e4e2954a3b9..b26276792d7b3 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc @@ -24,8 +24,10 @@ using namespace __sanitizer; #endif #ifndef SIGNAL_INTERCEPTOR_SIGNAL_IMPL -#define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signum, handler) \ - { return REAL(func)(signum, handler); } +# define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signum, handler) \ + { \ + ret = REAL(func)(signum, handler); \ + } #endif #ifndef SIGNAL_INTERCEPTOR_SIGACTION_IMPL @@ -35,9 +37,10 @@ using namespace __sanitizer; Printf( \ "Warning: REAL(sigaction_symname) == nullptr. This may happen " \ "if you link with ubsan statically. Sigaction will not work.\n"); \ - return -1; \ + ret = -1; \ + } else { \ + ret = REAL(sigaction_symname)(signum, act, oldact); \ } \ - return REAL(sigaction_symname)(signum, act, oldact); \ } #endif @@ -45,7 +48,10 @@ using namespace __sanitizer; INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) { SIGNAL_INTERCEPTOR_ENTER(); if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0; + + int ret; SIGNAL_INTERCEPTOR_SIGNAL_IMPL(bsd_signal, signum, handler); + return ret; } #define INIT_BSD_SIGNAL COMMON_INTERCEPT_FUNCTION(bsd_signal) #else // SANITIZER_INTERCEPT_BSD_SIGNAL @@ -56,19 +62,50 @@ INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) { INTERCEPTOR(uptr, signal, int signum, uptr handler) { SIGNAL_INTERCEPTOR_ENTER(); if (GetHandleSignalMode(signum) == kHandleSignalExclusive) + // A side-effect is that a user can never uncloak the sanitizer's + // preinstalled signal handler. return (uptr) nullptr; + uptr ret; SIGNAL_INTERCEPTOR_SIGNAL_IMPL(signal, signum, handler); + + if (signum >= 0 && signum < MaxSignals && + signal_handler_is_from_sanitizer[signum] && ret != sig_err) { + // If the user sets a signal handler, it is never cloaked, even if they + // reuse a sanitizer's signal handler. + signal_handler_is_from_sanitizer[signum] = false; + + ret = sig_dfl; + } + + return ret; } #define INIT_SIGNAL COMMON_INTERCEPT_FUNCTION(signal) INTERCEPTOR(int, sigaction_symname, int signum, const __sanitizer_sigaction *act, __sanitizer_sigaction *oldact) { SIGNAL_INTERCEPTOR_ENTER(); + if (GetHandleSignalMode(signum) == kHandleSignalExclusive) { if (!oldact) return 0; act = nullptr; + // A side-effect is that a user can never uncloak the sanitizer's + // preinstalled signal handler. } + int ret; SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); + + if (signum >= 0 && signum < MaxSignals && + signal_handler_is_from_sanitizer[signum] && ret == 0) { + if (act) + // If the user sets a signal handler, it is never cloaked, even if they + // reuse a sanitizer's signal handler. + signal_handler_is_from_sanitizer[signum] = false; + + if (oldact) + oldact->handler = reinterpret_cast<__sanitizer_sighandler_ptr>(sig_dfl); + } + + return ret; } #define INIT_SIGACTION COMMON_INTERCEPT_FUNCTION(sigaction_symname) diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cpp index 1c740153a81d7..d4f7816dc68f1 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cpp @@ -23,6 +23,7 @@ // Flaky errors in debuggerd with "waitpid returned unexpected pid (0)" in logcat. // UNSUPPORTED: android && i386-target-arch +#include #include #include #include @@ -68,6 +69,10 @@ bool InstallHandler(int signum, struct sigaction *original_sigaction) { } int main() { + // This test case is unusual because it retrieves the original + // (ASan-installed) signal handler; thus, we don't want ASan to cloak them. + __sanitizer_uncloak_preinstalled_signal_handlers(); + // Let's install handlers for both SIGSEGV and SIGBUS, since pre-Yosemite // 32-bit Darwin triggers SIGBUS instead. if (InstallHandler(SIGSEGV, &original_sigaction_sigsegv) && diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp new file mode 100644 index 0000000000000..50b3e0a80a5bf --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp @@ -0,0 +1,49 @@ +// XFAIL: msan +// XFAIL: tsan + +// UNSUPPORTED: android +// UNSUPPORTED: hwasan + +// RUN: %clangxx -O0 %s -o %t + +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefix=UNCLOAKED +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefix=CLOAKED + +// RUN: %clangxx -O0 %s -DUNCLOAK_RT -o %t +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefix=UNCLOAKED +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefix=UNCLOAKED + +#include +#include +#include +#include + +void handler(int signum, siginfo_t *info, void *context) { + printf("Custom signal handler\n"); + exit(1); +} + +int main(int argc, char *argv[]) { +#ifdef UNCLOAK_RT + __sanitizer_uncloak_preinstalled_signal_handlers(); +#endif + + struct sigaction sa = {0}; + struct sigaction old = {0}; + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = &handler; + sigaction(SIGSEGV, &sa, &old); + + if (reinterpret_cast(old.sa_sigaction) == SIG_DFL) + printf("Old handler: default\n"); + // CLOAKED: Old handler: default + else + printf("Old handler: non-default\n"); + // UNCLOAKED: Old handler: non-default + + char *c = (char *)0x123; + printf("%d\n", *c); + // UNCLOAKED,CLOAKED:Custom signal handler + + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp new file mode 100644 index 0000000000000..4e7d1b2a475a6 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp @@ -0,0 +1,44 @@ +// XFAIL: msan +// XFAIL: tsan + +// UNSUPPORTED: android +// UNSUPPORTED: hwasan + +// RUN: %clangxx -O0 %s -o %t + +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefix=UNCLOAKED +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefix=CLOAKED + +// RUN: %clangxx -O0 %s -DUNCLOAK_RT -o %t +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefix=UNCLOAKED +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefix=UNCLOAKED + +#include +#include +#include +#include + +void my_signal_sighandler(int signum) { + printf("Custom signal handler\n"); + exit(1); +} + +int main(int argc, char *argv[]) { +#ifdef UNCLOAK_RT + __sanitizer_uncloak_preinstalled_signal_handlers(); +#endif + + __sighandler_t old = signal(SIGSEGV, &my_signal_sighandler); + if (old == SIG_DFL) + printf("Old handler: default\n"); + // CLOAKED: Old handler: default + else + printf("Old handler: non-default\n"); + // UNCLOAKED: Old handler: non-default + + char *c = (char *)0x123; + printf("%d\n", *c); + // UNCLOAKED,CLOAKED:Custom signal handler + + return 0; +} From 8c5e14c14924fd70907ff5d3a0a58d1ca3501bea Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Thu, 9 Oct 2025 22:00:54 +0000 Subject: [PATCH 02/16] Undo API addition --- compiler-rt/include/sanitizer/common_interface_defs.h | 5 ----- compiler-rt/lib/sanitizer_common/sanitizer_common.cpp | 6 ------ .../lib/sanitizer_common/sanitizer_common_interface.inc | 1 - .../sanitizer_common/TestCases/Linux/allow_user_segv.cpp | 9 ++++----- 4 files changed, 4 insertions(+), 17 deletions(-) diff --git a/compiler-rt/include/sanitizer/common_interface_defs.h b/compiler-rt/include/sanitizer/common_interface_defs.h index 83b333d1f44fc..57313f9bc80e6 100644 --- a/compiler-rt/include/sanitizer/common_interface_defs.h +++ b/compiler-rt/include/sanitizer/common_interface_defs.h @@ -485,11 +485,6 @@ void SANITIZER_CDECL __sanitizer_finish_switch_fiber(void *fake_stack_save, int SANITIZER_CDECL __sanitizer_get_module_and_offset_for_pc( void *pc, char *module_path, size_t module_path_len, void **pc_offset); -// If cloak_sanitizer_signal_handlers() is set, signal/sigaction will pretend -// that sanitizers did not preinstall any signal handlers. This function clears -// the cloaking state. -void SANITIZER_CDECL __sanitizer_uncloak_preinstalled_signal_handlers(); - #ifdef __cplusplus } // extern "C" #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp index 5e39de4e8b8be..60f2834d277a7 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp @@ -418,12 +418,6 @@ int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *, return InstallMallocFreeHooks(malloc_hook, free_hook); } -SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_uncloak_preinstalled_signal_handlers() { - internal_memset(signal_handler_is_from_sanitizer, 0, - sizeof(signal_handler_is_from_sanitizer)); -} - // Provide default (no-op) implementation of malloc hooks. SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook, void *ptr, uptr size) { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc index 706b7b0d220a8..4ea75cdd67cb9 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc @@ -24,7 +24,6 @@ INTERFACE_WEAK_FUNCTION(__sanitizer_on_print) INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary) INTERFACE_WEAK_FUNCTION(__sanitizer_sandbox_on_notify) INTERFACE_WEAK_FUNCTION(__sanitizer_get_dtls_size) -INTERFACE_FUNCTION(__sanitizer_uncloak_preinstalled_signal_handlers) // Sanitizer weak hooks INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_memcmp) INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_strcmp) diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cpp index d4f7816dc68f1..0c5a922ecfb83 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cpp @@ -23,7 +23,10 @@ // Flaky errors in debuggerd with "waitpid returned unexpected pid (0)" in logcat. // UNSUPPORTED: android && i386-target-arch -#include +// Note: this test case is unusual because it retrieves the original +// (ASan-installed) signal handler; thus, it is incompatible with the +// cloak_sanitizer_signal_handlers runtime option. + #include #include #include @@ -69,10 +72,6 @@ bool InstallHandler(int signum, struct sigaction *original_sigaction) { } int main() { - // This test case is unusual because it retrieves the original - // (ASan-installed) signal handler; thus, we don't want ASan to cloak them. - __sanitizer_uncloak_preinstalled_signal_handlers(); - // Let's install handlers for both SIGSEGV and SIGBUS, since pre-Yosemite // 32-bit Darwin triggers SIGBUS instead. if (InstallHandler(SIGSEGV, &original_sigaction_sigsegv) && From d6e0f8960f97a2a11546ccc887bf9e2aa8abc05a Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Thu, 9 Oct 2025 22:07:56 +0000 Subject: [PATCH 03/16] Undo NFC change --- .../lib/sanitizer_common/sanitizer_posix_libcdep.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index e45cc57387dc0..b06f6b1028e7b 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -234,8 +234,12 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) { // will be actually set only once. if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); - int signals[] = {SIGSEGV, SIGBUS, SIGABRT, SIGFPE, SIGILL, SIGTRAP}; - for (int signum : signals) MaybeInstallSigaction(signum, handler); + MaybeInstallSigaction(SIGSEGV, handler); + MaybeInstallSigaction(SIGBUS, handler); + MaybeInstallSigaction(SIGABRT, handler); + MaybeInstallSigaction(SIGFPE, handler); + MaybeInstallSigaction(SIGILL, handler); + MaybeInstallSigaction(SIGTRAP, handler); } bool SignalContext::IsStackOverflow() const { From 9048f7a94e70fa9e5d83c2964ae875e1e677eaf2 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Thu, 9 Oct 2025 22:08:44 +0000 Subject: [PATCH 04/16] Remove runtime uncloaking test --- .../sanitizer_common/TestCases/Linux/cloak_sigaction.cpp | 8 -------- .../sanitizer_common/TestCases/Linux/cloak_signal.cpp | 8 -------- 2 files changed, 16 deletions(-) diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp index 50b3e0a80a5bf..3610a3f4e8cf0 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp @@ -9,10 +9,6 @@ // RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefix=UNCLOAKED // RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefix=CLOAKED -// RUN: %clangxx -O0 %s -DUNCLOAK_RT -o %t -// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefix=UNCLOAKED -// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefix=UNCLOAKED - #include #include #include @@ -24,10 +20,6 @@ void handler(int signum, siginfo_t *info, void *context) { } int main(int argc, char *argv[]) { -#ifdef UNCLOAK_RT - __sanitizer_uncloak_preinstalled_signal_handlers(); -#endif - struct sigaction sa = {0}; struct sigaction old = {0}; sa.sa_flags = SA_SIGINFO; diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp index 4e7d1b2a475a6..bf35df469d862 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp @@ -9,10 +9,6 @@ // RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefix=UNCLOAKED // RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefix=CLOAKED -// RUN: %clangxx -O0 %s -DUNCLOAK_RT -o %t -// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefix=UNCLOAKED -// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefix=UNCLOAKED - #include #include #include @@ -24,10 +20,6 @@ void my_signal_sighandler(int signum) { } int main(int argc, char *argv[]) { -#ifdef UNCLOAK_RT - __sanitizer_uncloak_preinstalled_signal_handlers(); -#endif - __sighandler_t old = signal(SIGSEGV, &my_signal_sighandler); if (old == SIG_DFL) printf("Old handler: default\n"); From 294f76e06f80ee0a56c6b0d13c37eb2f4bfbe911 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Thu, 9 Oct 2025 22:26:16 +0000 Subject: [PATCH 05/16] Undo stray newline --- compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index b06f6b1028e7b..1e6b4d41a86cb 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -233,7 +233,6 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) { // This will cause SetAlternateSignalStack to be called twice, but the stack // will be actually set only once. if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); - MaybeInstallSigaction(SIGSEGV, handler); MaybeInstallSigaction(SIGBUS, handler); MaybeInstallSigaction(SIGABRT, handler); From dd6ffffbbc9b0325ca34334e800438a249db874c Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Thu, 9 Oct 2025 22:59:48 +0000 Subject: [PATCH 06/16] Add TODO for BSD --- .../lib/sanitizer_common/sanitizer_signal_interceptors.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc index b26276792d7b3..b9c47d4983a69 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc @@ -49,6 +49,7 @@ INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) { SIGNAL_INTERCEPTOR_ENTER(); if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0; + // TODO: support cloak_sanitizer_signal_handlers int ret; SIGNAL_INTERCEPTOR_SIGNAL_IMPL(bsd_signal, signum, handler); return ret; From f14b39fe92ef84c595639613f1e94d8a7d11261b Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Fri, 10 Oct 2025 05:18:21 +0000 Subject: [PATCH 07/16] Expand tests to cover handle_segv=0 and handle_segv=2 This uncovered a quirk of the existing signal interceptor: cloaking is effectively on when handle_segv=2. --- .../TestCases/Linux/cloak_sigaction.cpp | 25 ++++++++++++++----- .../TestCases/Linux/cloak_signal.cpp | 25 ++++++++++++++----- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp index 3610a3f4e8cf0..36a9dd777e8cc 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp @@ -6,10 +6,20 @@ // RUN: %clangxx -O0 %s -o %t -// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefix=UNCLOAKED -// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefix=CLOAKED +// Sanitizer signal handler not installed; custom signal handler installed +// RUN: %env_tool_opts=handle_segv=0:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,CUSTOM +// RUN: %env_tool_opts=handle_segv=0:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,CUSTOM + +// Sanitizer signal handler installed but overriden by custom signal handler +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefixes=NONDEFAULT,CUSTOM +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,CUSTOM + +// Sanitizer signal handler installed immutably +// N.B. for handle_segv=2 with cloaking off, there is a pre-existing difference +// in signal vs. sigaction: signal effectively cloaks the handler. +// RUN: %env_tool_opts=handle_segv=2:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefixes=NONDEFAULT,SANITIZER +// RUN: %env_tool_opts=handle_segv=2:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,SANITIZER -#include #include #include #include @@ -28,14 +38,17 @@ int main(int argc, char *argv[]) { if (reinterpret_cast(old.sa_sigaction) == SIG_DFL) printf("Old handler: default\n"); - // CLOAKED: Old handler: default + // DEFAULT: Old handler: default else printf("Old handler: non-default\n"); - // UNCLOAKED: Old handler: non-default + // NONDEFAULT: Old handler: non-default + + fflush(stdout); char *c = (char *)0x123; printf("%d\n", *c); - // UNCLOAKED,CLOAKED:Custom signal handler + // CUSTOM: Custom signal handler + // SANITIZER: Sanitizer:DEADLYSIGNAL return 0; } diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp index bf35df469d862..42531b5fbb483 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp @@ -6,10 +6,20 @@ // RUN: %clangxx -O0 %s -o %t -// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefix=UNCLOAKED -// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefix=CLOAKED +// Sanitizer signal handler not installed; custom signal handler installed +// RUN: %env_tool_opts=handle_segv=0:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,CUSTOM +// RUN: %env_tool_opts=handle_segv=0:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,CUSTOM + +// Sanitizer signal handler installed but overriden by custom signal handler +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefixes=NONDEFAULT,CUSTOM +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,CUSTOM + +// Sanitizer signal handler installed immutably +// N.B. for handle_segv=2 with cloaking off, there is a pre-existing difference +// in signal vs. sigaction: signal effectively cloaks the handler. +// RUN: %env_tool_opts=handle_segv=2:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,SANITIZER +// RUN: %env_tool_opts=handle_segv=2:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,SANITIZER -#include #include #include #include @@ -23,14 +33,17 @@ int main(int argc, char *argv[]) { __sighandler_t old = signal(SIGSEGV, &my_signal_sighandler); if (old == SIG_DFL) printf("Old handler: default\n"); - // CLOAKED: Old handler: default + // DEFAULT: Old handler: default else printf("Old handler: non-default\n"); - // UNCLOAKED: Old handler: non-default + // NONDEFAULT: Old handler: non-default + + fflush(stdout); char *c = (char *)0x123; printf("%d\n", *c); - // UNCLOAKED,CLOAKED:Custom signal handler + // CUSTOM: Custom signal handler + // SANITIZER: Sanitizer:DEADLYSIGNAL return 0; } From 714bd587a947d086817c5af5ffb27bbdd3d854dc Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Fri, 10 Oct 2025 05:29:14 +0000 Subject: [PATCH 08/16] Update commentary --- .../sanitizer_signal_interceptors.inc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc index b9c47d4983a69..a20f4c19519db 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc @@ -63,8 +63,9 @@ INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) { INTERCEPTOR(uptr, signal, int signum, uptr handler) { SIGNAL_INTERCEPTOR_ENTER(); if (GetHandleSignalMode(signum) == kHandleSignalExclusive) - // A side-effect is that a user can never uncloak the sanitizer's - // preinstalled signal handler. + // The user can neither view nor change the signal handler, regardless of + // the cloak_sanitizer_signal_handlers setting. This differs from + // sigaction(). return (uptr) nullptr; uptr ret; SIGNAL_INTERCEPTOR_SIGNAL_IMPL(signal, signum, handler); @@ -89,8 +90,10 @@ INTERCEPTOR(int, sigaction_symname, int signum, if (GetHandleSignalMode(signum) == kHandleSignalExclusive) { if (!oldact) return 0; act = nullptr; - // A side-effect is that a user can never uncloak the sanitizer's - // preinstalled signal handler. + // If cloak_sanitizer_signal_handlers=true, the user can neither view nor + // change the signal handle. + // If false, the user can view but not change the signal handler. This + // differs from signal(). } int ret; SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); From 65468343534015455b18f7db64885511bbfb109b Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Fri, 10 Oct 2025 19:56:36 +0000 Subject: [PATCH 09/16] Add SetSignalHandlerFromSanitizer/IsSignalHandlerFromSanitizer --- .../lib/sanitizer_common/sanitizer_common.cpp | 13 +++++++++++++ compiler-rt/lib/sanitizer_common/sanitizer_common.h | 6 +++--- .../sanitizer_common/sanitizer_posix_libcdep.cpp | 2 +- .../sanitizer_signal_interceptors.inc | 11 ++++------- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp index 60f2834d277a7..475146b9c82b5 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp @@ -24,6 +24,7 @@ namespace __sanitizer { const char *SanitizerToolName = "SanitizerTool"; +const int MaxSignals = 64; bool signal_handler_is_from_sanitizer[MaxSignals] = {0}; atomic_uint32_t current_verbosity; @@ -113,6 +114,18 @@ const char *StripModuleName(const char *module) { return module; } +void SetSignalHandlerFromSanitizer(int signum, bool new_state) { + if (signum >= 0 && signum < MaxSignals) + signal_handler_is_from_sanitizer[signum] = new_state; +} + +bool IsSignalHandlerFromSanitizer(int signum) { + if (signum >= 0 && signum < MaxSignals) + return signal_handler_is_from_sanitizer[signum]; + + return false; +} + void ReportErrorSummary(const char *error_message, const char *alt_tool_name) { if (!common_flags()->print_summary) return; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h index 10bd83118e9a4..59358b1f88d4e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -52,9 +52,6 @@ const u64 kExternalPCBit = 1ULL << 60; extern const char *SanitizerToolName; // Can be changed by the tool. -const int MaxSignals = 64; -extern bool signal_handler_is_from_sanitizer[MaxSignals]; - extern atomic_uint32_t current_verbosity; inline void SetVerbosity(int verbosity) { atomic_store(¤t_verbosity, verbosity, memory_order_relaxed); @@ -393,6 +390,9 @@ void ReportDeadlySignal(const SignalContext &sig, u32 tid, void SetAlternateSignalStack(); void UnsetAlternateSignalStack(); +void SetSignalHandlerFromSanitizer(int signum, bool new_state); +bool IsSignalHandlerFromSanitizer(int signum); + // Construct a one-line string: // SUMMARY: SanitizerToolName: error_message // and pass it to __sanitizer_report_error_summary. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index 1e6b4d41a86cb..e901b30551b75 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -225,7 +225,7 @@ static void MaybeInstallSigaction(int signum, VReport(1, "Installed the sigaction for signal %d\n", signum); if (common_flags()->cloak_sanitizer_signal_handlers) - signal_handler_is_from_sanitizer[signum] = true; + SetSignalHandlerFromSanitizer(signum, true); } void InstallDeadlySignalHandlers(SignalHandlerType handler) { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc index a20f4c19519db..e6c25e92d9f7a 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc @@ -70,12 +70,10 @@ INTERCEPTOR(uptr, signal, int signum, uptr handler) { uptr ret; SIGNAL_INTERCEPTOR_SIGNAL_IMPL(signal, signum, handler); - if (signum >= 0 && signum < MaxSignals && - signal_handler_is_from_sanitizer[signum] && ret != sig_err) { + if (IsSignalHandlerFromSanitizer(signum) && ret != sig_err) { // If the user sets a signal handler, it is never cloaked, even if they // reuse a sanitizer's signal handler. - signal_handler_is_from_sanitizer[signum] = false; - + SetSignalHandlerFromSanitizer(signum, false); ret = sig_dfl; } @@ -98,12 +96,11 @@ INTERCEPTOR(int, sigaction_symname, int signum, int ret; SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); - if (signum >= 0 && signum < MaxSignals && - signal_handler_is_from_sanitizer[signum] && ret == 0) { + if (IsSignalHandlerFromSanitizer(signum) && ret == 0) { if (act) // If the user sets a signal handler, it is never cloaked, even if they // reuse a sanitizer's signal handler. - signal_handler_is_from_sanitizer[signum] = false; + SetSignalHandlerFromSanitizer(signum, false); if (oldact) oldact->handler = reinterpret_cast<__sanitizer_sighandler_ptr>(sig_dfl); From 4f4b75e79bf5644779946048a9bb5bac51b6a161 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Fri, 10 Oct 2025 20:15:55 +0000 Subject: [PATCH 10/16] Use ARRAY_SIZE() instead of MaxSignals --- compiler-rt/lib/sanitizer_common/sanitizer_common.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp index 475146b9c82b5..5137377242d99 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp @@ -24,8 +24,7 @@ namespace __sanitizer { const char *SanitizerToolName = "SanitizerTool"; -const int MaxSignals = 64; -bool signal_handler_is_from_sanitizer[MaxSignals] = {0}; +bool signal_handler_is_from_sanitizer[64] = {0}; atomic_uint32_t current_verbosity; uptr PageSizeCached; @@ -115,12 +114,14 @@ const char *StripModuleName(const char *module) { } void SetSignalHandlerFromSanitizer(int signum, bool new_state) { - if (signum >= 0 && signum < MaxSignals) + if (signum >= 0 && static_cast(signum) < + ARRAY_SIZE(signal_handler_is_from_sanitizer)) signal_handler_is_from_sanitizer[signum] = new_state; } bool IsSignalHandlerFromSanitizer(int signum) { - if (signum >= 0 && signum < MaxSignals) + if (signum >= 0 && static_cast(signum) < + ARRAY_SIZE(signal_handler_is_from_sanitizer)) return signal_handler_is_from_sanitizer[signum]; return false; From 253d5b647c80afdd3f6ac1782b7c06607e6d7703 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Sat, 11 Oct 2025 05:13:04 +0000 Subject: [PATCH 11/16] Updated to use atomics --- .../lib/sanitizer_common/sanitizer_common.cpp | 16 ---------------- .../lib/sanitizer_common/sanitizer_common.h | 2 +- .../sanitizer_posix_libcdep.cpp | 17 +++++++++++++++++ .../sanitizer_signal_interceptors.inc | 15 ++++++++------- 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp index 5137377242d99..6cd69a53093e7 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp @@ -24,8 +24,6 @@ namespace __sanitizer { const char *SanitizerToolName = "SanitizerTool"; -bool signal_handler_is_from_sanitizer[64] = {0}; - atomic_uint32_t current_verbosity; uptr PageSizeCached; u32 NumberOfCPUsCached; @@ -113,20 +111,6 @@ const char *StripModuleName(const char *module) { return module; } -void SetSignalHandlerFromSanitizer(int signum, bool new_state) { - if (signum >= 0 && static_cast(signum) < - ARRAY_SIZE(signal_handler_is_from_sanitizer)) - signal_handler_is_from_sanitizer[signum] = new_state; -} - -bool IsSignalHandlerFromSanitizer(int signum) { - if (signum >= 0 && static_cast(signum) < - ARRAY_SIZE(signal_handler_is_from_sanitizer)) - return signal_handler_is_from_sanitizer[signum]; - - return false; -} - void ReportErrorSummary(const char *error_message, const char *alt_tool_name) { if (!common_flags()->print_summary) return; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h index 59358b1f88d4e..ba85a0eb5a35e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -390,8 +390,8 @@ void ReportDeadlySignal(const SignalContext &sig, u32 tid, void SetAlternateSignalStack(); void UnsetAlternateSignalStack(); -void SetSignalHandlerFromSanitizer(int signum, bool new_state); bool IsSignalHandlerFromSanitizer(int signum); +bool SetSignalHandlerFromSanitizer(int signum, bool new_state); // Construct a one-line string: // SUMMARY: SanitizerToolName: error_message diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index e901b30551b75..3fa5ebdbed783 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -47,6 +47,8 @@ typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); namespace __sanitizer { +static atomic_uint8_t signal_handler_is_from_sanitizer[64]; + u32 GetUid() { return getuid(); } @@ -210,6 +212,21 @@ void UnsetAlternateSignalStack() { UnmapOrDie(oldstack.ss_sp, oldstack.ss_size); } +bool IsSignalHandlerFromSanitizer(int signum) { + return atomic_load(&signal_handler_is_from_sanitizer[signum], + memory_order_relaxed); +} + +bool SetSignalHandlerFromSanitizer(int signum, bool new_state) { + bool old_state = false; + if (signum >= 0 && static_cast(signum) < + ARRAY_SIZE(signal_handler_is_from_sanitizer)) + old_state = atomic_exchange(&signal_handler_is_from_sanitizer[signum], + new_state, memory_order_relaxed); + + return old_state; +} + static void MaybeInstallSigaction(int signum, SignalHandlerType handler) { if (GetHandleSignalMode(signum) == kHandleSignalNo) return; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc index e6c25e92d9f7a..b7941397f5715 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc @@ -70,12 +70,10 @@ INTERCEPTOR(uptr, signal, int signum, uptr handler) { uptr ret; SIGNAL_INTERCEPTOR_SIGNAL_IMPL(signal, signum, handler); - if (IsSignalHandlerFromSanitizer(signum) && ret != sig_err) { + if (ret != sig_err && SetSignalHandlerFromSanitizer(signum, false)) // If the user sets a signal handler, it is never cloaked, even if they // reuse a sanitizer's signal handler. - SetSignalHandlerFromSanitizer(signum, false); ret = sig_dfl; - } return ret; } @@ -96,14 +94,17 @@ INTERCEPTOR(int, sigaction_symname, int signum, int ret; SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); - if (IsSignalHandlerFromSanitizer(signum) && ret == 0) { - if (act) + if (act) { + if (ret == 0 && SetSignalHandlerFromSanitizer(signum, false)) { // If the user sets a signal handler, it is never cloaked, even if they // reuse a sanitizer's signal handler. SetSignalHandlerFromSanitizer(signum, false); - if (oldact) - oldact->handler = reinterpret_cast<__sanitizer_sighandler_ptr>(sig_dfl); + if (oldact) + oldact->handler = reinterpret_cast<__sanitizer_sighandler_ptr>(sig_dfl); + } + } else if (ret == 0 && oldact && IsSignalHandlerFromSanitizer(signum)) { + oldact->handler = reinterpret_cast<__sanitizer_sighandler_ptr>(sig_dfl); } return ret; From fef7f3ef6f8cd3944c5fa9ea9d4c094a011a5abd Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Sat, 11 Oct 2025 05:22:34 +0000 Subject: [PATCH 12/16] Use lambdas --- .../sanitizer_signal_interceptors.inc | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc index b7941397f5715..0874c1274ca87 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc @@ -26,7 +26,7 @@ using namespace __sanitizer; #ifndef SIGNAL_INTERCEPTOR_SIGNAL_IMPL # define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signum, handler) \ { \ - ret = REAL(func)(signum, handler); \ + return REAL(func)(signum, handler); \ } #endif @@ -37,10 +37,9 @@ using namespace __sanitizer; Printf( \ "Warning: REAL(sigaction_symname) == nullptr. This may happen " \ "if you link with ubsan statically. Sigaction will not work.\n"); \ - ret = -1; \ - } else { \ - ret = REAL(sigaction_symname)(signum, act, oldact); \ + return -1; \ } \ + return REAL(sigaction_symname)(signum, act, oldact); \ } #endif @@ -50,9 +49,7 @@ INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) { if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0; // TODO: support cloak_sanitizer_signal_handlers - int ret; SIGNAL_INTERCEPTOR_SIGNAL_IMPL(bsd_signal, signum, handler); - return ret; } #define INIT_BSD_SIGNAL COMMON_INTERCEPT_FUNCTION(bsd_signal) #else // SANITIZER_INTERCEPT_BSD_SIGNAL @@ -67,8 +64,10 @@ INTERCEPTOR(uptr, signal, int signum, uptr handler) { // the cloak_sanitizer_signal_handlers setting. This differs from // sigaction(). return (uptr) nullptr; - uptr ret; - SIGNAL_INTERCEPTOR_SIGNAL_IMPL(signal, signum, handler); + + uptr ret = +[](auto signal, int signum, uptr handler) { + SIGNAL_INTERCEPTOR_SIGNAL_IMPL(signal, signum, handler); + }(signal, signum, handler); if (ret != sig_err && SetSignalHandlerFromSanitizer(signum, false)) // If the user sets a signal handler, it is never cloaked, even if they @@ -91,8 +90,11 @@ INTERCEPTOR(int, sigaction_symname, int signum, // If false, the user can view but not change the signal handler. This // differs from signal(). } - int ret; - SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); + + int ret = +[](int signum, const __sanitizer_sigaction* act, + __sanitizer_sigaction* oldact) { + SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); + }(signum, act, oldact); if (act) { if (ret == 0 && SetSignalHandlerFromSanitizer(signum, false)) { From 8a7f494d07df2b7568ee249cfbf48b3a52828f36 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Sat, 11 Oct 2025 05:24:32 +0000 Subject: [PATCH 13/16] Remove redundant line` --- .../lib/sanitizer_common/sanitizer_signal_interceptors.inc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc index 0874c1274ca87..fa9d6e71ad2b8 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc @@ -70,7 +70,7 @@ INTERCEPTOR(uptr, signal, int signum, uptr handler) { }(signal, signum, handler); if (ret != sig_err && SetSignalHandlerFromSanitizer(signum, false)) - // If the user sets a signal handler, it is never cloaked, even if they + // If the user sets a signal handler, it becomes uncloaked, even if they // reuse a sanitizer's signal handler. ret = sig_dfl; @@ -98,9 +98,8 @@ INTERCEPTOR(int, sigaction_symname, int signum, if (act) { if (ret == 0 && SetSignalHandlerFromSanitizer(signum, false)) { - // If the user sets a signal handler, it is never cloaked, even if they + // If the user sets a signal handler, it becomes uncloaked, even if they // reuse a sanitizer's signal handler. - SetSignalHandlerFromSanitizer(signum, false); if (oldact) oldact->handler = reinterpret_cast<__sanitizer_sighandler_ptr>(sig_dfl); From e531a92209f6436a61f85dc2f3ce6cd23ba40e06 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Sat, 11 Oct 2025 05:31:36 +0000 Subject: [PATCH 14/16] Lambda approach works with msan and tsan --- .../test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp | 3 --- .../test/sanitizer_common/TestCases/Linux/cloak_signal.cpp | 3 --- 2 files changed, 6 deletions(-) diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp index 36a9dd777e8cc..d713d2d1501b6 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp @@ -1,6 +1,3 @@ -// XFAIL: msan -// XFAIL: tsan - // UNSUPPORTED: android // UNSUPPORTED: hwasan diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp index 42531b5fbb483..1c166c953fcfd 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp @@ -1,6 +1,3 @@ -// XFAIL: msan -// XFAIL: tsan - // UNSUPPORTED: android // UNSUPPORTED: hwasan From ed76424e8e861e87b206e546a339dd4704aa8448 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Sat, 11 Oct 2025 05:39:07 +0000 Subject: [PATCH 15/16] Undo formatting change --- .../lib/sanitizer_common/sanitizer_signal_interceptors.inc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc index fa9d6e71ad2b8..8511e4d55fa9e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc @@ -24,10 +24,8 @@ using namespace __sanitizer; #endif #ifndef SIGNAL_INTERCEPTOR_SIGNAL_IMPL -# define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signum, handler) \ - { \ - return REAL(func)(signum, handler); \ - } +#define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signum, handler) \ + { return REAL(func)(signum, handler); } #endif #ifndef SIGNAL_INTERCEPTOR_SIGACTION_IMPL From 55715084b0f3ab2a4da50659d339391206c1be4b Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 14 Oct 2025 01:38:00 +0000 Subject: [PATCH 16/16] Early exit --- .../lib/sanitizer_common/sanitizer_posix_libcdep.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index 3fa5ebdbed783..15cd1824abc56 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -218,13 +218,12 @@ bool IsSignalHandlerFromSanitizer(int signum) { } bool SetSignalHandlerFromSanitizer(int signum, bool new_state) { - bool old_state = false; - if (signum >= 0 && static_cast(signum) < - ARRAY_SIZE(signal_handler_is_from_sanitizer)) - old_state = atomic_exchange(&signal_handler_is_from_sanitizer[signum], - new_state, memory_order_relaxed); + if (signum < 0 || static_cast(signum) >= + ARRAY_SIZE(signal_handler_is_from_sanitizer)) + return false; - return old_state; + return atomic_exchange(&signal_handler_is_from_sanitizer[signum], new_state, + memory_order_relaxed); } static void MaybeInstallSigaction(int signum,