aboutsummaryrefslogtreecommitdiff
path: root/init
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-12-14 03:03:29 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2009-12-14 03:03:29 +0100
commitbcc6ec9b7e19087254ef323bcc503bb8b6872d75 (patch)
tree2f9bc3f4e1735a773602d667a0a6137278de70d4 /init
parent6be918d0ae15ca5f8b3b3879c496205bc8a11c2b (diff)
downloadbusybox-w32-bcc6ec9b7e19087254ef323bcc503bb8b6872d75.tar.gz
busybox-w32-bcc6ec9b7e19087254ef323bcc503bb8b6872d75.tar.bz2
busybox-w32-bcc6ec9b7e19087254ef323bcc503bb8b6872d75.zip
init: fix "while true; do reboot; done" bug. +15 bytes. Closes bug 781
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'init')
-rw-r--r--init/init.c101
1 files changed, 59 insertions, 42 deletions
diff --git a/init/init.c b/init/init.c
index 3748a1507..89bbafd13 100644
--- a/init/init.c
+++ b/init/init.c
@@ -260,6 +260,20 @@ static int open_stdio_to_tty(const char* tty_name)
260 return 1; /* success */ 260 return 1; /* success */
261} 261}
262 262
263static void reset_sighandlers_and_unblock_sigs(void)
264{
265 bb_signals(0
266 + (1 << SIGUSR1)
267 + (1 << SIGUSR2)
268 + (1 << SIGTERM)
269 + (1 << SIGQUIT)
270 + (1 << SIGINT)
271 + (1 << SIGHUP)
272 + (1 << SIGTSTP)
273 , SIG_DFL);
274 sigprocmask_allsigs(SIG_UNBLOCK);
275}
276
263/* Wrapper around exec: 277/* Wrapper around exec:
264 * Takes string (max COMMAND_SIZE chars). 278 * Takes string (max COMMAND_SIZE chars).
265 * If chars like '>' detected, execs '[-]/bin/sh -c "exec ......."'. 279 * If chars like '>' detected, execs '[-]/bin/sh -c "exec ......."'.
@@ -329,16 +343,7 @@ static pid_t run(const struct init_action *a)
329 /* Child */ 343 /* Child */
330 344
331 /* Reset signal handlers that were set by the parent process */ 345 /* Reset signal handlers that were set by the parent process */
332 bb_signals(0 346 reset_sighandlers_and_unblock_sigs();
333 + (1 << SIGUSR1)
334 + (1 << SIGUSR2)
335 + (1 << SIGTERM)
336 + (1 << SIGQUIT)
337 + (1 << SIGINT)
338 + (1 << SIGHUP)
339 + (1 << SIGTSTP)
340 , SIG_DFL);
341 sigprocmask_allsigs(SIG_UNBLOCK);
342 347
343 /* Create a new session and make ourself the process group leader */ 348 /* Create a new session and make ourself the process group leader */
344 setsid(); 349 setsid();
@@ -651,12 +656,21 @@ static void run_shutdown_and_kill_processes(void)
651 * and only one will be remembered and acted upon. 656 * and only one will be remembered and acted upon.
652 */ 657 */
653 658
659/* The SIGUSR[12]/SIGTERM handler */
654static void halt_reboot_pwoff(int sig) NORETURN; 660static void halt_reboot_pwoff(int sig) NORETURN;
655static void halt_reboot_pwoff(int sig) 661static void halt_reboot_pwoff(int sig)
656{ 662{
657 const char *m; 663 const char *m;
658 unsigned rb; 664 unsigned rb;
659 665
666 /* We may call run() and it unmasks signals,
667 * including the one masked inside this signal handler.
668 * Testcase which would start multiple reboot scripts:
669 * while true; do reboot; done
670 * Preventing it:
671 */
672 reset_sighandlers_and_unblock_sigs();
673
660 run_shutdown_and_kill_processes(); 674 run_shutdown_and_kill_processes();
661 675
662 m = "halt"; 676 m = "halt";
@@ -673,38 +687,6 @@ static void halt_reboot_pwoff(int sig)
673 /* not reached */ 687 /* not reached */
674} 688}
675 689
676/* The SIGSTOP/SIGTSTP handler
677 * NB: inside it, all signals except SIGCONT are masked
678 * via appropriate setup in sigaction().
679 */
680static void stop_handler(int sig UNUSED_PARAM)
681{
682 smallint saved_bb_got_signal;
683 int saved_errno;
684
685 saved_bb_got_signal = bb_got_signal;
686 saved_errno = errno;
687 signal(SIGCONT, record_signo);
688
689 while (1) {
690 pid_t wpid;
691
692 if (bb_got_signal == SIGCONT)
693 break;
694 /* NB: this can accidentally wait() for a process
695 * which we waitfor() elsewhere! waitfor() must have
696 * code which is resilient against this.
697 */
698 wpid = wait_any_nohang(NULL);
699 mark_terminated(wpid);
700 sleep(1);
701 }
702
703 signal(SIGCONT, SIG_DFL);
704 errno = saved_errno;
705 bb_got_signal = saved_bb_got_signal;
706}
707
708/* Handler for QUIT - exec "restart" action, 690/* Handler for QUIT - exec "restart" action,
709 * else (no such action defined) do nothing */ 691 * else (no such action defined) do nothing */
710static void restart_handler(int sig UNUSED_PARAM) 692static void restart_handler(int sig UNUSED_PARAM)
@@ -719,6 +701,9 @@ static void restart_handler(int sig UNUSED_PARAM)
719 * Thus don't need to worry about preserving errno 701 * Thus don't need to worry about preserving errno
720 * and such. 702 * and such.
721 */ 703 */
704
705 reset_sighandlers_and_unblock_sigs();
706
722 run_shutdown_and_kill_processes(); 707 run_shutdown_and_kill_processes();
723 708
724 /* Allow Ctrl-Alt-Del to reboot the system. 709 /* Allow Ctrl-Alt-Del to reboot the system.
@@ -744,6 +729,38 @@ static void restart_handler(int sig UNUSED_PARAM)
744 } 729 }
745} 730}
746 731
732/* The SIGSTOP/SIGTSTP handler
733 * NB: inside it, all signals except SIGCONT are masked
734 * via appropriate setup in sigaction().
735 */
736static void stop_handler(int sig UNUSED_PARAM)
737{
738 smallint saved_bb_got_signal;
739 int saved_errno;
740
741 saved_bb_got_signal = bb_got_signal;
742 saved_errno = errno;
743 signal(SIGCONT, record_signo);
744
745 while (1) {
746 pid_t wpid;
747
748 if (bb_got_signal == SIGCONT)
749 break;
750 /* NB: this can accidentally wait() for a process
751 * which we waitfor() elsewhere! waitfor() must have
752 * code which is resilient against this.
753 */
754 wpid = wait_any_nohang(NULL);
755 mark_terminated(wpid);
756 sleep(1);
757 }
758
759 signal(SIGCONT, SIG_DFL);
760 errno = saved_errno;
761 bb_got_signal = saved_bb_got_signal;
762}
763
747#if ENABLE_FEATURE_USE_INITTAB 764#if ENABLE_FEATURE_USE_INITTAB
748static void reload_inittab(void) 765static void reload_inittab(void)
749{ 766{