Skip to content

Commit

Permalink
Improve delivery of crash signals
Browse files Browse the repository at this point in the history
  • Loading branch information
jart committed Feb 23, 2023
1 parent a3d4889 commit 26b9929
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 118 deletions.
83 changes: 45 additions & 38 deletions blink/blink.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ extern char **environ;
static bool FLAG_zero;
static bool FLAG_nojit;
static char g_pathbuf[PATH_MAX];
static siginfo_t g_siginfo;

static void OnSigSys(int sig) {
// do nothing
Expand All @@ -109,8 +110,18 @@ void TerminateSignal(struct Machine *m, int sig) {
int syssig;
struct sigaction sa;
unassert(!IsSignalIgnoredByDefault(sig));
ERRF("terminating due to signal %s", DescribeSignal(sig));
if ((syssig = XlatSignal(sig)) == -1) syssig = SIGTERM;
if (IsSignalSerious(sig)) {
ERRF("terminating due to %s (rip=%" PRIx64 " faultaddr=%" PRIx64 ")",
DescribeSignal(sig), m->ip, m->faultaddr);
ERRF("additional information\n"
"\t%s\n"
"%s",
GetBacktrace(m), FormatPml4t(m));
#ifdef DEBUG
PrintBacktrace();
#endif
}
if ((syssig = XlatSignal(sig)) == -1) syssig = SIGKILL;
KillOtherThreads(m->system);
FreeMachine(m);
#ifdef HAVE_JIT
Expand All @@ -126,54 +137,47 @@ void TerminateSignal(struct Machine *m, int sig) {
Abort();
}

static void OnSigSegv(int sig, siginfo_t *si, void *ptr) {
int sig_linux;
RestoreIp(g_machine);
static void OnFatalSystemSignal(int sig, siginfo_t *si, void *ptr) {
g_siginfo = *si;
siglongjmp(g_machine->onhalt, kMachineFatalSystemSignal);
}

static void HandleFatalSystemSignal(struct Machine *m) {
int sig;
RestoreIp(m);
// TODO(jart): Fix address translation in non-linear mode.
g_machine->faultaddr = ToGuest(si->si_addr);
ERRF("SEGMENTATION FAULT (%s) AT ADDRESS %" PRIx64 " at RIP=%" PRIx64,
strsignal(sig), g_machine->faultaddr, g_machine->ip);
ERRF("ADDITIONAL INFORMATION\n"
"\t%s\n"
"%s",
GetBacktrace(g_machine), FormatPml4t(g_machine));
#ifdef DEBUG
PrintBacktrace();
#endif
if ((sig_linux = UnXlatSignal(sig)) != -1) {
DeliverSignalToUser(g_machine, sig_linux);
}
siglongjmp(g_machine->onhalt, kMachineSegmentationFault);
sig = UnXlatSignal(g_siginfo.si_signo);
m->faultaddr = ToGuest(g_siginfo.si_addr);
DeliverSignalToUser(m, sig);
}

static int Exec(char *execfn, char *prog, char **argv, char **envp) {
int i;
int i, rc;
sigset_t oldmask;
struct Machine *old;
struct Machine *m, *old;
if ((old = g_machine)) KillOtherThreads(old->system);
unassert((g_machine = NewMachine(NewSystem(XED_MODE_LONG), 0)));
unassert((g_machine = m = NewMachine(NewSystem(XED_MODE_LONG), 0)));
#ifdef HAVE_JIT
if (FLAG_nojit) DisableJit(&g_machine->system->jit);
if (FLAG_nojit) DisableJit(&m->system->jit);
#endif
g_machine->system->exec = Exec;
m->system->exec = Exec;
if (!old) {
// this is the first time a program is being loaded
LoadProgram(g_machine, execfn, prog, argv, envp);
SetupCod(g_machine);
LoadProgram(m, execfn, prog, argv, envp);
SetupCod(m);
for (i = 0; i < 10; ++i) {
AddStdFd(&g_machine->system->fds, i);
AddStdFd(&m->system->fds, i);
}
} else {
unassert(!FreeVirtual(old->system, -0x800000000000, 0x1000000000000));
for (i = 1; i <= 64; ++i) {
if (Read64(old->system->hands[i - 1].handler) == SIG_IGN_LINUX) {
Write64(g_machine->system->hands[i - 1].handler, SIG_IGN_LINUX);
Write64(m->system->hands[i - 1].handler, SIG_IGN_LINUX);
}
}
memcpy(g_machine->system->rlim, old->system->rlim,
sizeof(old->system->rlim));
LoadProgram(g_machine, execfn, prog, argv, envp);
g_machine->system->fds.list = old->system->fds.list;
memcpy(m->system->rlim, old->system->rlim, sizeof(old->system->rlim));
LoadProgram(m, execfn, prog, argv, envp);
m->system->fds.list = old->system->fds.list;
old->system->fds.list = 0;
// releasing the execve() lock must come after unlocking fds
memcpy(&oldmask, &old->system->exec_sigmask, sizeof(oldmask));
Expand All @@ -185,12 +189,15 @@ static int Exec(char *execfn, char *prog, char **argv, char **envp) {
}
// meta interpreter loop
for (;;) {
if (!sigsetjmp(g_machine->onhalt, 1)) {
g_machine->canhalt = true;
Actor(g_machine);
if (!(rc = sigsetjmp(m->onhalt, 1))) {
m->canhalt = true;
Actor(m);
}
if (IsMakingPath(m)) {
AbandonPath(m);
}
if (IsMakingPath(g_machine)) {
AbandonPath(g_machine);
if (rc == kMachineFatalSystemSignal) {
HandleFatalSystemSignal(m);
}
}
}
Expand Down Expand Up @@ -287,7 +294,7 @@ static void HandleSigs(void) {
unassert(!sigaction(SIGXCPU, &sa, 0));
unassert(!sigaction(SIGXFSZ, &sa, 0));
#if !defined(__SANITIZE_THREAD__) && !defined(__SANITIZE_ADDRESS__)
sa.sa_sigaction = OnSigSegv;
sa.sa_sigaction = OnFatalSystemSignal;
sa.sa_flags = SA_SIGINFO;
unassert(!sigaction(SIGBUS, &sa, 0));
unassert(!sigaction(SIGILL, &sa, 0));
Expand Down
1 change: 1 addition & 0 deletions blink/machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#define kMachineProtectionFault -8
#define kMachineSimdException -9
#define kMachineExitTrap -10
#define kMachineFatalSystemSignal -11

#define CR0_PE 0x01 // protected mode enabled
#define CR0_MP 0x02 // monitor coprocessor
Expand Down
68 changes: 30 additions & 38 deletions blink/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,15 @@ bool IsSignalIgnoredByDefault(int sig) {
sig == SIGWINCH_LINUX;
}

bool IsSignalTooDangerousToIgnore(int sig) {
return sig == SIGFPE_LINUX || //
sig == SIGILL_LINUX || //
sig == SIGSEGV_LINUX;
bool IsSignalSerious(int sig) {
return sig == SIGFPE_LINUX || //
sig == SIGILL_LINUX || //
sig == SIGBUS_LINUX || //
sig == SIGQUIT_LINUX || //
sig == SIGTRAP_LINUX || //
sig == SIGSEGV_LINUX || //
sig == SIGSTOP_LINUX || //
sig == SIGKILL_LINUX;
}

void DeliverSignal(struct Machine *m, int sig, int code) {
Expand Down Expand Up @@ -193,44 +198,31 @@ static int ConsumeSignalImpl(struct Machine *m, int *delivered, bool *restart) {
if (delivered) *delivered = 0;
if (restart) *restart = true;
// look for a pending signal that isn't currently masked
for (signals = m->signals; signals; signals &= ~(1ull << (sig - 1))) {
while ((signals = m->signals & ~m->sigmask)) {
sig = bsr(signals) + 1;
if (~m->sigmask & (1ull << (sig - 1))) {
m->signals &= ~(1ull << (sig - 1));
handler = Read64(m->system->hands[sig - 1].handler);
if (handler == SIG_DFL_LINUX) {
if (IsSignalIgnoredByDefault(sig)) {
SIG_LOGF("default action is to ignore signal %s",
DescribeSignal(sig));
return 0;
} else {
SIG_LOGF("default action is to terminate upon signal %s",
DescribeSignal(sig));
return sig;
}
} else if (handler == SIG_IGN_LINUX) {
if (!IsSignalTooDangerousToIgnore(sig)) {
SIG_LOGF("explicitly ignoring signal %s", DescribeSignal(sig));
return 0;
} else {
SIG_LOGF("won't ignore signal %s", DescribeSignal(sig));
return sig;
}
m->signals &= ~(1ull << (sig - 1));
handler = Read64(m->system->hands[sig - 1].handler);
if (handler == SIG_DFL_LINUX) {
if (IsSignalIgnoredByDefault(sig)) {
SIG_LOGF("default action is to ignore signal %s", DescribeSignal(sig));
return 0;
} else {
SIG_LOGF("default action is to terminate upon signal %s",
DescribeSignal(sig));
return sig;
}
if (delivered) {
*delivered = sig;
}
if (restart) {
*restart =
!!(Read64(m->system->hands[sig - 1].flags) & SA_RESTART_LINUX);
}
DeliverSignal(m, sig, SI_KERNEL_LINUX);
} else if (handler == SIG_IGN_LINUX) {
SIG_LOGF("explicitly ignoring signal %s", DescribeSignal(sig));
return 0;
} else if (IsSignalTooDangerousToIgnore(sig)) {
// signal is too dangerous to be deferred
// TODO(jart): permit defer if sent by kill() or tkill()
return sig;
}
if (delivered) {
*delivered = sig;
}
if (restart) {
*restart = !!(Read64(m->system->hands[sig - 1].flags) & SA_RESTART_LINUX);
}
DeliverSignal(m, sig, SI_KERNEL_LINUX);
return 0;
}
return 0;
}
Expand Down
2 changes: 2 additions & 0 deletions blink/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#define BLINK_SIGNAL_H_
#include "blink/machine.h"

bool IsSignalSerious(int);
bool IsSignalQueueable(int);
void SigRestore(struct Machine *);
bool IsSignalIgnoredByDefault(int);
void OnSignal(int, siginfo_t *, void *);
Expand Down
Loading

0 comments on commit 26b9929

Please sign in to comment.