From e374439f4b8def786031ddbbd7dfdae3a335d4d2 Mon Sep 17 00:00:00 2001 From: Kai Lueke Date: Mon, 15 Aug 2022 17:47:03 +0200 Subject: [PATCH] Use original filename for extension name check The loading of an extension image from a symlink "NAME.raw" to "NAME-VERSION.raw" failed because the release file name check worked with the backing file of the loop device which already resolves the symlink and thus the found name "NAME-VERSION" mismatched "NAME". Pass the original filename and use it instead of the backing file when available. This fixes the loading of "NAME.raw" extensions which are a symlink to "NAME-VERSION.raw" as, e.g., may be the case when systemd-sysupdate manages multiple versions. Fixes https://github.com/systemd/systemd/issues/24293 --- src/core/namespace.c | 1 + src/gpt-auto-generator/gpt-auto-generator.c | 1 + src/portable/portable.c | 1 + src/shared/discover-image.c | 1 + src/shared/dissect-image.c | 25 +++++++++++++++++---- src/shared/dissect-image.h | 6 ++--- src/test/test-loop-block.c | 12 +++++++--- test/units/testsuite-50.sh | 5 +++++ 8 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/core/namespace.c b/src/core/namespace.c index 468b27905e7..3fbf0948517 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -2065,6 +2065,7 @@ int setup_namespace( r = dissect_loop_device( loop_device, + root_image, &verity, root_image_options, dissect_image_flags, diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index bd16ae333c9..baa72e77baf 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -710,6 +710,7 @@ static int enumerate_partitions(dev_t devnum) { r = dissect_image( fd, + NULL, NULL, NULL, /* diskseq= */ 0, UINT64_MAX, diff --git a/src/portable/portable.c b/src/portable/portable.c index 5d0a965db5f..9ac34ced6d8 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -367,6 +367,7 @@ static int portable_extract_by_path( r = dissect_loop_device( d, + path, NULL, NULL, DISSECT_IMAGE_READ_ONLY | DISSECT_IMAGE_GENERIC_ROOT | diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c index b3b59fc0bb4..6ddb279f0d3 100644 --- a/src/shared/discover-image.c +++ b/src/shared/discover-image.c @@ -1198,6 +1198,7 @@ int image_read_metadata(Image *i) { r = dissect_loop_device( d, + i->path, NULL, NULL, DISSECT_IMAGE_GENERIC_ROOT | DISSECT_IMAGE_REQUIRE_ROOT | diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 5ede8923fae..dc7cf817f3a 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -193,6 +193,7 @@ static int make_partition_devname( int dissect_image( int fd, + const char *original_path, const VeritySettings *verity, const MountOptions *mount_options, uint64_t diskseq, @@ -307,15 +308,29 @@ int dissect_image( r = sd_device_get_sysname(d, &sysname); if (r < 0) return log_debug_errno(r, "Failed to get device sysname: %m"); - if (startswith(sysname, "loop")) { - _cleanup_free_ char *name_stripped = NULL; + if (original_path) { + _cleanup_free_ char *extracted_filename = NULL, *name_stripped = NULL; + r = path_extract_filename(original_path, &extracted_filename); + if (r < 0) + return r; + r = raw_strip_suffixes(extracted_filename, &name_stripped); + if (r < 0) + return r; + + free_and_replace(m->image_name, name_stripped); + } else if (startswith(sysname, "loop")) { + _cleanup_free_ char *extracted_filename = NULL, *name_stripped = NULL; const char *full_path; + /* Note that the backing_file reference resolves symlinks, while for sysext images we want the original path */ r = sd_device_get_sysattr_value(d, "loop/backing_file", &full_path); if (r < 0) log_debug_errno(r, "Failed to lookup image name via loop device backing file sysattr, ignoring: %m"); else { - r = raw_strip_suffixes(basename(full_path), &name_stripped); + r = path_extract_filename(full_path, &extracted_filename); + if (r < 0) + return r; + r = raw_strip_suffixes(extracted_filename, &name_stripped); if (r < 0) return r; } @@ -2812,7 +2827,7 @@ int dissect_loop_device_and_warn( if (!name) name = ASSERT_PTR(loop->node); - r = dissect_loop_device(loop, verity, mount_options, flags, ret); + r = dissect_loop_device(loop, name, verity, mount_options, flags, ret); switch (r) { case -EOPNOTSUPP: @@ -3078,6 +3093,7 @@ int verity_dissect_and_mount( r = dissect_loop_device( loop_device, + src, &verity, options, dissect_image_flags, @@ -3086,6 +3102,7 @@ int verity_dissect_and_mount( if (!verity.data_path && r == -ENOPKG) r = dissect_loop_device( loop_device, + src, &verity, options, dissect_image_flags | DISSECT_IMAGE_NO_PARTITION_TABLE, diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index 2e71fda8b44..cc0cf661808 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -253,10 +253,10 @@ 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, uint64_t diskseq, uint64_t uevent_seqnum_not_before, usec_t timestamp_not_before, DissectImageFlags flags, DissectedImage **ret); -static inline int dissect_loop_device(const LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret) { +int dissect_image(int fd, const char *original_path, const VeritySettings *verity, const MountOptions *mount_options, uint64_t diskseq, uint64_t uevent_seqnum_not_before, usec_t timestamp_not_before, DissectImageFlags flags, DissectedImage **ret); +static inline int dissect_loop_device(const LoopDevice *loop, const char *original_path, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret) { assert(loop); - return dissect_image(loop->fd, verity, mount_options, loop->diskseq, loop->uevent_seqnum_not_before, loop->timestamp_not_before, flags, ret); + return dissect_image(loop->fd, original_path, verity, mount_options, loop->diskseq, loop->uevent_seqnum_not_before, loop->timestamp_not_before, flags, ret); } int dissect_loop_device_and_warn(const char *name, const LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret); diff --git a/src/test/test-loop-block.c b/src/test/test-loop-block.c index effd6535af9..143e5a61e07 100644 --- a/src/test/test-loop-block.c +++ b/src/test/test-loop-block.c @@ -39,6 +39,7 @@ static void* thread_func(void *ptr) { _cleanup_(loop_device_unrefp) LoopDevice *loop = NULL; _cleanup_(umount_and_rmdir_and_freep) char *mounted = NULL; _cleanup_(dissected_image_unrefp) DissectedImage *dissected = NULL; + _cleanup_free_ char *path = NULL; if (now(CLOCK_MONOTONIC) >= end) { log_notice("Time's up, exiting thread's loop"); @@ -56,7 +57,12 @@ static void* thread_func(void *ptr) { log_notice("Acquired loop device %s, will mount on %s", loop->node, mounted); - r = dissect_loop_device(loop, NULL, NULL, DISSECT_IMAGE_READ_ONLY, &dissected); + r = fd_get_path(fd, &path); + if (r < 0) + log_error_errno(r, "Failed to get path from fd: %m"); + assert_se(r >= 0); + + r = dissect_loop_device(loop, path, NULL, NULL, DISSECT_IMAGE_READ_ONLY, &dissected); if (r < 0) log_error_errno(r, "Failed dissect loopback device %s: %m", loop->node); assert_se(r >= 0); @@ -220,7 +226,7 @@ static int run(int argc, char *argv[]) { pthread_t threads[arg_n_threads]; sd_id128_t id; - assert_se(dissect_loop_device(loop, NULL, NULL, 0, &dissected) >= 0); + assert_se(dissect_loop_device(loop, p, NULL, NULL, 0, &dissected) >= 0); assert_se(dissected->partitions[PARTITION_ESP].found); assert_se(dissected->partitions[PARTITION_ESP].node); @@ -244,7 +250,7 @@ static int run(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_loop_device(loop, NULL, NULL, 0, &dissected) >= 0); + assert_se(dissect_loop_device(loop, p, NULL, NULL, 0, &dissected) >= 0); assert_se(mkdtemp_malloc(NULL, &mounted) >= 0); diff --git a/test/units/testsuite-50.sh b/test/units/testsuite-50.sh index e4204fcdc2a..db39149eb27 100755 --- a/test/units/testsuite-50.sh +++ b/test/units/testsuite-50.sh @@ -318,6 +318,11 @@ systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.r systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /opt/script1.sh | grep -q -F "extension-release.app2" systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1" systemd-run -P --property ExtensionImages=/usr/share/app-nodistro.raw --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" +# Check that using a symlink to NAME-VERSION.raw works as long as the symlink has the correct name NAME.raw +mkdir -p /usr/share/symlink-test/ +cp /usr/share/app-nodistro.raw /usr/share/symlink-test/app-nodistro-v1.raw +ln -fs /usr/share/symlink-test/app-nodistro-v1.raw /usr/share/symlink-test/app-nodistro.raw +systemd-run -P --property ExtensionImages=/usr/share/symlink-test/app-nodistro.raw --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" cat >/run/systemd/system/testservice-50e.service <