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