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