init: fix "while true; do reboot; done" bug. +15 bytes. Closes bug 781
No binary (build failed)
—
(log yok)
| @@ -260,6 +260,20 @@ static int open_stdio_to_tty(const char* tty_name) | |
| return 1; /* success */ | |
| } | |
| + | static void reset_sighandlers_and_unblock_sigs(void) |
| + | { |
| + | bb_signals(0 |
| + | + (1 << SIGUSR1) |
| + | + (1 << SIGUSR2) |
| + | + (1 << SIGTERM) |
| + | + (1 << SIGQUIT) |
| + | + (1 << SIGINT) |
| + | + (1 << SIGHUP) |
| + | + (1 << SIGTSTP) |
| + | , SIG_DFL); |
| + | sigprocmask_allsigs(SIG_UNBLOCK); |
| + | } |
| + | |
| /* Wrapper around exec: | |
| * Takes string (max COMMAND_SIZE chars). | |
| * If chars like '>' detected, execs '[-]/bin/sh -c "exec ......."'. | |
| @@ -329,16 +343,7 @@ static pid_t run(const struct init_action *a) | |
| /* Child */ | |
| /* Reset signal handlers that were set by the parent process */ | |
| - | bb_signals(0 |
| - | + (1 << SIGUSR1) |
| - | + (1 << SIGUSR2) |
| - | + (1 << SIGTERM) |
| - | + (1 << SIGQUIT) |
| - | + (1 << SIGINT) |
| - | + (1 << SIGHUP) |
| - | + (1 << SIGTSTP) |
| - | , SIG_DFL); |
| - | sigprocmask_allsigs(SIG_UNBLOCK); |
| + | reset_sighandlers_and_unblock_sigs(); |
| /* Create a new session and make ourself the process group leader */ | |
| setsid(); | |
| @@ -651,12 +656,21 @@ static void run_shutdown_and_kill_processes(void) | |
| * and only one will be remembered and acted upon. | |
| */ | |
| + | /* The SIGUSR[12]/SIGTERM handler */ |
| static void halt_reboot_pwoff(int sig) NORETURN; | |
| static void halt_reboot_pwoff(int sig) | |
| { | |
| const char *m; | |
| unsigned rb; | |
| + | /* We may call run() and it unmasks signals, |
| + | * including the one masked inside this signal handler. |
| + | * Testcase which would start multiple reboot scripts: |
| + | * while true; do reboot; done |
| + | * Preventing it: |
| + | */ |
| + | reset_sighandlers_and_unblock_sigs(); |
| + | |
| run_shutdown_and_kill_processes(); | |
| m = "halt"; | |
| @@ -673,38 +687,6 @@ static void halt_reboot_pwoff(int sig) | |
| /* not reached */ | |
| } | |
| - | /* The SIGSTOP/SIGTSTP handler |
| - | * NB: inside it, all signals except SIGCONT are masked |
| - | * via appropriate setup in sigaction(). |
| - | */ |
| - | static void stop_handler(int sig UNUSED_PARAM) |
| - | { |
| - | smallint saved_bb_got_signal; |
| - | int saved_errno; |
| - | |
| - | saved_bb_got_signal = bb_got_signal; |
| - | saved_errno = errno; |
| - | signal(SIGCONT, record_signo); |
| - | |
| - | while (1) { |
| - | pid_t wpid; |
| - | |
| - | if (bb_got_signal == SIGCONT) |
| - | break; |
| - | /* NB: this can accidentally wait() for a process |
| - | * which we waitfor() elsewhere! waitfor() must have |
| - | * code which is resilient against this. |
| - | */ |
| - | wpid = wait_any_nohang(NULL); |
| - | mark_terminated(wpid); |
| - | sleep(1); |
| - | } |
| - | |
| - | signal(SIGCONT, SIG_DFL); |
| - | errno = saved_errno; |
| - | bb_got_signal = saved_bb_got_signal; |
| - | } |
| - | |
| /* Handler for QUIT - exec "restart" action, | |
| * else (no such action defined) do nothing */ | |
| static void restart_handler(int sig UNUSED_PARAM) | |
| @@ -719,6 +701,9 @@ static void restart_handler(int sig UNUSED_PARAM) | |
| * Thus don't need to worry about preserving errno | |
| * and such. | |
| */ | |
| + | |
| + | reset_sighandlers_and_unblock_sigs(); |
| + | |
| run_shutdown_and_kill_processes(); | |
| /* Allow Ctrl-Alt-Del to reboot the system. | |
| @@ -744,6 +729,38 @@ static void restart_handler(int sig UNUSED_PARAM) | |
| } | |
| } | |
| + | /* The SIGSTOP/SIGTSTP handler |
| + | * NB: inside it, all signals except SIGCONT are masked |
| + | * via appropriate setup in sigaction(). |
| + | */ |
| + | static void stop_handler(int sig UNUSED_PARAM) |
| + | { |
| + | smallint saved_bb_got_signal; |
| + | int saved_errno; |
| + | |
| + | saved_bb_got_signal = bb_got_signal; |
| + | saved_errno = errno; |
| + | signal(SIGCONT, record_signo); |
| + | |
| + | while (1) { |
| + | pid_t wpid; |
| + | |
| + | if (bb_got_signal == SIGCONT) |
| + | break; |
| + | /* NB: this can accidentally wait() for a process |
| + | * which we waitfor() elsewhere! waitfor() must have |
| + | * code which is resilient against this. |
| + | */ |
| + | wpid = wait_any_nohang(NULL); |
| + | mark_terminated(wpid); |
| + | sleep(1); |
| + | } |
| + | |
| + | signal(SIGCONT, SIG_DFL); |
| + | errno = saved_errno; |
| + | bb_got_signal = saved_bb_got_signal; |
| + | } |
| + | |
| #if ENABLE_FEATURE_USE_INITTAB | |
| static void reload_inittab(void) | |
| { | |