2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-21 14:49:41 +00:00

process: block signals while spawning child processes

Between fork() and execvp() calls in the process_start()
function both child and parent processes share the same
file descriptors.  This means that, if a child process
received a signal during this time interval, then it could
potentially write data to a shared file descriptor.

One such example is fatal signal handler, where, if
child process received SIGTERM signal, then it would
write data into pipe.  Then a read event would occur
on the other end of the pipe where parent process is
listening and this would make parent process to incorrectly
believe that it was the one who received SIGTERM.
Also, since parent process never reads data from this
pipe, then this bug would make parent process to consume
100% CPU by immediately waking up from the event loop.

This patch will help to avoid this problem by blocking
signals until child closes all its file descriptors.

Signed-off-by: Ansis Atteka <aatteka@nicira.com>
Reported-by: Suganya Ramachandran <suganyar@vmware.com>
Issue: 1255110
This commit is contained in:
Ansis Atteka
2014-05-23 14:15:28 -07:00
parent 60032110f1
commit 1481a7551d
5 changed files with 43 additions and 2 deletions

View File

@@ -227,6 +227,7 @@ process_start(char **argv, struct process **pp)
#ifndef _WIN32
pid_t pid;
int error;
sigset_t prev_mask;
assert_single_threaded();
@@ -237,14 +238,15 @@ process_start(char **argv, struct process **pp)
return error;
}
fatal_signal_block(&prev_mask);
pid = fork();
if (pid < 0) {
VLOG_WARN("fork failed: %s", ovs_strerror(errno));
return errno;
error = errno;
} else if (pid) {
/* Running in parent process. */
*pp = process_register(argv[0], pid);
return 0;
error = 0;
} else {
/* Running in child process. */
int fd_max = get_max_fds();
@@ -254,11 +256,14 @@ process_start(char **argv, struct process **pp)
for (fd = 3; fd < fd_max; fd++) {
close(fd);
}
xpthread_sigmask(SIG_SETMASK, &prev_mask, NULL);
execvp(argv[0], argv);
fprintf(stderr, "execvp(\"%s\") failed: %s\n",
argv[0], ovs_strerror(errno));
_exit(1);
}
xpthread_sigmask(SIG_SETMASK, &prev_mask, NULL);
return error;
#else
*pp = NULL;
return ENOSYS;