process: Fix races on fatal signal handling in process_start().
authorBen Pfaff <blp@nicira.com>
Wed, 15 Jul 2009 19:05:04 +0000 (12:05 -0700)
committerBen Pfaff <blp@nicira.com>
Thu, 16 Jul 2009 16:17:06 +0000 (09:17 -0700)
To prevent fatal signals in a child process from causing the parent
process's pidfile, etc. to be deleted, we need to block fatal signals
around fork and call fatal_signal_fork() in the child process.

This problem was noticed through code inspection; it has not been observed
in practice.

lib/process.c

index 7b583cac0d33d69b2c7cd123dbff15a3753397f5..cd7cbcfb2e1762ae82780eb551a1899e8e109093 100644 (file)
@@ -27,6 +27,7 @@
 #include <unistd.h>
 #include "coverage.h"
 #include "dynamic-string.h"
+#include "fatal-signal.h"
 #include "list.h"
 #include "poll-loop.h"
 #include "socket-util.h"
@@ -51,6 +52,7 @@ static int fds[2];
 /* All processes. */
 static struct list all_processes = LIST_INITIALIZER(&all_processes);
 
+static bool sigchld_is_blocked(void);
 static void block_sigchld(sigset_t *);
 static void unblock_sigchld(const sigset_t *);
 static void sigchld_handler(int signr UNUSED);
@@ -158,8 +160,10 @@ process_start(char **argv,
     free(binary);
 
     block_sigchld(&oldsigs);
+    fatal_signal_block();
     pid = fork();
     if (pid < 0) {
+        fatal_signal_unblock();
         unblock_sigchld(&oldsigs);
         VLOG_WARN("fork failed: %s", strerror(errno));
         return errno;
@@ -176,6 +180,7 @@ process_start(char **argv,
 
         list_push_back(&all_processes, &p->node);
         unblock_sigchld(&oldsigs);
+        fatal_signal_unblock();
 
         *pp = p;
         return 0;
@@ -184,6 +189,8 @@ process_start(char **argv,
         int fd_max = get_max_fds();
         int fd;
 
+        fatal_signal_fork();
+        fatal_signal_unblock();
         unblock_sigchld(&oldsigs);
         for (fd = 0; fd < fd_max; fd++) {
             if (is_member(fd, null_fds, n_null_fds)) {