mirror of
https://github.com/systemd/systemd.git
synced 2024-12-25 01:34:28 +03:00
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.
This commit is contained in:
parent
c609cb9898
commit
8a7c93d858
@ -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);
|
||||
|
||||
/* Check whether our parent died before we were able
|
||||
* to set the death signal */
|
||||
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();
|
||||
|
||||
/* Check whether our parent died before we were able
|
||||
* 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);
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user