git: 1fe93549714d - stable/14 - timeout(1): Fix the inheritance of signal dispositions
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 16 Jun 2025 08:54:06 UTC
The branch stable/14 has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=1fe93549714d01e16e76af0d279bd05c5a7e0c7d
commit 1fe93549714d01e16e76af0d279bd05c5a7e0c7d
Author: Aaron LI <aly@aaronly.me>
AuthorDate: 2025-04-03 01:07:52 +0000
Commit: Konstantin Belousov <kib@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;