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