Skip to content

Commit

Permalink
init: do not run shutdown/reexec actions from signal handler
Browse files Browse the repository at this point in the history
this is racy wrt various libc functions such as syslog()

function                                             old     new   delta
check_delayed_sigs                                   182     352    +170
init_main                                            772     728     -44
restart_handler                                       74       -     -74
halt_reboot_pwoff                                     79       -     -79
------------------------------------------------------------------------------
(add/remove: 0/2 grow/shrink: 1/1 up/down: 170/-197)          Total: -27 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
  • Loading branch information
Denys Vlasenko committed Nov 21, 2014
1 parent 4e314fa commit 2bba9ad
Showing 1 changed file with 30 additions and 20 deletions.
50 changes: 30 additions & 20 deletions init/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,7 @@ static void halt_reboot_pwoff(int sig)

/* Handler for QUIT - exec "restart" action,
* else (no such action defined) do nothing */
static void restart_handler(int sig UNUSED_PARAM)
static void exec_restart_action(void)
{
struct init_action *a;

Expand Down Expand Up @@ -975,6 +975,20 @@ static int check_delayed_sigs(void)
#endif
if (sig == SIGINT)
run_actions(CTRLALTDEL);
if (sig == SIGQUIT) {
exec_restart_action();
/* returns only if no restart action defined */
}
if ((1 << sig) & (0
#ifdef SIGPWR
+ (1 << SIGPWR)
#endif
+ (1 << SIGUSR1)
+ (1 << SIGUSR2)
+ (1 << SIGTERM)
)) {
halt_reboot_pwoff(sig);
}
}
}

Expand Down Expand Up @@ -1070,7 +1084,7 @@ int init_main(int argc UNUSED_PARAM, char **argv)

#if 0
/* It's 2013, does anyone really still depend on this? */
/* If you do, consider adding swapon to sysinot actions then! */
/* If you do, consider adding swapon to sysinit actions then! */
/* struct sysinfo is linux-specific */
# ifdef __linux__
/* Make sure there is enough memory to do something useful. */
Expand Down Expand Up @@ -1134,16 +1148,6 @@ int init_main(int argc UNUSED_PARAM, char **argv)
if (!DEBUG_INIT) {
struct sigaction sa;

bb_signals(0
#ifdef SIGPWR
+ (1 << SIGPWR) /* halt */
#endif
+ (1 << SIGUSR1) /* halt */
+ (1 << SIGTERM) /* reboot */
+ (1 << SIGUSR2) /* poweroff */
, halt_reboot_pwoff);
signal(SIGQUIT, restart_handler); /* re-exec another init */

/* Stop handler must allow only SIGCONT inside itself */
memset(&sa, 0, sizeof(sa));
sigfillset(&sa.sa_mask);
Expand All @@ -1158,18 +1162,24 @@ int init_main(int argc UNUSED_PARAM, char **argv)
*/
sigaction_set(SIGSTOP, &sa); /* pause */

/* SIGINT (Ctrl-Alt-Del) must interrupt wait(),
/* These signals must interrupt wait(),
* setting handler without SA_RESTART flag.
*/
bb_signals_recursive_norestart((1 << SIGINT), record_signo);
bb_signals_recursive_norestart(0
+ (1 << SIGINT) /* Ctrl-Alt-Del */
+ (1 << SIGQUIT) /* re-exec another init */
#ifdef SIGPWR
+ (1 << SIGPWR) /* halt */
#endif
+ (1 << SIGUSR1) /* halt */
+ (1 << SIGTERM) /* reboot */
+ (1 << SIGUSR2) /* poweroff */
#if ENABLE_FEATURE_USE_INITTAB
+ (1 << SIGHUP) /* reread /etc/inittab */
#endif
, record_signo);
}

/* Set up "reread /etc/inittab" handler.
* Handler is set up without SA_RESTART, it will interrupt syscalls.
*/
if (!DEBUG_INIT && ENABLE_FEATURE_USE_INITTAB)
bb_signals_recursive_norestart((1 << SIGHUP), record_signo);

/* Now run everything that needs to be run */
/* First run the sysinit command */
run_actions(SYSINIT);
Expand Down

2 comments on commit 2bba9ad

@AnkurTank
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recently we upgraded busybox from version 1.20.2 to 1.26.2.
We are facing a issue where reboots(as mentioned below) from init scripts doesn't seem to work.
In case of critical errors during initscript execution we used to reboot the board. Now reboot doesn't seem to work however reboot -f works but that doesn't run stop script to do cleanup. From SO I got redirected to this patch.

reboot_and_hang()
{
     reboot
     while [ true ]
     do
          sleep 1
     done
}

I have following queries, if someone can help

  1. What kind of race this patch is solving ?
  2. Is there a better way to reboot the board from init script which will run stop script as well ?

@likema
Copy link

@likema likema commented on 2bba9ad Oct 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have the similar issues when a single app is runing at sysinit.

It can be fixed by reverting this patch.

Please sign in to comment.