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 <aatt...@nicira.com> Reported-by: Suganya Ramachandran <sugan...@vmware.com> Issue: 1255110 --- lib/process.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/process.c b/lib/process.c index 313f11f..1270ae2 100644 --- a/lib/process.c +++ b/lib/process.c @@ -226,7 +226,8 @@ process_start(char **argv, struct process **pp) { #ifndef _WIN32 pid_t pid; - int error; + int error, error2; + sigset_t block_mask, prev_mask; assert_single_threaded(); @@ -237,14 +238,21 @@ process_start(char **argv, struct process **pp) return error; } + sigfillset(&block_mask); + error = pthread_sigmask(SIG_BLOCK, &block_mask, &prev_mask); + if (error) { + VLOG_ERR("failed to block signals before fork: %s", + ovs_strerror(error)); + return error; + } 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 +262,23 @@ process_start(char **argv, struct process **pp) for (fd = 3; fd < fd_max; fd++) { close(fd); } + error = pthread_sigmask(SIG_SETMASK, &prev_mask, NULL); + if (error) { + fprintf(stderr, "failed to unblock signals for \"%s\": %s\n", + argv[0], ovs_strerror(error)); + _exit(1); + } execvp(argv[0], argv); fprintf(stderr, "execvp(\"%s\") failed: %s\n", argv[0], ovs_strerror(errno)); _exit(1); } + error2 = pthread_sigmask(SIG_SETMASK, &prev_mask, NULL); + if (error2) { + VLOG_FATAL("failed to unblock signals after fork: %s", + ovs_strerror(error2)); + } + return error; #else *pp = NULL; return ENOSYS; -- 1.7.9.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev