Skip to content

Commit

Permalink
Forward almost all signals to the child
Browse files Browse the repository at this point in the history
  • Loading branch information
JonathonReinhart committed Jun 22, 2023
1 parent 390cd62 commit 3b9f51c
Showing 1 changed file with 55 additions and 24 deletions.
79 changes: 55 additions & 24 deletions bootloader/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,37 +238,67 @@ make_argv(int orig_argc, char **orig_argv, char *argv0)
return argv;
}

/* XXX Should be volatile, but is used in too many places */
static pid_t child_pid;

static void sig_handler(int signum)
{
/* Forward received signal to child */
debug_printf("Forwarding signal %d to child %d\n", signum, child_pid);
kill(child_pid, signum);
if (child_pid) {
/* Forward received signal to child */
debug_printf("Forwarding signal %d to child %d\n", signum, child_pid);
kill(child_pid, signum);
}
}

static void
setup_sig_handler(int signum)
static void adjust_signal(int signum, bool forward)
{
struct sigaction sa = {
.sa_handler = sig_handler,
.sa_handler = forward ? sig_handler : SIG_DFL,
};
sigemptyset(&sa.sa_mask);

if (sigaction(signum, &sa, NULL) < 0)
error(2, errno, "Error establishing handler for signal %d", signum);
if (sigaction(signum, &sa, NULL) < 0) {
error(2, errno, "Error %s handler for signal %d",
forward ? "establishing" : "restoring",
signum);
}
}

static void
restore_sig_handler(int signum)
static void adjust_signals(bool forward)
{
struct sigaction sa = {
.sa_handler = SIG_DFL,
};
sigemptyset(&sa.sa_mask);
int signum;

/* As indicated in signal(7), standard signals range from 1-31 */
for (signum = 1; signum <= 31; signum++) {
switch (signum) {
case SIGKILL: /* Can't be caught */
case SIGSTOP: /* Can't be caught */
case SIGCHLD: /* Interferes with wait(); doesn't make sense */
case SIGSEGV: /* Doesn't make sense to forward */
continue;
}
adjust_signal(signum, forward);
}

/**
* Realtime signals range from SIGRTMIN to SIGRTMAX.
* Note that SIGRTMIN might not be 32, so we run a separate loop.
*/
for (signum = SIGRTMIN; signum <= SIGRTMAX; signum++) {
adjust_signal(signum, forward);
}
}

if (sigaction(signum, &sa, NULL) < 0)
error(2, errno, "Error restoring handler for signal %d", signum);
static void forward_signals(void)
{
debug_printf("Setting up signal handlers...\n");
adjust_signals(true);
}

static void restore_signals(void)
{
debug_printf("Restoring signal handlers...\n");
adjust_signals(false);
}

static void
Expand Down Expand Up @@ -342,11 +372,8 @@ run_app(int argc, char **argv, char *prog_path)

/*** Parent ***/

/* Forward terminating signals to child */
setup_sig_handler(SIGINT);
setup_sig_handler(SIGTERM);
/* SIGKILL can't be caught */

/* Forward (most) all signals to the child. */
forward_signals();

/* Wait for child to exit */
int wstatus;
Expand All @@ -355,11 +382,15 @@ run_app(int argc, char **argv, char *prog_path)
continue;
error(2, errno, "Failed to wait for child process %d", child_pid);
}
/**
* XXX There is a race here, where we could get a signal and fail to
* deliver it to the dead child. One solution might be to handle SIGCHLD
* (ensuring it is configured to mask all forwardable signals) and clear
* this variable there.
*/
child_pid = 0;

/* Restore signal handlers */
restore_sig_handler(SIGINT);
restore_sig_handler(SIGTERM);
restore_signals();

debug_printf("Child process terminated with wstatus=%d\n", wstatus);

Expand Down

0 comments on commit 3b9f51c

Please sign in to comment.