-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[sanitizer] Add cloak_sanitizer_signal_handlers runtime option #162746
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?
Changes from 8 commits
5d7e930
8c5e14c
d6e0f89
9048f7a
294f76e
dd6ffff
f14b39f
714bd58
6546834
4f4b75e
253d5b6
fef7f3e
8a7f494
e531a92
ed76424
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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,17 +37,22 @@ 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 | ||
|
||
#if SANITIZER_INTERCEPT_BSD_SIGNAL | ||
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; | ||
} | ||
#define INIT_BSD_SIGNAL COMMON_INTERCEPT_FUNCTION(bsd_signal) | ||
#else // SANITIZER_INTERCEPT_BSD_SIGNAL | ||
|
@@ -56,19 +63,53 @@ 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; | ||
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; | ||
// 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); | ||
|
||
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) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// XFAIL: msan | ||
// XFAIL: tsan | ||
|
||
// 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); | ||
|
||
char *c = (char *)0x123; | ||
printf("%d\n", *c); | ||
// CUSTOM: Custom signal handler | ||
// SANITIZER: Sanitizer:DEADLYSIGNAL | ||
|
||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// XFAIL: msan | ||
// XFAIL: tsan | ||
|
||
// 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); | ||
|
||
char *c = (char *)0x123; | ||
printf("%d\n", *c); | ||
// CUSTOM: Custom signal handler | ||
// SANITIZER: Sanitizer:DEADLYSIGNAL | ||
|
||
return 0; | ||
} |
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 don't see any locking, so should be atomic
SetSignalHandlerFromSanitizer/IsSignalHandlerFromSanitizer
should be just atomic SetSignalHandlerFromSanitizer which returns previos value
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 will add atomicity.
I don't think it's feasible to combine SetSignalHandlerFromSanitizer/IsSignalHandlerFromSanitizer, because of this code in the sigaction interceptor:
Uh oh!
There was an error while loading. Please reload this page.
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.
you still need "Is" but you can set atomically
Note: check local ret before more expensive SetSignalHandlerFromSanitizer
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.
Done