9fc0f6
From f0fdbdb003cb3e8d8188c1c01701b510505b5b8b Mon Sep 17 00:00:00 2001
9fc0f6
From: Lennart Poettering <lennart@poettering.net>
9fc0f6
Date: Wed, 27 Aug 2014 21:42:20 +0200
9fc0f6
Subject: [PATCH] util: fix minimal race where we might miss SIGTERMs when
9fc0f6
 forking off an agent
9fc0f6
9fc0f6
Before forking, block all signals, and unblock them afterwards. This way
9fc0f6
the child will have them blocked, and we won't lose them.
9fc0f6
9fc0f6
(cherry picked from commit 8a7c93d858c342744adf481565d8bb03b9713dcf)
9fc0f6
9fc0f6
Related: #1134818
9fc0f6
---
9fc0f6
 src/shared/util.c | 35 +++++++++++++++++++++++------------
9fc0f6
 1 file changed, 23 insertions(+), 12 deletions(-)
9fc0f6
9fc0f6
diff --git a/src/shared/util.c b/src/shared/util.c
9fc0f6
index e4448ff..9f25b15 100644
9fc0f6
--- a/src/shared/util.c
9fc0f6
+++ b/src/shared/util.c
9fc0f6
@@ -5002,9 +5002,9 @@ int fd_inc_rcvbuf(int fd, size_t n) {
9fc0f6
 }
9fc0f6
 
9fc0f6
 int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
9fc0f6
-        pid_t parent_pid, agent_pid;
9fc0f6
-        int fd;
9fc0f6
         bool stdout_is_tty, stderr_is_tty;
9fc0f6
+        pid_t parent_pid, agent_pid;
9fc0f6
+        sigset_t ss, saved_ss;
9fc0f6
         unsigned n, i;
9fc0f6
         va_list ap;
9fc0f6
         char **l;
9fc0f6
@@ -5012,16 +5012,25 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
9fc0f6
         assert(pid);
9fc0f6
         assert(path);
9fc0f6
 
9fc0f6
-        parent_pid = getpid();
9fc0f6
-
9fc0f6
         /* Spawns a temporary TTY agent, making sure it goes away when
9fc0f6
          * we go away */
9fc0f6
 
9fc0f6
+        parent_pid = getpid();
9fc0f6
+
9fc0f6
+        /* First we temporarily block all signals, so that the new
9fc0f6
+         * child has them blocked initially. This way, we can be sure
9fc0f6
+         * that SIGTERMs are not lost we might send to the agent. */
9fc0f6
+        assert_se(sigfillset(&ss) >= 0);
9fc0f6
+        assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
9fc0f6
+
9fc0f6
         agent_pid = fork();
9fc0f6
-        if (agent_pid < 0)
9fc0f6
+        if (agent_pid < 0) {
9fc0f6
+                assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
9fc0f6
                 return -errno;
9fc0f6
+        }
9fc0f6
 
9fc0f6
         if (agent_pid != 0) {
9fc0f6
+                assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
9fc0f6
                 *pid = agent_pid;
9fc0f6
                 return 0;
9fc0f6
         }
9fc0f6
@@ -5032,24 +5041,26 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
9fc0f6
         if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
9fc0f6
                 _exit(EXIT_FAILURE);
9fc0f6
 
9fc0f6
+        /* Make sure we actually can kill the agent, if we need to, in
9fc0f6
+         * case somebody invoked us from a shell script that trapped
9fc0f6
+         * SIGTERM or so... */
9fc0f6
+        reset_all_signal_handlers();
9fc0f6
+        reset_signal_mask();
9fc0f6
+
9fc0f6
         /* Check whether our parent died before we were able
9fc0f6
-         * to set the death signal */
9fc0f6
+         * to set the death signal and unblock the signals */
9fc0f6
         if (getppid() != parent_pid)
9fc0f6
                 _exit(EXIT_SUCCESS);
9fc0f6
 
9fc0f6
         /* Don't leak fds to the agent */
9fc0f6
         close_all_fds(except, n_except);
9fc0f6
 
9fc0f6
-        /* Make sure we actually can kill the agent, if we need to, in
9fc0f6
-         * case somebody invoked us from a shell script that trapped
9fc0f6
-         * SIGTERM or so... */
9fc0f6
-        reset_all_signal_handlers();
9fc0f6
-        reset_signal_mask();
9fc0f6
-
9fc0f6
         stdout_is_tty = isatty(STDOUT_FILENO);
9fc0f6
         stderr_is_tty = isatty(STDERR_FILENO);
9fc0f6
 
9fc0f6
         if (!stdout_is_tty || !stderr_is_tty) {
9fc0f6
+                int fd;
9fc0f6
+
9fc0f6
                 /* Detach from stdout/stderr. and reopen
9fc0f6
                  * /dev/tty for them. This is important to
9fc0f6
                  * ensure that when systemctl is started via