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