Blame SOURCES/0735-udev-check-if-the-spawned-PID-didn-t-exit-after-reap.patch

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