923a60
From 175c446fc5ca6adbeeb25dfe0ef725e2f1914259 Mon Sep 17 00:00:00 2001
923a60
From: Tom Gundersen <teg@jklm.no>
923a60
Date: Mon, 9 Mar 2015 16:16:23 +0100
923a60
Subject: [PATCH] udevd: close race in udev settle
923a60
923a60
The udev-settle guarantees that udevd is no longer processing any of the
923a60
events casued by udev-trigger. The way this works is that it sends a
923a60
synchronous PING to udevd after udev-trigger has ran, and when that returns
923a60
it knows that udevd has started processing the events from udev-trigger.
923a60
udev-settle will then wait for the event queue to empty before returning.
923a60
923a60
However, there was a race here, as we would only update the /run state at
923a60
the beginning of the event loop, before reading out new events and before
923a60
processing the ping.
923a60
923a60
That means that if the first uevent arrived in the same event-loop iteration
923a60
as the PING, we would return the ping before updating the queue state in /run
923a60
(which would happen on the next iteration).
923a60
923a60
The race window here is tiny (as the /run state would probably get updated
923a60
before udev-settle got a chance to read /run), but still a possibility.
923a60
923a60
Fix the problem by updating the /run state as the last step before returning
923a60
the PING.
923a60
923a60
We must still update it at the beginning of the loop as well, otherwise we
923a60
risk being stuck in poll() with a stale state in /run.
923a60
923a60
Reported-by: Daniel Drake <drake@endlessm.com>
923a60
(cherry picked from commit db93e063bdffe0a8b95fcc522aeacddf62d1a9f9)
923a60
---
923a60
 src/udev/udevd.c | 26 +++++++++++++++++---------
923a60
 1 file changed, 17 insertions(+), 9 deletions(-)
923a60
923a60
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
923a60
index 99d4c8983a..e98c1fd6da 100644
923a60
--- a/src/udev/udevd.c
923a60
+++ b/src/udev/udevd.c
923a60
@@ -909,6 +909,17 @@ static void handle_signal(struct udev *udev, int signo) {
923a60
         }
923a60
 }
923a60
 
923a60
+static void event_queue_update(void) {
923a60
+        if (!udev_list_node_is_empty(&event_list)) {
923a60
+                int fd;
923a60
+
923a60
+                fd = open("/run/udev/queue", O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
923a60
+                if (fd >= 0)
923a60
+                       close(fd);
923a60
+        } else
923a60
+                unlink("/run/udev/queue");
923a60
+}
923a60
+
923a60
 static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink) {
923a60
         int ctrl = -1, netlink = -1;
923a60
         int fd, n;
923a60
@@ -1369,15 +1380,7 @@ int main(int argc, char *argv[]) {
923a60
                 }
923a60
 
923a60
                 /* tell settle that we are busy or idle */
923a60
-                if (!udev_list_node_is_empty(&event_list)) {
923a60
-                        int fd;
923a60
-
923a60
-                        fd = open("/run/udev/queue", O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
923a60
-                        if (fd >= 0)
923a60
-                                close(fd);
923a60
-                } else {
923a60
-                        unlink("/run/udev/queue");
923a60
-                }
923a60
+                event_queue_update();
923a60
 
923a60
                 fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), timeout);
923a60
                 if (fdcount < 0)
923a60
@@ -1502,6 +1505,11 @@ int main(int argc, char *argv[]) {
923a60
                 if (is_inotify)
923a60
                         handle_inotify(udev);
923a60
 
923a60
+                /* tell settle that we are busy or idle, this needs to be before the
923a60
+                 * PING handling
923a60
+                 */
923a60
+                event_queue_update();
923a60
+
923a60
                 /*
923a60
                  * This needs to be after the inotify handling, to make sure,
923a60
                  * that the ping is send back after the possibly generated