]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
priv: correctly handle lldpcli exit
authorVincent Bernat <vincent@bernat.im>
Fri, 20 Oct 2017 06:42:01 +0000 (08:42 +0200)
committerVincent Bernat <vincent@bernat.im>
Fri, 20 Oct 2017 09:05:36 +0000 (11:05 +0200)
When lldpcli exits, we must acknowledge its death with
`waitpid()`. There were two missing cases:

 - when lldpcli exits before setting the SIG_CHLD signal
 - when privilege separation was not configured

For the first case, we call the function associated to the signal
ourselves after the signal is configured. This function is idempotent.

For the second case, we setup the SIG_CHLD signal even when privilege
separation is disabled.

Fix #250

src/daemon/priv.c

index 92c68d870b6df2a98fbbe4e55d2596c57e795b2d..2412d80d678062294b27c548b9b50a765f3e185e 100644 (file)
@@ -488,7 +488,9 @@ sig_pass_to_chld(int sig)
        errno = oerrno;
 }
 
-/* if parent gets a SIGCHLD, it will exit */
+/* If priv parent gets a SIGCHLD, it will exit if this is the monitored
+ * process. Other processes (including lldpcli)) are just reaped without
+ * consequences. */
 static void
 sig_chld(int sig)
 {
@@ -496,11 +498,14 @@ sig_chld(int sig)
        int rc = waitpid(monitored, &status, WNOHANG);
        if (rc == 0) {
                while ((rc = waitpid(-1, &status, WNOHANG)) > 0) {
-                       if (rc == monitored) priv_exit_rc_status(rc, status);
+                       if (monitored != -1 && rc == monitored)
+                               priv_exit_rc_status(rc, status);
                }
                return;
        }
-       priv_exit_rc_status(rc, status);
+       if (monitored != -1)
+               /* Monitored process not here anymore */
+               priv_exit_rc_status(rc, status);
 }
 
 /* Initialization */
@@ -599,7 +604,6 @@ priv_init(const char *chrootdir, int ctl, uid_t uid, gid_t gid)
 
 #ifdef ENABLE_PRIVSEP
        gid_t gidset[1];
-        int status;
        /* Spawn off monitor */
        if ((monitored = fork()) < 0)
                fatal("privsep", "unable to fork monitor");
@@ -657,14 +661,17 @@ priv_init(const char *chrootdir, int ctl, uid_t uid, gid_t gid)
                        .sa_flags = SA_RESTART
                };
                sigaction(SIGCHLD, &child, NULL);
-
-                if (waitpid(monitored, &status, WNOHANG) != 0)
-                        /* Child is already dead */
-                        _exit(1);
+               sig_chld(0);    /* Reap already dead children */
                priv_loop(pair[1], 0);
                exit(0);
        }
 #else
+       const struct sigaction child = {
+               .sa_handler = sig_chld,
+               .sa_flags = SA_RESTART
+       };
+       sigaction(SIGCHLD, &child, NULL);
+       sig_chld(0);    /* Reap already dead children */
        log_warnx("priv", "no privilege separation available");
        priv_ping();
 #endif