init: fix "while true; do reboot; done" bug. +15 bytes. Closes bug 781

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2009-12-14 03:03:29 +01:00
parent 6be918d0ae
commit bcc6ec9b7e

View File

@ -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,6 +687,48 @@ static void halt_reboot_pwoff(int sig)
/* not reached */
}
/* Handler for QUIT - exec "restart" action,
* else (no such action defined) do nothing */
static void restart_handler(int sig UNUSED_PARAM)
{
struct init_action *a;
for (a = init_action_list; a; a = a->next) {
if (!(a->action_type & RESTART))
continue;
/* Starting from here, we won't return.
* 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.
* This is how kernel sets it up for init, we follow suit.
*/
reboot(RB_ENABLE_CAD); /* misnomer */
if (open_stdio_to_tty(a->terminal)) {
dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command);
/* Theoretically should be safe.
* But in practice, kernel bugs may leave
* unkillable processes, and wait() may block forever.
* Oh well. Hoping "new" init won't be too surprised
* by having children it didn't create.
*/
//while (wait(NULL) > 0)
// continue;
init_exec(a->command);
}
/* Open or exec failed */
pause_and_low_level_reboot(RB_HALT_SYSTEM);
/* not reached */
}
}
/* The SIGSTOP/SIGTSTP handler
* NB: inside it, all signals except SIGCONT are masked
* via appropriate setup in sigaction().
@ -705,45 +761,6 @@ static void stop_handler(int sig UNUSED_PARAM)
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)
{
struct init_action *a;
for (a = init_action_list; a; a = a->next) {
if (!(a->action_type & RESTART))
continue;
/* Starting from here, we won't return.
* Thus don't need to worry about preserving errno
* and such.
*/
run_shutdown_and_kill_processes();
/* Allow Ctrl-Alt-Del to reboot the system.
* This is how kernel sets it up for init, we follow suit.
*/
reboot(RB_ENABLE_CAD); /* misnomer */
if (open_stdio_to_tty(a->terminal)) {
dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command);
/* Theoretically should be safe.
* But in practice, kernel bugs may leave
* unkillable processes, and wait() may block forever.
* Oh well. Hoping "new" init won't be too surprised
* by having children it didn't create.
*/
//while (wait(NULL) > 0)
// continue;
init_exec(a->command);
}
/* Open or exec failed */
pause_and_low_level_reboot(RB_HALT_SYSTEM);
/* not reached */
}
}
#if ENABLE_FEATURE_USE_INITTAB
static void reload_inittab(void)
{