aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2021-06-05 16:20:05 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2021-06-05 16:20:05 +0200
commit5dadd497ffd9835a2860cf89ad781d1b513803dc (patch)
tree7ad8eb72b3cd1b5a3d94cd6d2ead9e86f2779c0a
parentd3e1090308b6d3c55e01a2000a743b73605ddd7f (diff)
downloadbusybox-w32-5dadd497ffd9835a2860cf89ad781d1b513803dc.tar.gz
busybox-w32-5dadd497ffd9835a2860cf89ad781d1b513803dc.tar.bz2
busybox-w32-5dadd497ffd9835a2860cf89ad781d1b513803dc.zip
runsv: robustify signal handling - SIGTERM to child between vfork and exec could mess things up
While at it, rename bb_signals_recursive_norestart() to bb_signals_norestart(): "recursive" was implying we are setting SA_NODEFER allowing signal handler to be entered recursively, but we do not do that. function old new delta bb_signals_norestart - 70 +70 startservice 380 394 +14 bb_signals_recursive_norestart 70 - -70 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 1/0 up/down: 84/-70) Total: 14 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--console-tools/showkey.c2
-rw-r--r--include/libbb.h2
-rw-r--r--libbb/signals.c2
-rw-r--r--runit/runsv.c29
-rw-r--r--runit/svlogd.c8
-rw-r--r--sysklogd/klogd.c2
6 files changed, 27 insertions, 18 deletions
diff --git a/console-tools/showkey.c b/console-tools/showkey.c
index 4d7a9b9e5..84eb38a0a 100644
--- a/console-tools/showkey.c
+++ b/console-tools/showkey.c
@@ -106,7 +106,7 @@ int showkey_main(int argc UNUSED_PARAM, char **argv)
106 xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)((option_mask32 & OPT_k) ? K_MEDIUMRAW : K_RAW)); 106 xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)((option_mask32 & OPT_k) ? K_MEDIUMRAW : K_RAW));
107 107
108 // we should exit on any signal; signals should interrupt read 108 // we should exit on any signal; signals should interrupt read
109 bb_signals_recursive_norestart(BB_FATAL_SIGS, record_signo); 109 bb_signals_norestart(BB_FATAL_SIGS, record_signo);
110 110
111 // inform user that program ends after time of inactivity 111 // inform user that program ends after time of inactivity
112 printf(press_keys, "10s after last keypress"); 112 printf(press_keys, "10s after last keypress");
diff --git a/include/libbb.h b/include/libbb.h
index 4c9c83bd1..a3f76a206 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -593,7 +593,7 @@ void bb_signals(int sigs, void (*f)(int)) FAST_FUNC;
593/* Unlike signal() and bb_signals, sets handler with sigaction() 593/* Unlike signal() and bb_signals, sets handler with sigaction()
594 * and in a way that while signal handler is run, no other signals 594 * and in a way that while signal handler is run, no other signals
595 * will be blocked; syscalls will not be restarted: */ 595 * will be blocked; syscalls will not be restarted: */
596void bb_signals_recursive_norestart(int sigs, void (*f)(int)) FAST_FUNC; 596void bb_signals_norestart(int sigs, void (*f)(int)) FAST_FUNC;
597/* syscalls like read() will be interrupted with EINTR: */ 597/* syscalls like read() will be interrupted with EINTR: */
598void signal_no_SA_RESTART_empty_mask(int sig, void (*handler)(int)) FAST_FUNC; 598void signal_no_SA_RESTART_empty_mask(int sig, void (*handler)(int)) FAST_FUNC;
599/* syscalls like read() won't be interrupted (though select/poll will be): */ 599/* syscalls like read() won't be interrupted (though select/poll will be): */
diff --git a/libbb/signals.c b/libbb/signals.c
index d3d84ef6a..0bebc847d 100644
--- a/libbb/signals.c
+++ b/libbb/signals.c
@@ -56,7 +56,7 @@ void FAST_FUNC bb_signals(int sigs, void (*f)(int))
56 } 56 }
57} 57}
58 58
59void FAST_FUNC bb_signals_recursive_norestart(int sigs, void (*f)(int)) 59void FAST_FUNC bb_signals_norestart(int sigs, void (*f)(int))
60{ 60{
61 int sig_no = 0; 61 int sig_no = 0;
62 int bit = 1; 62 int bit = 1;
diff --git a/runit/runsv.c b/runit/runsv.c
index 61ea240ff..7fad563f5 100644
--- a/runit/runsv.c
+++ b/runit/runsv.c
@@ -149,11 +149,15 @@ static void warn_cannot(const char *m)
149 warn2_cannot(m, ""); 149 warn2_cannot(m, "");
150} 150}
151 151
152/* SIGCHLD/TERM handlers are reentrancy-safe because they are unmasked
153 * only over poll() call, not over memory allocations
154 * or printouts. Do not need to save/restore errno either,
155 * as poll() error is not checked there.
156 */
152static void s_child(int sig_no UNUSED_PARAM) 157static void s_child(int sig_no UNUSED_PARAM)
153{ 158{
154 write(selfpipe.wr, "", 1); 159 write(selfpipe.wr, "", 1);
155} 160}
156
157static void s_term(int sig_no UNUSED_PARAM) 161static void s_term(int sig_no UNUSED_PARAM)
158{ 162{
159 sigterm = 1; 163 sigterm = 1;
@@ -380,14 +384,14 @@ static void startservice(struct svdir *s)
380 xdup2(logpipe.wr, 1); 384 xdup2(logpipe.wr, 1);
381 } 385 }
382 } 386 }
383 /* Non-ignored signals revert to SIG_DFL on exec anyway. 387 /* Non-ignored signals revert to SIG_DFL on exec.
384 * But we can get signals BEFORE execl(), this is unlikely 388 * But we can get signals BEFORE execl(), unlikely as that may be.
385 * but wouldn't be good... 389 * SIGCHLD is safe (would merely write to selfpipe),
390 * but SIGTERM would set sigterm = 1 (with vfork, we affect parent).
391 * Avoid that.
386 */ 392 */
387 /*bb_signals(0 393 /*signal(SIGCHLD, SIG_DFL);*/
388 + (1 << SIGCHLD) 394 signal(SIGTERM, SIG_DFL);
389 + (1 << SIGTERM)
390 , SIG_DFL);*/
391 sig_unblock(SIGCHLD); 395 sig_unblock(SIGCHLD);
392 sig_unblock(SIGTERM); 396 sig_unblock(SIGTERM);
393 execv(arg[0], (char**) arg); 397 execv(arg[0], (char**) arg);
@@ -514,9 +518,13 @@ int runsv_main(int argc UNUSED_PARAM, char **argv)
514 ndelay_on(selfpipe.wr); 518 ndelay_on(selfpipe.wr);
515 519
516 sig_block(SIGCHLD); 520 sig_block(SIGCHLD);
517 bb_signals_recursive_norestart(1 << SIGCHLD, s_child);
518 sig_block(SIGTERM); 521 sig_block(SIGTERM);
519 bb_signals_recursive_norestart(1 << SIGTERM, s_term); 522 /* No particular reason why we don't set SA_RESTART
523 * (poll() wouldn't restart regardless of that flag),
524 * we just follow what runit-2.1.2 does:
525 */
526 bb_signals_norestart(1 << SIGCHLD, s_child);
527 bb_signals_norestart(1 << SIGTERM, s_term);
520 528
521 xchdir(dir); 529 xchdir(dir);
522 /* bss: svd[0].pid = 0; */ 530 /* bss: svd[0].pid = 0; */
@@ -628,6 +636,7 @@ int runsv_main(int argc UNUSED_PARAM, char **argv)
628 sig_unblock(SIGTERM); 636 sig_unblock(SIGTERM);
629 sig_unblock(SIGCHLD); 637 sig_unblock(SIGCHLD);
630 poll(x, 2 + haslog, 3600*1000); 638 poll(x, 2 + haslog, 3600*1000);
639 /* NB: signal handlers can trash errno of poll() */
631 sig_block(SIGTERM); 640 sig_block(SIGTERM);
632 sig_block(SIGCHLD); 641 sig_block(SIGCHLD);
633 642
diff --git a/runit/svlogd.c b/runit/svlogd.c
index 4490492e3..02c305696 100644
--- a/runit/svlogd.c
+++ b/runit/svlogd.c
@@ -1111,10 +1111,10 @@ int svlogd_main(int argc, char **argv)
1111 sigaddset(&blocked_sigset, SIGALRM); 1111 sigaddset(&blocked_sigset, SIGALRM);
1112 sigaddset(&blocked_sigset, SIGHUP); 1112 sigaddset(&blocked_sigset, SIGHUP);
1113 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL); 1113 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
1114 bb_signals_recursive_norestart(1 << SIGTERM, sig_term_handler); 1114 bb_signals_norestart(1 << SIGTERM, sig_term_handler);
1115 bb_signals_recursive_norestart(1 << SIGCHLD, sig_child_handler); 1115 bb_signals_norestart(1 << SIGCHLD, sig_child_handler);
1116 bb_signals_recursive_norestart(1 << SIGALRM, sig_alarm_handler); 1116 bb_signals_norestart(1 << SIGALRM, sig_alarm_handler);
1117 bb_signals_recursive_norestart(1 << SIGHUP, sig_hangup_handler); 1117 bb_signals_norestart(1 << SIGHUP, sig_hangup_handler);
1118 1118
1119 /* Without timestamps, we don't have to print each line 1119 /* Without timestamps, we don't have to print each line
1120 * separately, so we can look for _last_ newline, not first, 1120 * separately, so we can look for _last_ newline, not first,
diff --git a/sysklogd/klogd.c b/sysklogd/klogd.c
index 82596bc0b..df0edee0a 100644
--- a/sysklogd/klogd.c
+++ b/sysklogd/klogd.c
@@ -226,7 +226,7 @@ int klogd_main(int argc UNUSED_PARAM, char **argv)
226 226
227 signal(SIGHUP, SIG_IGN); 227 signal(SIGHUP, SIG_IGN);
228 /* We want klogd_read to not be restarted, thus _norestart: */ 228 /* We want klogd_read to not be restarted, thus _norestart: */
229 bb_signals_recursive_norestart(BB_FATAL_SIGS, record_signo); 229 bb_signals_norestart(BB_FATAL_SIGS, record_signo);
230 230
231 syslog(LOG_NOTICE, "klogd started: %s", bb_banner); 231 syslog(LOG_NOTICE, "klogd started: %s", bb_banner);
232 232