aboutsummaryrefslogtreecommitdiff
path: root/compiler-rt
diff options
context:
space:
mode:
Diffstat (limited to 'compiler-rt')
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_common.h3
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_flags.inc5
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp19
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc42
-rw-r--r--compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp33
-rw-r--r--compiler-rt/test/asan/TestCases/wcscat.cpp6
-rw-r--r--compiler-rt/test/asan/TestCases/wcscpy.cpp6
-rw-r--r--compiler-rt/test/asan/TestCases/wcsncat.cpp6
-rw-r--r--compiler-rt/test/asan/TestCases/wcsncpy.cpp6
-rw-r--r--compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cpp4
-rw-r--r--compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp53
-rw-r--r--compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp48
12 files changed, 221 insertions, 10 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h
index 3e82df4..ba85a0e 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h
@@ -390,6 +390,9 @@ void ReportDeadlySignal(const SignalContext &sig, u32 tid,
void SetAlternateSignalStack();
void UnsetAlternateSignalStack();
+bool IsSignalHandlerFromSanitizer(int signum);
+bool SetSignalHandlerFromSanitizer(int signum, bool new_state);
+
// 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_flags.inc b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
index 650a458..5f44990 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 b1eb200..8e5e879 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 {
+[[maybe_unused]] static atomic_uint8_t signal_handler_is_from_sanitizer[64];
+
u32 GetUid() {
return getuid();
}
@@ -210,6 +212,20 @@ 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) {
+ if (signum < 0 || static_cast<unsigned>(signum) >=
+ ARRAY_SIZE(signal_handler_is_from_sanitizer))
+ return false;
+
+ return atomic_exchange(&signal_handler_is_from_sanitizer[signum], new_state,
+ memory_order_relaxed);
+}
+
static void MaybeInstallSigaction(int signum,
SignalHandlerType handler) {
if (GetHandleSignalMode(signum) == kHandleSignalNo) return;
@@ -223,6 +239,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)
+ 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 94e4e29..8511e4d 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc
@@ -45,6 +45,8 @@ using namespace __sanitizer;
INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) {
SIGNAL_INTERCEPTOR_ENTER();
if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0;
+
+ // TODO: support cloak_sanitizer_signal_handlers
SIGNAL_INTERCEPTOR_SIGNAL_IMPL(bsd_signal, signum, handler);
}
#define INIT_BSD_SIGNAL COMMON_INTERCEPT_FUNCTION(bsd_signal)
@@ -56,19 +58,55 @@ INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) {
INTERCEPTOR(uptr, signal, int signum, uptr handler) {
SIGNAL_INTERCEPTOR_ENTER();
if (GetHandleSignalMode(signum) == kHandleSignalExclusive)
+ // 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;
- 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 becomes uncloaked, even if they
+ // reuse a sanitizer's signal handler.
+ 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;
+ // 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().
}
- 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)) {
+ // If the user sets a signal handler, it becomes uncloaked, even if they
+ // reuse a sanitizer's signal handler.
+
+ 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;
}
#define INIT_SIGACTION COMMON_INTERCEPT_FUNCTION(sigaction_symname)
diff --git a/compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp b/compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp
new file mode 100644
index 0000000..6f02814
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp
@@ -0,0 +1,33 @@
+// RUN: %clangxx_asan %s -o %t
+// RUN: %run %t | FileCheck %s
+
+// This test tests that declaring a parameter in a catch-block does not produce a false positive
+// ASan error on Windows.
+
+// This code is based on the repro in https://github.com/google/sanitizers/issues/749
+#include <cstdio>
+#include <exception>
+
+void throwInFunction() { throw std::exception("test2"); }
+
+int main() {
+ // case 1: direct throw
+ try {
+ throw std::exception("test1");
+ } catch (const std::exception &ex) {
+ puts(ex.what());
+ // CHECK: test1
+ }
+
+ // case 2: throw in function
+ try {
+ throwInFunction();
+ } catch (const std::exception &ex) {
+ puts(ex.what());
+ // CHECK: test2
+ }
+
+ printf("Success!\n");
+ // CHECK: Success!
+ return 0;
+}
diff --git a/compiler-rt/test/asan/TestCases/wcscat.cpp b/compiler-rt/test/asan/TestCases/wcscat.cpp
index fd0b5a4..beab1dc 100644
--- a/compiler-rt/test/asan/TestCases/wcscat.cpp
+++ b/compiler-rt/test/asan/TestCases/wcscat.cpp
@@ -9,11 +9,13 @@
int main() {
const wchar_t *start = L"X means ";
const wchar_t *append = L"dog";
- wchar_t goodDst[12];
+ wchar_t goodArray[12];
+ wchar_t *volatile goodDst = goodArray;
wcscpy(goodDst, start);
wcscat(goodDst, append);
- wchar_t badDst[9];
+ wchar_t badArray[9];
+ wchar_t *volatile badDst = badArray;
wcscpy(badDst, start);
fprintf(stderr, "Good so far.\n");
// CHECK-DAG: Good so far.
diff --git a/compiler-rt/test/asan/TestCases/wcscpy.cpp b/compiler-rt/test/asan/TestCases/wcscpy.cpp
index 8133a58..2b82803 100644
--- a/compiler-rt/test/asan/TestCases/wcscpy.cpp
+++ b/compiler-rt/test/asan/TestCases/wcscpy.cpp
@@ -8,10 +8,12 @@
int main() {
const wchar_t *src = L"X means dog";
- wchar_t goodDst[12];
+ wchar_t goodArray[12];
+ wchar_t *volatile goodDst = goodArray;
wcscpy(goodDst, src);
- wchar_t badDst[7];
+ wchar_t badArray[7];
+ wchar_t *volatile badDst = badArray;
fprintf(stderr, "Good so far.\n");
// CHECK-DAG: Good so far.
fflush(stderr);
diff --git a/compiler-rt/test/asan/TestCases/wcsncat.cpp b/compiler-rt/test/asan/TestCases/wcsncat.cpp
index 365e732..04cdcf2 100644
--- a/compiler-rt/test/asan/TestCases/wcsncat.cpp
+++ b/compiler-rt/test/asan/TestCases/wcsncat.cpp
@@ -9,11 +9,13 @@
int main() {
const wchar_t *start = L"X means ";
const wchar_t *append = L"dog";
- wchar_t goodDst[15];
+ wchar_t goodArray[15];
+ wchar_t *volatile goodDst = goodArray;
wcscpy(goodDst, start);
wcsncat(goodDst, append, 5);
- wchar_t badDst[11];
+ wchar_t badArray[11];
+ wchar_t *volatile badDst = badArray;
wcscpy(badDst, start);
wcsncat(badDst, append, 1);
fprintf(stderr, "Good so far.\n");
diff --git a/compiler-rt/test/asan/TestCases/wcsncpy.cpp b/compiler-rt/test/asan/TestCases/wcsncpy.cpp
index 485ddc4..9e11b55 100644
--- a/compiler-rt/test/asan/TestCases/wcsncpy.cpp
+++ b/compiler-rt/test/asan/TestCases/wcsncpy.cpp
@@ -8,10 +8,12 @@
int main() {
const wchar_t *src = L"X means dog";
- wchar_t goodDst[12];
+ wchar_t goodArray[12];
+ wchar_t *volatile goodDst = goodArray;
wcsncpy(goodDst, src, 12);
- wchar_t badDst[7];
+ wchar_t badArray[7];
+ wchar_t *volatile badDst = badArray;
wcsncpy(badDst, src, 7); // This should still work.
fprintf(stderr, "Good so far.\n");
// CHECK-DAG: Good so far.
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 1c74015..0c5a922 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,10 @@
// Flaky errors in debuggerd with "waitpid returned unexpected pid (0)" in logcat.
// UNSUPPORTED: android && i386-target-arch
+// 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 <signal.h>
#include <stdio.h>
#include <stdlib.h>
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 0000000..422e4ab
--- /dev/null
+++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp
@@ -0,0 +1,53 @@
+// UNSUPPORTED: android
+// UNSUPPORTED: hwasan
+
+// RUN: %clangxx -O0 %s -o %t
+
+// 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 <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void handler(int signum, siginfo_t *info, void *context) {
+ printf("Custom signal handler\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ struct sigaction sa = {0};
+ struct sigaction old = {0};
+ sa.sa_flags = SA_SIGINFO;
+ sa.sa_sigaction = &handler;
+ sigaction(SIGSEGV, &sa, &old);
+
+ if (reinterpret_cast<void *>(old.sa_sigaction) == SIG_DFL)
+ printf("Old handler: default\n");
+ // DEFAULT: Old handler: default
+ else
+ printf("Old handler: non-default\n");
+ // NONDEFAULT: Old handler: non-default
+
+ fflush(stdout);
+
+ // Trying to organically segfault by dereferencing a pointer can be tricky
+ // in builds with assertions. Additionally, some older platforms may SIGBUS
+ // instead.
+ raise(SIGSEGV);
+ // 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
new file mode 100644
index 0000000..48e5475
--- /dev/null
+++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp
@@ -0,0 +1,48 @@
+// UNSUPPORTED: android
+// UNSUPPORTED: hwasan
+
+// RUN: %clangxx -O0 %s -o %t
+
+// 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 <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void my_signal_sighandler(int signum) {
+ printf("Custom signal handler\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ __sighandler_t old = signal(SIGSEGV, &my_signal_sighandler);
+ if (old == SIG_DFL)
+ printf("Old handler: default\n");
+ // DEFAULT: Old handler: default
+ else
+ printf("Old handler: non-default\n");
+ // NONDEFAULT: Old handler: non-default
+
+ fflush(stdout);
+
+ // Trying to organically segfault by dereferencing a pointer can be tricky
+ // in builds with assertions. Additionally, some older platforms may SIGBUS
+ // instead.
+ raise(SIGSEGV);
+ // CUSTOM: Custom signal handler
+ // SANITIZER: Sanitizer:DEADLYSIGNAL
+
+ return 0;
+}