Don't suppress prev signal handler in hw bound check (#1268)

Enhance the hw bound check reported in #1262:

When registering signal handlers for SIGSEGV & SIGBUS in boundary
check with hardware trap, preserve the previous handlers for signal
SIGSEGV and SIGBUS, and forward the signal to the preserved signal
handlers if it isn't handled by hw bound check.
This commit is contained in:
Wenyong Huang 2022-07-06 16:53:05 +08:00 committed by GitHub
parent 653efecd02
commit daeb7a4265
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -448,31 +448,53 @@ mask_signals(int how)
pthread_sigmask(how, &set, NULL);
}
__attribute__((noreturn)) static void
static os_thread_local_attribute struct sigaction prev_sig_act_SIGSEGV;
static os_thread_local_attribute struct sigaction prev_sig_act_SIGBUS;
static void
signal_callback(int sig_num, siginfo_t *sig_info, void *sig_ucontext)
{
void *sig_addr = sig_info->si_addr;
struct sigaction *prev_sig_act = NULL;
mask_signals(SIG_BLOCK);
/* Try to handle signal with the registered signal handler */
if (signal_handler && (sig_num == SIGSEGV || sig_num == SIGBUS)) {
signal_handler(sig_addr);
}
/* signal unhandled */
switch (sig_num) {
case SIGSEGV:
os_printf("unhandled SIGSEGV, si_addr: %p\n", sig_addr);
break;
case SIGBUS:
os_printf("unhandled SIGBUS, si_addr: %p\n", sig_addr);
break;
default:
os_printf("unhandle signal %d, si_addr: %p\n", sig_num, sig_addr);
break;
}
if (sig_num == SIGSEGV)
prev_sig_act = &prev_sig_act_SIGSEGV;
else if (sig_num == SIGBUS)
prev_sig_act = &prev_sig_act_SIGBUS;
abort();
/* Forward the signal to next handler if found */
if (prev_sig_act && (prev_sig_act->sa_flags & SA_SIGINFO)) {
prev_sig_act->sa_sigaction(sig_num, sig_info, sig_ucontext);
}
else if (prev_sig_act
&& ((void *)prev_sig_act->sa_sigaction == SIG_DFL
|| (void *)prev_sig_act->sa_sigaction == SIG_IGN)) {
sigaction(sig_num, prev_sig_act, NULL);
}
/* Output signal info and then crash if signal is unhandled */
else {
switch (sig_num) {
case SIGSEGV:
os_printf("unhandled SIGSEGV, si_addr: %p\n", sig_addr);
break;
case SIGBUS:
os_printf("unhandled SIGBUS, si_addr: %p\n", sig_addr);
break;
default:
os_printf("unhandle signal %d, si_addr: %p\n", sig_num,
sig_addr);
break;
}
abort();
}
}
int
@ -508,12 +530,15 @@ os_thread_signal_init(os_signal_handler handler)
goto fail2;
}
memset(&prev_sig_act_SIGSEGV, 0, sizeof(struct sigaction));
memset(&prev_sig_act_SIGBUS, 0, sizeof(struct sigaction));
/* Install signal hanlder */
sig_act.sa_sigaction = signal_callback;
sig_act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER;
sigemptyset(&sig_act.sa_mask);
if (sigaction(SIGSEGV, &sig_act, NULL) != 0
|| sigaction(SIGBUS, &sig_act, NULL) != 0) {
if (sigaction(SIGSEGV, &sig_act, &prev_sig_act_SIGSEGV) != 0
|| sigaction(SIGBUS, &sig_act, &prev_sig_act_SIGBUS) != 0) {
os_printf("Failed to register signal handler\n");
goto fail3;
}