|
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 |
|