unix: reset signal disposition before execve()

Signal dispositions are inherited by child processes.  Libuv itself
does not touch them (if you don't use uv_signal_start(), that is)
but the embedder might and probably does in the case of SIGPIPE.

Reset the disposition for signals 1-31 to their defaults right before
execve'ing into the new process.

Fixes: https://github.com/nodejs/node/issues/13662
PR-URL: https://github.com/libuv/libuv/pull/1376
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
This commit is contained in:
Ben Noordhuis 2017-06-14 12:15:40 +02:00
parent d0a27baa7d
commit 28eb1d44f5
2 changed files with 26 additions and 0 deletions

View File

@ -282,6 +282,7 @@ static void uv__process_child_init(const uv_process_options_t* options,
int close_fd; int close_fd;
int use_fd; int use_fd;
int fd; int fd;
int n;
if (options->flags & UV_PROCESS_DETACHED) if (options->flags & UV_PROCESS_DETACHED)
setsid(); setsid();
@ -376,6 +377,22 @@ static void uv__process_child_init(const uv_process_options_t* options,
environ = options->env; environ = options->env;
} }
/* Reset signal disposition. Use a hard-coded limit because NSIG
* is not fixed on Linux: it's either 32, 34 or 64, depending on
* whether RT signals are enabled. We are not allowed to touch
* RT signal handlers, glibc uses them internally.
*/
for (n = 1; n < 32; n += 1) {
if (n == SIGKILL || n == SIGSTOP)
continue; /* Can't be changed. */
if (SIG_ERR != signal(n, SIG_DFL))
continue;
uv__write_int(error_fd, -errno);
_exit(127);
}
execvp(options->file, options->args); execvp(options->file, options->args);
uv__write_int(error_fd, -errno); uv__write_int(error_fd, -errno);
_exit(127); _exit(127);

View File

@ -929,9 +929,18 @@ TEST_IMPL(kill) {
init_process_options("spawn_helper4", kill_cb); init_process_options("spawn_helper4", kill_cb);
/* Verify that uv_spawn() resets the signal disposition. */
#ifndef _WIN32
ASSERT(SIG_ERR != signal(SIGTERM, SIG_IGN));
#endif
r = uv_spawn(uv_default_loop(), &process, &options); r = uv_spawn(uv_default_loop(), &process, &options);
ASSERT(r == 0); ASSERT(r == 0);
#ifndef _WIN32
ASSERT(SIG_ERR != signal(SIGTERM, SIG_DFL));
#endif
/* Sending signum == 0 should check if the /* Sending signum == 0 should check if the
* child process is still alive, not kill it. * child process is still alive, not kill it.
*/ */