summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsfan5 <sfan5@live.de>2021-12-19 14:17:54 +0100
committersfan5 <sfan5@live.de>2021-12-19 15:58:12 +0100
commit80c03b49bfbcc2567aeca39b7bba7c06d5bbb4dc (patch)
treec435502b8eeb3e73816ae2b7f518ef8aedf1480e
parente7fbc86d58baffc2e9aa5967bf93c94c2cfca43a (diff)
downloadmpv-80c03b49bfbcc2567aeca39b7bba7c06d5bbb4dc.tar.bz2
mpv-80c03b49bfbcc2567aeca39b7bba7c06d5bbb4dc.tar.xz
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
-rw-r--r--osdep/subprocess-posix.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/osdep/subprocess-posix.c b/osdep/subprocess-posix.c
index bae0ca2c78..013ca143ed 100644
--- a/osdep/subprocess-posix.c
+++ b/osdep/subprocess-posix.c
@@ -33,6 +33,12 @@
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)
// 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;
}
+// 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.
// 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,
@@ -96,6 +116,7 @@ static pid_t spawn_process(const char *path, struct mp_subprocess_opts *opts,
}
if (fres == 0) {
// child
+ reset_signals_child();
for (int n = 0; n < opts->num_fds; n++) {
if (src_fds[n] == opts->fds[n].fd) {