process: Introduce afterfork()
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 27 Sep 2014 10:10:06 +0000 (11:10 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 8 Oct 2014 17:25:18 +0000 (18:25 +0100)
Rework set_default_signals into afterfork, which does the sigprocmask
too.  This is necessary for processes we fork after
setup_signal_handling(), which otherwise inherit our blocking mask and
non-default handlers.

Call it after each fork() (except the ones we use for daemonising).
As a consequence:
 - hackypar children will die if they get a terminating signal
 - our subprocesses such as `route' and `ifconfig' will inherit
   reasonable signal setups
 - it will be correct to call udp_make_socket during phase RUN
   (previously any authbind would get a strange signal setup)

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
hackypar.c
process.c
secnet.h
udp.c

index eb445b0..abc93c4 100644 (file)
@@ -55,6 +55,7 @@ static HPState start(void)
     }
 
     if (!child) { /* we are the child */
+       afterfork();
        return hp_compute;
     }
 
index b75b9c0..edc87ac 100644 (file)
--- a/process.c
+++ b/process.c
@@ -35,8 +35,6 @@ static struct signotify *sigs=NULL;
 
 static int spw,spr; /* file descriptors for signal notification pipe */
 
-static void set_default_signals(void);
-
 /* Long-lived subprocesses can only be started once we've started
    signal processing so that we can catch SIGCHLD for them and report
    their exit status using the callback function.  We block SIGCHLD
@@ -58,8 +56,7 @@ pid_t makesubproc(process_entry_fn *entry, process_callback_fn *cb,
     p=fork();
     if (p==0) {
        /* Child process */
-       set_default_signals();
-       sigprocmask(SIG_SETMASK,&emptyset,NULL);
+       afterfork();
        entry(est);
        abort();
     } else if (p==-1) {
@@ -155,6 +152,7 @@ int sys_cmd(const char *path, const char *arg, ...)
           if the execvp() fails this seems somewhat pointless, and
           increases the chance of the child process failing before it
           gets to exec(). */
+       afterfork();
        va_start(ap,arg);
        args[0]=(char *)arg; /* program name */
        i=1;
@@ -214,7 +212,7 @@ static void signal_afterpoll(void *st, struct pollfd *fds, int nfds)
     }
 }
 
-static void set_default_signals(void)
+void afterfork(void)
 {
     struct signotify *n;
     sigset_t done;
@@ -229,6 +227,9 @@ static void set_default_signals(void)
            sa.sa_flags=0;
            sigaction(n->signum,&sa,NULL);
        }
+
+    sigemptyset(&emptyset);
+    sigprocmask(SIG_SETMASK,&emptyset,NULL);
 }
 
 static void signal_handler(int signum)
index 3b54def..1bfe8a1 100644 (file)
--- a/secnet.h
+++ b/secnet.h
@@ -59,6 +59,10 @@ extern struct log_if *system_log;
 /* from process.c */
 extern void start_signal_handling(void);
 
+void afterfork(void);
+/* Must be called before exec in every child made after
+   start_signal_handling.  Safe to call in earlier children too. */
+
 /***** CONFIGURATION support *****/
 
 extern bool_t just_check_config; /* If True then we're going to exit after
diff --git a/udp.c b/udp.c
index 30bf73f..8947058 100644 (file)
--- a/udp.c
+++ b/udp.c
@@ -232,6 +232,7 @@ bool_t udp_make_socket(struct udpcommon *uc, struct udpsock *us,
            char *argv[5], addrstr[33], portstr[5];
            const char *addrfam;
            int port;
+           afterfork();
            switch (addr->sa.sa_family) {
            case AF_INET:
                sprintf(addrstr,"%08lX",(long)addr->sin.sin_addr.s_addr);