summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2021-04-20 15:57:29 +0200
committerLennart Poettering <lennart@poettering.net>2021-04-20 17:14:10 +0200
commit75dc190d39bb71428ab0a0e6185af42aef9451a1 (patch)
tree24953f8c3a287cea4f809e32819449eceb97726e
parentloop-util: read kernel's uevent seqnum right before attaching a loopback device (diff)
downloadsystemd-75dc190d39bb71428ab0a0e6185af42aef9451a1.tar.xz
systemd-75dc190d39bb71428ab0a0e6185af42aef9451a1.zip
dissect: ignore old uevents when waiting for loopback partition scan
Let's drop all monitor uevent that were enqueued before we actually started setting up the device. This doesn't fix the race, but it makes the race window smaller: since we cannot determine the uevent seqnum and the loopback attachment atomically, there's a tiny window where uevents might be generated by the device which we mistake for being associated with out use of the loopback device.
-rw-r--r--src/core/namespace.c1
-rw-r--r--src/dissect/dissect.c1
-rw-r--r--src/gpt-auto-generator/gpt-auto-generator.c1
-rw-r--r--src/nspawn/nspawn.c1
-rw-r--r--src/portable/portable.c1
-rw-r--r--src/shared/discover-image.c4
-rw-r--r--src/shared/dissect-image.c29
-rw-r--r--src/shared/dissect-image.h4
-rw-r--r--src/sysext/sysext.c1
-rw-r--r--src/test/test-loop-block.c6
10 files changed, 39 insertions, 10 deletions
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 9f9d47d34a..bffcb5ac86 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -1863,6 +1863,7 @@ int setup_namespace(
loop_device->fd,
&verity,
root_image_options,
+ loop_device->uevent_seqnum_not_before,
dissect_image_flags,
&dissected_image);
if (r < 0)
diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c
index c21d3e47e4..d70f1e791f 100644
--- a/src/dissect/dissect.c
+++ b/src/dissect/dissect.c
@@ -781,6 +781,7 @@ static int run(int argc, char *argv[]) {
arg_image,
&arg_verity_settings,
NULL,
+ d->uevent_seqnum_not_before,
arg_flags,
&m);
if (r < 0)
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index 42549a2cd8..eb80165bbe 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -672,6 +672,7 @@ static int enumerate_partitions(dev_t devnum) {
r = dissect_image(
fd,
NULL, NULL,
+ UINT64_MAX,
DISSECT_IMAGE_GPT_ONLY|
DISSECT_IMAGE_NO_UDEV|
DISSECT_IMAGE_USR_NO_ROOT,
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 164a330207..0701602418 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -5483,6 +5483,7 @@ static int run(int argc, char *argv[]) {
arg_image,
&arg_verity_settings,
NULL,
+ loop->uevent_seqnum_not_before,
dissect_image_flags,
&dissected_image);
if (r == -ENOPKG) {
diff --git a/src/portable/portable.c b/src/portable/portable.c
index e2bce27947..28d884a951 100644
--- a/src/portable/portable.c
+++ b/src/portable/portable.c
@@ -395,6 +395,7 @@ static int portable_extract_by_path(
r = dissect_image(
d->fd,
NULL, NULL,
+ d->uevent_seqnum_not_before,
DISSECT_IMAGE_READ_ONLY |
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c
index 43138e0a6f..c343d08931 100644
--- a/src/shared/discover-image.c
+++ b/src/shared/discover-image.c
@@ -1201,10 +1201,12 @@ int image_read_metadata(Image *i) {
r = dissect_image(
d->fd,
NULL, NULL,
+ d->uevent_seqnum_not_before,
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_RELAX_VAR_CHECK |
- DISSECT_IMAGE_USR_NO_ROOT, &m);
+ DISSECT_IMAGE_USR_NO_ROOT,
+ &m);
if (r < 0)
return r;
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c
index f6971038de..345e1db9a7 100644
--- a/src/shared/dissect-image.c
+++ b/src/shared/dissect-image.c
@@ -260,6 +260,7 @@ struct wait_data {
sd_device *parent_device;
blkid_partition blkidp;
sd_device *found;
+ uint64_t uevent_seqnum_not_before;
};
static inline void wait_data_done(struct wait_data *d) {
@@ -275,6 +276,20 @@ static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device,
if (device_for_action(device, SD_DEVICE_REMOVE))
return 0;
+ if (w->uevent_seqnum_not_before != UINT64_MAX) {
+ uint64_t seqnum;
+
+ r = sd_device_get_seqnum(device, &seqnum);
+ if (r < 0)
+ goto finish;
+
+ if (seqnum <= w->uevent_seqnum_not_before) { /* From an older use of this loop device */
+ log_debug("Dropping event because seqnum too old (%" PRIu64 " <= %" PRIu64 ")",
+ seqnum, w->uevent_seqnum_not_before);
+ return 0;
+ }
+ }
+
r = device_is_partition(device, w->parent_device, w->blkidp);
if (r < 0)
goto finish;
@@ -294,6 +309,7 @@ static int wait_for_partition_device(
sd_device *parent,
blkid_partition pp,
usec_t deadline,
+ uint64_t uevent_seqnum_not_before,
sd_device **ret) {
_cleanup_(sd_event_source_unrefp) sd_event_source *timeout_source = NULL;
@@ -336,6 +352,7 @@ static int wait_for_partition_device(
_cleanup_(wait_data_done) struct wait_data w = {
.parent_device = parent,
.blkidp = pp,
+ .uevent_seqnum_not_before = uevent_seqnum_not_before,
};
r = sd_device_monitor_start(monitor, device_monitor_handler, &w);
@@ -492,6 +509,7 @@ int dissect_image(
int fd,
const VeritySettings *verity,
const MountOptions *mount_options,
+ uint64_t uevent_seqnum_not_before,
DissectImageFlags flags,
DissectedImage **ret) {
@@ -744,7 +762,7 @@ int dissect_image(
if (!pp)
return errno_or_else(EIO);
- r = wait_for_partition_device(d, pp, deadline, &q);
+ r = wait_for_partition_device(d, pp, deadline, uevent_seqnum_not_before, &q);
if (r < 0)
return r;
@@ -2579,6 +2597,7 @@ int dissect_image_and_warn(
const char *name,
const VeritySettings *verity,
const MountOptions *mount_options,
+ uint64_t uevent_seqnum_not_before,
DissectImageFlags flags,
DissectedImage **ret) {
@@ -2593,7 +2612,7 @@ int dissect_image_and_warn(
name = buffer;
}
- r = dissect_image(fd, verity, mount_options, flags, ret);
+ r = dissect_image(fd, verity, mount_options, uevent_seqnum_not_before, flags, ret);
switch (r) {
case -EOPNOTSUPP:
@@ -2701,7 +2720,7 @@ int mount_image_privately_interactively(
if (r < 0)
return log_error_errno(r, "Failed to set up loopback device: %m");
- r = dissect_image_and_warn(d->fd, image, &verity, NULL, flags, &dissected_image);
+ r = dissect_image_and_warn(d->fd, image, &verity, NULL, d->uevent_seqnum_not_before, flags, &dissected_image);
if (r < 0)
return r;
@@ -2792,6 +2811,7 @@ int verity_dissect_and_mount(
loop_device->fd,
&verity,
options,
+ loop_device->uevent_seqnum_not_before,
dissect_image_flags,
&dissected_image);
/* No partition table? Might be a single-filesystem image, try again */
@@ -2800,7 +2820,8 @@ int verity_dissect_and_mount(
loop_device->fd,
&verity,
options,
- dissect_image_flags|DISSECT_IMAGE_NO_PARTITION_TABLE,
+ loop_device->uevent_seqnum_not_before,
+ dissect_image_flags | DISSECT_IMAGE_NO_PARTITION_TABLE,
&dissected_image);
if (r < 0)
return log_debug_errno(r, "Failed to dissect image: %m");
diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h
index d51049e78a..5d0b1d5e65 100644
--- a/src/shared/dissect-image.h
+++ b/src/shared/dissect-image.h
@@ -159,8 +159,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all);
const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator);
int probe_filesystem(const char *node, char **ret_fstype);
-int dissect_image(int fd, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret);
-int dissect_image_and_warn(int fd, const char *name, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret);
+int dissect_image(int fd, const VeritySettings *verity, const MountOptions *mount_options, uint64_t uevent_seqnum_not_before, DissectImageFlags flags, DissectedImage **ret);
+int dissect_image_and_warn(int fd, const char *name, const VeritySettings *verity, const MountOptions *mount_options, uint64_t uevent_seqnum_not_before, DissectImageFlags flags, DissectedImage **ret);
DissectedImage* dissected_image_unref(DissectedImage *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c
index 49ec23d934..c305a30fae 100644
--- a/src/sysext/sysext.c
+++ b/src/sysext/sysext.c
@@ -532,6 +532,7 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
img->path,
&verity_settings,
NULL,
+ d->uevent_seqnum_not_before,
flags,
&m);
if (r < 0)
diff --git a/src/test/test-loop-block.c b/src/test/test-loop-block.c
index 93f2da70e7..cfa999eff7 100644
--- a/src/test/test-loop-block.c
+++ b/src/test/test-loop-block.c
@@ -51,7 +51,7 @@ static void* thread_func(void *ptr) {
log_notice("Acquired loop device %s, will mount on %s", loop->node, mounted);
- r = dissect_image(loop->fd, NULL, NULL, DISSECT_IMAGE_READ_ONLY, &dissected);
+ r = dissect_image(loop->fd, NULL, NULL, loop->uevent_seqnum_not_before, DISSECT_IMAGE_READ_ONLY, &dissected);
if (r < 0)
log_error_errno(r, "Failed dissect loopback device %s: %m", loop->node);
assert_se(r >= 0);
@@ -188,7 +188,7 @@ int main(int argc, char *argv[]) {
sfdisk = NULL;
assert_se(loop_device_make(fd, O_RDWR, 0, UINT64_MAX, LO_FLAGS_PARTSCAN, &loop) >= 0);
- assert_se(dissect_image(loop->fd, NULL, NULL, 0, &dissected) >= 0);
+ assert_se(dissect_image(loop->fd, NULL, NULL, loop->uevent_seqnum_not_before, 0, &dissected) >= 0);
assert_se(dissected->partitions[PARTITION_ESP].found);
assert_se(dissected->partitions[PARTITION_ESP].node);
@@ -212,7 +212,7 @@ int main(int argc, char *argv[]) {
assert_se(make_filesystem(dissected->partitions[PARTITION_HOME].node, "ext4", "home", id, true) >= 0);
dissected = dissected_image_unref(dissected);
- assert_se(dissect_image(loop->fd, NULL, NULL, 0, &dissected) >= 0);
+ assert_se(dissect_image(loop->fd, NULL, NULL, loop->uevent_seqnum_not_before, 0, &dissected) >= 0);
assert_se(mkdtemp_malloc(NULL, &mounted) >= 0);