diff --git a/shell/hush.c b/shell/hush.c index bb95d6318..132b974f0 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -805,9 +805,9 @@ struct globals { unsigned special_sig_mask; #if ENABLE_HUSH_JOB unsigned fatal_sig_mask; -#define G_fatal_sig_mask G.fatal_sig_mask +# define G_fatal_sig_mask G.fatal_sig_mask #else -#define G_fatal_sig_mask 0 +# define G_fatal_sig_mask 0 #endif char **traps; /* char *traps[NSIG] */ sigset_t pending_set; @@ -1414,6 +1414,9 @@ static void restore_G_args(save_arg_t *sv, char **argv) * Standard says "When a subshell is entered, traps that are not being ignored * are set to the default actions". bash interprets it so that traps which * are set to '' (ignore) are NOT reset to defaults. We do the same. + * + * TODO: don't use signal() to install sighandlers: need to mask ALL signals + * while handler runs. I saw signal nesting in one strace, race window isn't small. */ enum { SPECIAL_INTERACTIVE_SIGS = 0 @@ -1486,12 +1489,13 @@ static sighandler_t pick_sighandler(unsigned sig) unsigned sigmask = (1 << sig); #if ENABLE_HUSH_JOB - /* sig is fatal? */ + /* is sig fatal? */ if (G_fatal_sig_mask & sigmask) handler = sigexit; + else #endif /* sig has special handling? */ - else if (G.special_sig_mask & sigmask) { + if (G.special_sig_mask & sigmask) { handler = record_pending_signo; /* TTIN/TTOU/TSTP can't be set to record_pending_signo * in order to ignore them: they will be raised @@ -5604,9 +5608,6 @@ static void re_execute_shell(char ***to_free, const char *s, * _inside_ group (just before echo 1), it works. * * I conclude it means we don't need to pass active traps here. - * Even if we would use signal handlers instead of signal masking - * in order to implement trap handling, - * exec syscall below resets signals to SIG_DFL for us. */ *pp++ = (char *) "-c"; *pp++ = (char *) s; @@ -5623,7 +5624,9 @@ static void re_execute_shell(char ***to_free, const char *s, do_exec: debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); - switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); + /* Don't propagate SIG_IGN to the child */ + if (SPECIAL_JOBSTOP_SIGS != 0) + switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); execve(bb_busybox_exec_path, argv, pp); /* Fallback. Useful for init=/bin/hush usage etc */ if (argv[0][0] == '/') @@ -6277,7 +6280,9 @@ static void execvp_or_die(char **argv) NORETURN; static void execvp_or_die(char **argv) { debug_printf_exec("execing '%s'\n", argv[0]); - switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); + /* Don't propagate SIG_IGN to the child */ + if (SPECIAL_JOBSTOP_SIGS != 0) + switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); execvp(argv[0], argv); bb_perror_msg("can't execute '%s'", argv[0]); _exit(127); /* bash compat */ @@ -6409,7 +6414,9 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, # endif /* Re-exec ourselves */ debug_printf_exec("re-execing applet '%s'\n", argv[0]); - switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); + /* Don't propagate SIG_IGN to the child */ + if (SPECIAL_JOBSTOP_SIGS != 0) + switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); execv(bb_busybox_exec_path, argv); /* If they called chroot or otherwise made the binary no longer * executable, fall through */