summaryrefslogtreecommitdiffstats
path: root/src/shared/dissect-image.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2022-04-07 16:09:45 +0200
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-04-10 15:52:29 +0200
commit41bc484906e973f6c91f8398a3ba309b7ee16f5a (patch)
tree57fad1132c0a90f01e527ac948f898ddea9863a4 /src/shared/dissect-image.c
parenttest-loop-block: reenable test on CI (diff)
downloadsystemd-41bc484906e973f6c91f8398a3ba309b7ee16f5a.tar.xz
systemd-41bc484906e973f6c91f8398a3ba309b7ee16f5a.zip
tree-wide: take BSD lock on loopback devices we dissect/mount/operate on
So here's something we should always keep in mind: systemd-udevd actually does *two* things with BSD file locks on block devices: 1. While it probes a device it takes a LOCK_SH lock. Thus everyone else taking a LOCK_EX lock will temporarily block udev from probing devices, which is good when making changes to it. 2. Whenever a device is closed after write (detected via inotify), udevd will issue BLKRRPART (requesting the kernel to reread the partition table). It does this while holding a LOCK_EX lock on the block device. Thus anyone else taking LOCK_SH or LOCK_EX will temporarily block udevd from issuing that ioctl. And that's quite relevant, since the kernel will temporarily flush out all partitions while re-reading the partition table and then create them anew. Thus it is smart to take LOCK_SH when dissecting a block device to ensure that no BLKRRPART is issued in the background, until we mounted the devices.
Diffstat (limited to 'src/shared/dissect-image.c')
-rw-r--r--src/shared/dissect-image.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c
index a84df05e3f..25fed4cf50 100644
--- a/src/shared/dissect-image.c
+++ b/src/shared/dissect-image.c
@@ -2980,6 +2980,11 @@ int mount_image_privately_interactively(
if (r < 0)
return log_error_errno(r, "Failed to set up loopback device for %s: %m", image);
+ /* Make sure udevd doesn't issue BLKRRPART behind our backs */
+ r = loop_device_flock(d, LOCK_SH);
+ if (r < 0)
+ return r;
+
r = dissect_image_and_warn(d->fd, image, &verity, NULL, d->diskseq, d->uevent_seqnum_not_before, d->timestamp_not_before, flags, &dissected_image);
if (r < 0)
return r;
@@ -3006,6 +3011,10 @@ int mount_image_privately_interactively(
if (r < 0)
return r;
+ r = loop_device_flock(d, LOCK_UN);
+ if (r < 0)
+ return r;
+
if (decrypted_image) {
r = decrypted_image_relinquish(decrypted_image);
if (r < 0)
@@ -3086,6 +3095,10 @@ int verity_dissect_and_mount(
if (r < 0)
return log_debug_errno(r, "Failed to create loop device for image: %m");
+ r = loop_device_flock(loop_device, LOCK_SH);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to lock loop device: %m");
+
r = dissect_image(
loop_device->fd,
&verity,
@@ -3133,6 +3146,10 @@ int verity_dissect_and_mount(
if (r < 0)
return log_debug_errno(r, "Failed to mount image: %m");
+ r = loop_device_flock(loop_device, LOCK_UN);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to unlock loopback device: %m");
+
/* If we got os-release values from the caller, then we need to match them with the image's
* extension-release.d/ content. Return -EINVAL if there's any mismatch.
* First, check the distro ID. If that matches, then check the new SYSEXT_LEVEL value if