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