|
|
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
|