Pablo Greco 48fc63
From 2d8d8b2d713a3b0c0aad0552608cc2cd13583207 Mon Sep 17 00:00:00 2001
Pablo Greco 48fc63
From: Michal Sekletar <msekleta@redhat.com>
Pablo Greco 48fc63
Date: Fri, 26 Apr 2019 19:20:09 +0200
Pablo Greco 48fc63
Subject: [PATCH] udev: check if the spawned PID didn't exit after reaping
Pablo Greco 48fc63
 unexpected PID
Pablo Greco 48fc63
Pablo Greco 48fc63
We shouldn't just continue after getting SIGCHLD for the unexpected
Pablo Greco 48fc63
process because signal coalescing might have happened. If it actually
Pablo Greco 48fc63
did happen we won't get any more SIGCHLDs on signalfd.
Pablo Greco 48fc63
Pablo Greco 48fc63
Related: #1697909
Pablo Greco 48fc63
---
Pablo Greco 48fc63
 src/udev/udev-event.c | 27 +++++++++++++++++++++++----
Pablo Greco 48fc63
 1 file changed, 23 insertions(+), 4 deletions(-)
Pablo Greco 48fc63
Pablo Greco 48fc63
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
Pablo Greco 48fc63
index 0ba079201c..7fe64f04a4 100644
Pablo Greco 48fc63
--- a/src/udev/udev-event.c
Pablo Greco 48fc63
+++ b/src/udev/udev-event.c
Pablo Greco 48fc63
@@ -597,8 +597,9 @@ static int spawn_wait(struct udev_event *event,
Pablo Greco 48fc63
                 }
Pablo Greco 48fc63
 
Pablo Greco 48fc63
                 if (pfd[0].revents & POLLIN) {
Pablo Greco 48fc63
+                        int child_exited = -1;
Pablo Greco 48fc63
                         struct signalfd_siginfo fdsi;
Pablo Greco 48fc63
-                        int status;
Pablo Greco 48fc63
+                        int status, r;
Pablo Greco 48fc63
                         ssize_t size;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
                         size = read(event->fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
Pablo Greco 48fc63
@@ -612,10 +613,28 @@ static int spawn_wait(struct udev_event *event,
Pablo Greco 48fc63
                         case SIGCHLD:
Pablo Greco 48fc63
                                 if (pid != (pid_t) fdsi.ssi_pid) {
Pablo Greco 48fc63
                                         log_debug("expected SIGCHLD from '%s' ["PID_FMT"] received from unknown process ["PID_FMT"]. Ignoring", cmd, pid, fdsi.ssi_pid);
Pablo Greco 48fc63
-                                        continue;
Pablo Greco 48fc63
+
Pablo Greco 48fc63
+                                        /* We got SIGCHLD from unexpected process. Possibly some library that we use forked off something behind our back.
Pablo Greco 48fc63
+                                           In case the PID we wait for also exited the kernel could coalesce SIGCHLDs and we won't get second SIGCHLD
Pablo Greco 48fc63
+                                           on the signalfd. We can't know if coalescing happened or not, hence we need to call waitpid() in a loop until
Pablo Greco 48fc63
+                                           the PID we care for exits, we if it haven't already. */
Pablo Greco 48fc63
+                                        while (child_exited < 0) {
Pablo Greco 48fc63
+                                                r = waitpid(-1, &status, 0);
Pablo Greco 48fc63
+                                                if (r < 0 && errno == EINTR)
Pablo Greco 48fc63
+                                                        continue;
Pablo Greco 48fc63
+                                                else if (r < 0)
Pablo Greco 48fc63
+                                                        break;
Pablo Greco 48fc63
+                                                else if (r == pid)
Pablo Greco 48fc63
+                                                        child_exited = 0;
Pablo Greco 48fc63
+                                        }
Pablo Greco 48fc63
                                 }
Pablo Greco 48fc63
-                                if (waitpid(pid, &status, WNOHANG) <= 0)
Pablo Greco 48fc63
-                                        break;
Pablo Greco 48fc63
+
Pablo Greco 48fc63
+                                /* We didn't wait for child yet, let's do that now */
Pablo Greco 48fc63
+                                if (child_exited < 0) {
Pablo Greco 48fc63
+                                        if (waitpid(pid, &status, WNOHANG) <= 0)
Pablo Greco 48fc63
+                                                break;
Pablo Greco 48fc63
+                                }
Pablo Greco 48fc63
+
Pablo Greco 48fc63
                                 if (WIFEXITED(status)) {
Pablo Greco 48fc63
                                         log_debug("'%s' ["PID_FMT"] exit with return code %i", cmd, pid, WEXITSTATUS(status));
Pablo Greco 48fc63
                                         if (WEXITSTATUS(status) != 0)