richardphibel / rpms / systemd

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