From d7e38115cbe14b289cc9165bb26a36d1c2abbc35 Mon Sep 17 00:00:00 2001 From: Mike Gilbert Date: Mon, 10 Feb 2020 17:17:02 -0500 Subject: [PATCH 1/2] safe_fork: unblock most signals before waiting for child This ensures we will recieve SIGTSTP if the user presses Ctrl-Z. We continue blocking SIGCHLD to ensure the child is processed by wait_for_terminate_and_check. Fixes: https://github.com/systemd/systemd/issues/9806 --- src/basic/process-util.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 5de366f830..4914da6c0b 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -1187,7 +1187,7 @@ int safe_fork_full( pid_t original_pid, pid; sigset_t saved_ss, ss; - bool block_signals = false; + bool block_signals = false, block_all = false; int prio, r; /* A wrapper around fork(), that does a couple of important initializations in addition to mere forking. Always @@ -1202,7 +1202,7 @@ int safe_fork_full( * be sure that SIGTERMs are not lost we might send to the child. */ assert_se(sigfillset(&ss) >= 0); - block_signals = true; + block_signals = block_all = true; } else if (flags & FORK_WAIT) { /* Let's block SIGCHLD at least, so that we can safely watch for the child process */ @@ -1234,6 +1234,13 @@ int safe_fork_full( log_debug("Successfully forked off '%s' as PID " PID_FMT ".", strna(name), pid); if (flags & FORK_WAIT) { + if (block_all) { + /* undo everything except SIGCHLD */ + ss = saved_ss; + assert_se(sigaddset(&ss, SIGCHLD) >= 0); + (void) sigprocmask(SIG_SETMASK, &ss, NULL); + } + r = wait_for_terminate_and_check(name, pid, (flags & FORK_LOG ? WAIT_LOG : 0)); if (r < 0) return r; From 4b3abcd01968bff0f816c1dc358a625a94cf2ee8 Mon Sep 17 00:00:00 2001 From: Mike Gilbert Date: Tue, 11 Feb 2020 11:17:49 -0500 Subject: [PATCH 2/2] safe_fork: use a cleanup function to restore signal mask in parent --- src/basic/process-util.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 4914da6c0b..fefc2bd840 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -1178,6 +1178,11 @@ int must_be_root(void) { return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Need to be root."); } +static void restore_sigsetp(sigset_t **ssp) { + if (*ssp) + (void) sigprocmask(SIG_SETMASK, *ssp, NULL); +} + int safe_fork_full( const char *name, const int except_fds[], @@ -1187,6 +1192,7 @@ int safe_fork_full( pid_t original_pid, pid; sigset_t saved_ss, ss; + _cleanup_(restore_sigsetp) sigset_t *saved_ssp = NULL; bool block_signals = false, block_all = false; int prio, r; @@ -1212,22 +1218,18 @@ int safe_fork_full( block_signals = true; } - if (block_signals) + if (block_signals) { if (sigprocmask(SIG_SETMASK, &ss, &saved_ss) < 0) return log_full_errno(prio, errno, "Failed to set signal mask: %m"); + saved_ssp = &saved_ss; + } if (flags & FORK_NEW_MOUNTNS) pid = raw_clone(SIGCHLD|CLONE_NEWNS); else pid = fork(); - if (pid < 0) { - r = -errno; - - if (block_signals) /* undo what we did above */ - (void) sigprocmask(SIG_SETMASK, &saved_ss, NULL); - - return log_full_errno(prio, r, "Failed to fork: %m"); - } + if (pid < 0) + return log_full_errno(prio, errno, "Failed to fork: %m"); if (pid > 0) { /* We are in the parent process */ @@ -1248,9 +1250,6 @@ int safe_fork_full( return -EPROTO; } - if (block_signals) /* undo what we did above */ - (void) sigprocmask(SIG_SETMASK, &saved_ss, NULL); - if (ret_pid) *ret_pid = pid; @@ -1259,6 +1258,9 @@ int safe_fork_full( /* We are in the child process */ + /* Restore signal mask manually */ + saved_ssp = NULL; + if (flags & FORK_REOPEN_LOG) { /* Close the logs if requested, before we log anything. And make sure we reopen it if needed. */ log_close();