The branch stable/14 has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=1fe93549714d01e16e76af0d279bd05c5a7e0c7d
commit 1fe93549714d01e16e76af0d279bd05c5a7e0c7d Author: Aaron LI <a...@aaronly.me> AuthorDate: 2025-04-03 01:07:52 +0000 Commit: Konstantin Belousov <k...@freebsd.org> CommitDate: 2025-06-16 08:51:53 +0000 timeout(1): Fix the inheritance of signal dispositions (cherry picked from commit 2390cbfe55f55916eca25e8ba94a3320535e01c9) --- bin/timeout/timeout.1 | 10 +++++++++- bin/timeout/timeout.c | 50 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/bin/timeout/timeout.1 b/bin/timeout/timeout.1 index 14fc19292684..371a167d19f3 100644 --- a/bin/timeout/timeout.1 +++ b/bin/timeout/timeout.1 @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd April 2, 2025 +.Dd April 3, 2025 .Dt TIMEOUT 1 .Os .Sh NAME @@ -65,6 +65,14 @@ Therefore, a signal is never sent if .Ar duration is 0. .Pp +The signal dispositions inherited by the +.Ar command +are the same as the dispositions that +.Nm +inherited, except for the signal that will be sent upon timeout, +which is reset to take the default action and should terminate +the process. +.Pp The options are as follows: .Bl -tag -width indent .It Fl f , Fl -foreground diff --git a/bin/timeout/timeout.c b/bin/timeout/timeout.c index 8a2f0faecd83..1c4cfa6e017d 100644 --- a/bin/timeout/timeout.c +++ b/bin/timeout/timeout.c @@ -224,6 +224,7 @@ main(int argc, char **argv) bool timedout = false; bool do_second_kill = false; bool child_done = false; + sigset_t zeromask, allmask, oldmask; struct sigaction signals; struct procctl_reaper_status info; int signums[] = { @@ -288,6 +289,33 @@ main(int argc, char **argv) err(EXIT_FAILURE, "procctl(PROC_REAP_ACQUIRE)"); } + /* Block all signals to avoid racing against the child. */ + sigfillset(&allmask); + if (sigprocmask(SIG_BLOCK, &allmask, &oldmask) == -1) + err(EXIT_FAILURE, "sigprocmask()"); + + pid = fork(); + if (pid == -1) { + err(EXIT_FAILURE, "fork()"); + } else if (pid == 0) { + /* + * child process + * + * POSIX.1-2024 requires that the child process inherit the + * same signal dispositions as the timeout(1) utility + * inherited, except for the signal to be sent upon timeout. + */ + signal(killsig, SIG_DFL); + if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1) + err(EXIT_FAILURE, "sigprocmask(oldmask)"); + + execvp(argv[0], argv); + warn("exec(%s)", argv[0]); + _exit(errno == ENOENT ? EXIT_CMD_NOENT : EXIT_CMD_ERROR); + } + + /* parent continues here */ + memset(&signals, 0, sizeof(signals)); sigemptyset(&signals.sa_mask); @@ -310,29 +338,11 @@ main(int argc, char **argv) signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); - pid = fork(); - if (pid == -1) { - err(EXIT_FAILURE, "fork()"); - } else if (pid == 0) { - /* child process */ - signal(SIGTTIN, SIG_DFL); - signal(SIGTTOU, SIG_DFL); - - execvp(argv[0], argv); - warn("exec(%s)", argv[0]); - _exit(errno == ENOENT ? EXIT_CMD_NOENT : EXIT_CMD_ERROR); - } - - /* parent continues here */ - - if (sigprocmask(SIG_BLOCK, &signals.sa_mask, NULL) == -1) - err(EXIT_FAILURE, "sigprocmask()"); - set_interval(first_kill); - sigemptyset(&signals.sa_mask); + sigemptyset(&zeromask); for (;;) { - sigsuspend(&signals.sa_mask); + sigsuspend(&zeromask); if (sig_chld) { sig_chld = 0;