forked from pool/systemd
97 lines
3.2 KiB
Diff
97 lines
3.2 KiB
Diff
Based on 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 | 39 ++++++++++++++++++++++++++++++++++-----
|
|
1 file changed, 34 insertions(+), 5 deletions(-)
|
|
|
|
--- src/shared/util.c
|
|
+++ src/shared/util.c 2014-08-28 10:32:06.442693437 +0000
|
|
@@ -894,6 +894,18 @@ int reset_all_signal_handlers(void) {
|
|
return 0;
|
|
}
|
|
|
|
+static int reset_signal_mask(void) {
|
|
+ sigset_t ss;
|
|
+
|
|
+ if (sigemptyset(&ss) < 0)
|
|
+ return -errno;
|
|
+
|
|
+ if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
|
|
+ return -errno;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
char *strstrip(char *s) {
|
|
char *e;
|
|
|
|
@@ -5119,9 +5131,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;
|
|
@@ -5129,16 +5141,25 @@ int fork_agent(pid_t *pid, const int exc
|
|
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;
|
|
}
|
|
@@ -5149,6 +5170,12 @@ int fork_agent(pid_t *pid, const int exc
|
|
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 */
|
|
if (getppid() != parent_pid)
|
|
@@ -5161,6 +5188,8 @@ int fork_agent(pid_t *pid, const int exc
|
|
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
|