subprocess: unblock/reset signals before running child process

During execve() ignored and blocked signals carry over to the child
process, though apparently for SIGCHLD (which the bug report was about)
this is implementation-defined.
fixes #9613
This commit is contained in:
sfan5 2021-12-19 14:17:54 +01:00
parent fd63bf398a
commit 24dcb5d167
1 changed files with 21 additions and 0 deletions

View File

@ -33,6 +33,12 @@
extern char **environ; extern char **environ;
#ifdef SIGRTMAX
#define SIGNAL_MAX SIGRTMAX
#else
#define SIGNAL_MAX 32
#endif
#define SAFE_CLOSE(fd) do { if ((fd) >= 0) close((fd)); (fd) = -1; } while (0) #define SAFE_CLOSE(fd) do { if ((fd) >= 0) close((fd)); (fd) = -1; } while (0)
// Async-signal-safe execvpe(). POSIX does not list it as async-signal-safe // Async-signal-safe execvpe(). POSIX does not list it as async-signal-safe
@ -65,6 +71,20 @@ static int as_execvpe(const char *path, const char *file, char *const argv[],
return -1; return -1;
} }
// In the child process, resets the signal mask to defaults. Also clears any
// signal handlers first so nothing funny happens.
static void reset_signals_child(void)
{
struct sigaction sa = { 0 };
sigset_t sigmask;
sa.sa_handler = SIG_DFL;
sigemptyset(&sigmask);
for (int nr = 1; nr < SIGNAL_MAX; nr++)
sigaction(nr, &sa, NULL);
sigprocmask(SIG_SETMASK, &sigmask, NULL);
}
// Returns 0 on any error, valid PID on success. // Returns 0 on any error, valid PID on success.
// This function must be async-signal-safe, as it may be called from a fork(). // This function must be async-signal-safe, as it may be called from a fork().
static pid_t spawn_process(const char *path, struct mp_subprocess_opts *opts, static pid_t spawn_process(const char *path, struct mp_subprocess_opts *opts,
@ -96,6 +116,7 @@ static pid_t spawn_process(const char *path, struct mp_subprocess_opts *opts,
} }
if (fres == 0) { if (fres == 0) {
// child // child
reset_signals_child();
for (int n = 0; n < opts->num_fds; n++) { for (int n = 0; n < opts->num_fds; n++) {
if (src_fds[n] == opts->fds[n].fd) { if (src_fds[n] == opts->fds[n].fd) {