summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko2009-12-14 03:03:29 +0100
committerDenys Vlasenko2009-12-14 03:03:29 +0100
commitbcc6ec9b7e19087254ef323bcc503bb8b6872d75 (patch)
tree2f9bc3f4e1735a773602d667a0a6137278de70d4
parent6be918d0ae15ca5f8b3b3879c496205bc8a11c2b (diff)
downloadbusybox-bcc6ec9b7e19087254ef323bcc503bb8b6872d75.zip
busybox-bcc6ec9b7e19087254ef323bcc503bb8b6872d75.tar.gz
init: fix "while true; do reboot; done" bug. +15 bytes. Closes bug 781
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--init/init.c101
1 files changed, 59 insertions, 42 deletions
diff --git a/init/init.c b/init/init.c
index 3748a15..89bbafd 100644
--- a/init/init.c
+++ b/init/init.c
@@ -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)
{