aboutsummaryrefslogtreecommitdiff
path: root/lib/process.c
diff options
context:
space:
mode:
authorBen Pfaff <blp@nicira.com>2009-07-15 12:05:04 -0700
committerBen Pfaff <blp@nicira.com>2009-07-16 09:17:06 -0700
commit52dc2ef41b18cc7d4ed2d19f125f19af5eba12b5 (patch)
treea46d821cafda045b3ab26e03ad047ce22dfc977c /lib/process.c
parent8c4c1387fdebb4b650a093340842ce2226e118af (diff)
process: Fix races on fatal signal handling in process_start().
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.
Diffstat (limited to 'lib/process.c')
-rw-r--r--lib/process.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/lib/process.c b/lib/process.c
index 7b583cac..cd7cbcfb 100644
--- a/lib/process.c
+++ b/lib/process.c
@@ -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)) {