Blame 0035-mount-Fix-race-in-loop-device-reuse-code.patch

Karel Zak 0f3035
From 99e5203da4bb8c4470f0c865add67b8151405bbc Mon Sep 17 00:00:00 2001
Karel Zak 0f3035
From: Jan Kara <jack@suse.cz>
Karel Zak 0f3035
Date: Thu, 20 Jan 2022 12:47:05 +0100
Karel Zak 0f3035
Subject: mount: Fix race in loop device reuse code
Karel Zak 0f3035
Karel Zak 0f3035
Small timing changes in the kernel loop device handling broke the
Karel Zak 0f3035
following loop:
Karel Zak 0f3035
Karel Zak 0f3035
while :; do mount -o loop,ro isofs.iso isofs/; umount isofs/; done
Karel Zak 0f3035
Karel Zak 0f3035
which quickly reports:
Karel Zak 0f3035
mount: /mnt: can't read superblock on /dev/loop0.
Karel Zak 0f3035
umount: /mnt: not mounted.
Karel Zak 0f3035
Karel Zak 0f3035
And this loop is broken because of a subtle interaction with
Karel Zak 0f3035
systemd-udevd that also opens the loop device. The race seems to be in
Karel Zak 0f3035
mount(8) handling itself and the altered kernel timing makes it happen.
Karel Zak 0f3035
It look like:
Karel Zak 0f3035
Karel Zak 0f3035
bash                                systemd-udevd
Karel Zak 0f3035
  mount -o loop,ro isofs.iso isofs/
Karel Zak 0f3035
    /dev/loop0 is created and bound to isofs.iso, autoclear is set for
Karel Zak 0f3035
    loop0
Karel Zak 0f3035
                                    opens /dev/loop0
Karel Zak 0f3035
  umount isofs/
Karel Zak 0f3035
  loop0 still lives because systemd-udev still has device open
Karel Zak 0f3035
  mount -o loop,ro isofs.iso isofs/
Karel Zak 0f3035
    gets to mnt_context_setup_loopdev()
Karel Zak 0f3035
      loopcxt_find_overlap()
Karel Zak 0f3035
      sees loop0 is still valid and with proper parameters
Karel Zak 0f3035
      reuse = true;
Karel Zak 0f3035
                                    close /dev/loop0
Karel Zak 0f3035
                                      last fd closed => loop0 is
Karel Zak 0f3035
                                        cleaned up
Karel Zak 0f3035
      loopcxt_get_fd()
Karel Zak 0f3035
        opens loop0 but it is no longer the device we wanted!
Karel Zak 0f3035
    calls mount(2) which fails because we cannot read from the loop device
Karel Zak 0f3035
Karel Zak 0f3035
Fix the problem by rechecking that loop device is still attached after
Karel Zak 0f3035
opening the device. This makes sure the kernel will not autoclear the
Karel Zak 0f3035
device anymore.
Karel Zak 0f3035
Karel Zak 0f3035
Addresses: https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=2117203
Karel Zak 0f3035
Signed-off-by: Jan Kara <jack@suse.cz>
Karel Zak 0f3035
---
Karel Zak 0f3035
 libmount/src/context_loopdev.c | 19 +++++++++++++++++++
Karel Zak 0f3035
 1 file changed, 19 insertions(+)
Karel Zak 0f3035
Karel Zak 0f3035
diff --git a/libmount/src/context_loopdev.c b/libmount/src/context_loopdev.c
Karel Zak 0f3035
index 6462bfb62..73bcc01c1 100644
Karel Zak 0f3035
--- a/libmount/src/context_loopdev.c
Karel Zak 0f3035
+++ b/libmount/src/context_loopdev.c
Karel Zak 0f3035
@@ -255,6 +255,25 @@ int mnt_context_setup_loopdev(struct libmnt_context *cxt)
Karel Zak 0f3035
 			DBG(LOOP, ul_debugobj(cxt, "re-using existing loop device %s",
Karel Zak 0f3035
 				loopcxt_get_device(&lc)));
Karel Zak 0f3035
 
Karel Zak 0f3035
+			/* Open loop device to block device autoclear... */
Karel Zak 0f3035
+			if (loopcxt_get_fd(&lc) < 0) {
Karel Zak 0f3035
+				DBG(LOOP, ul_debugobj(cxt, "failed to get loopdev FD"));
Karel Zak 0f3035
+				rc = -errno;
Karel Zak 0f3035
+				goto done;
Karel Zak 0f3035
+			}
Karel Zak 0f3035
+
Karel Zak 0f3035
+			/*
Karel Zak 0f3035
+			 * Now that we certainly have the loop device open,
Karel Zak 0f3035
+			 * verify the loop device was not autocleared in the
Karel Zak 0f3035
+			 * mean time.
Karel Zak 0f3035
+			 */
Karel Zak 0f3035
+			if (!loopcxt_get_info(&lc)) {
Karel Zak 0f3035
+				DBG(LOOP, ul_debugobj(cxt, "lost race with %s teardown",
Karel Zak 0f3035
+						loopcxt_get_device(&lc)));
Karel Zak 0f3035
+				loopcxt_deinit(&lc);
Karel Zak 0f3035
+				break;
Karel Zak 0f3035
+			}
Karel Zak 0f3035
+
Karel Zak 0f3035
 			/* Once a loop is initialized RO, there is no
Karel Zak 0f3035
 			 * way to change its parameters. */
Karel Zak 0f3035
 			if (loopcxt_is_readonly(&lc)
Karel Zak 0f3035
-- 
Karel Zak 0f3035
2.37.1
Karel Zak 0f3035