[git commit master] init: fix "while true; do reboot; done" bug. +15 bytes. Closes bug 781

Denys Vlasenko vda.linux at googlemail.com
Mon Dec 14 02:03:29 UTC 2009


commit: http://git.busybox.net/busybox/commit/?id=bcc6ec9b7e19087254ef323bcc503bb8b6872d75
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 init/init.c |  101 ++++++++++++++++++++++++++++++++++------------------------
 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)
 {
-- 
1.6.3.3



More information about the busybox-cvs mailing list