core: deduplicate identical dm-verity ExtensionImages=

It turns out OverlayFS doesn't handle gracefully when the same source is
specified multiple times in lowerdir= and it fails with ELOOP:

Failed to mount overlay (type overlay) on /run/systemd/mount-rootfs/opt (MS_RDONLY "lowerdir=/run/systemd/unit-extensions/1/opt:/run/systemd/unit-extensions/0/opt:/run/systemd/mount-rootfs/opt"): Too many levels of symbolic links

This happens even if we mount each image in a different internal mount
path, as OverlayFS will resolve it and look for the backing device, which
will be the same device mapper entity, and return a hard error.
This error does not appear if dm-verity is not used, so it is very
confusing for users, and unnecessary.

When mounting ExtensionImages, check if an image is dm-veritied,
and drop duplicates if the root hashes match, to avoid this user-unfriendly
hard error.
This commit is contained in:
Luca Boccassi
2024-06-28 14:37:58 +01:00
parent b268a71069
commit a1a40297db
6 changed files with 85 additions and 14 deletions
+19 -12
View File
@@ -4034,11 +4034,12 @@ int verity_dissect_and_mount(
const char *required_host_os_release_sysext_level,
const char *required_host_os_release_confext_level,
const char *required_sysext_scope,
VeritySettings *verity,
DissectedImage **ret_image) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
_cleanup_(verity_settings_done) VeritySettings verity = VERITY_SETTINGS_DEFAULT;
_cleanup_(verity_settings_done) VeritySettings local_verity = VERITY_SETTINGS_DEFAULT;
DissectImageFlags dissect_image_flags;
bool relax_extension_release_check;
int r;
@@ -4050,13 +4051,19 @@ int verity_dissect_and_mount(
relax_extension_release_check = mount_options_relax_extension_release_checks(options);
/* We might get an FD for the image, but we use the original path to look for the dm-verity files */
r = verity_settings_load(&verity, src, NULL, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to load root hash: %m");
/* We might get an FD for the image, but we use the original path to look for the dm-verity files.
* The caller might also give us a pre-loaded VeritySettings, in which case we just use it. It will
* also be extended, as dissected_image_load_verity_sig_partition() is invoked. */
if (!verity) {
r = verity_settings_load(&local_verity, src, NULL, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to load root hash: %m");
verity = &local_verity;
}
dissect_image_flags =
(verity.data_path ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0) |
(verity->data_path ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0) |
(relax_extension_release_check ? DISSECT_IMAGE_RELAX_EXTENSION_CHECK : 0) |
DISSECT_IMAGE_ADD_PARTITION_DEVICES |
DISSECT_IMAGE_PIN_PARTITION_DEVICES |
@@ -4068,7 +4075,7 @@ int verity_dissect_and_mount(
src_fd >= 0 ? FORMAT_PROC_FD_PATH(src_fd) : src,
/* open_flags= */ -1,
/* sector_size= */ UINT32_MAX,
verity.data_path ? 0 : LO_FLAGS_PARTSCAN,
verity->data_path ? 0 : LO_FLAGS_PARTSCAN,
LOCK_SH,
&loop_device);
if (r < 0)
@@ -4076,16 +4083,16 @@ int verity_dissect_and_mount(
r = dissect_loop_device(
loop_device,
&verity,
verity,
options,
image_policy,
dissect_image_flags,
&dissected_image);
/* No partition table? Might be a single-filesystem image, try again */
if (!verity.data_path && r == -ENOPKG)
if (!verity->data_path && r == -ENOPKG)
r = dissect_loop_device(
loop_device,
&verity,
verity,
options,
image_policy,
dissect_image_flags | DISSECT_IMAGE_NO_PARTITION_TABLE,
@@ -4093,14 +4100,14 @@ int verity_dissect_and_mount(
if (r < 0)
return log_debug_errno(r, "Failed to dissect image: %m");
r = dissected_image_load_verity_sig_partition(dissected_image, loop_device->fd, &verity);
r = dissected_image_load_verity_sig_partition(dissected_image, loop_device->fd, verity);
if (r < 0)
return r;
r = dissected_image_decrypt(
dissected_image,
NULL,
&verity,
verity,
dissect_image_flags);
if (r < 0)
return log_debug_errno(r, "Failed to decrypt dissected image: %m");
+1 -1
View File
@@ -226,7 +226,7 @@ bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesi
int mount_image_privately_interactively(const char *path, const ImagePolicy *image_policy, DissectImageFlags flags, char **ret_directory, int *ret_dir_fd, LoopDevice **ret_loop_device);
int verity_dissect_and_mount(int src_fd, const char *src, const char *dest, const MountOptions *options, const ImagePolicy *image_policy, const char *required_host_os_release_id, const char *required_host_os_release_version_id, const char *required_host_os_release_sysext_level, const char *required_host_os_release_confext_level, const char *required_sysext_scope, DissectedImage **ret_image);
int verity_dissect_and_mount(int src_fd, const char *src, const char *dest, const MountOptions *options, const ImagePolicy *image_policy, const char *required_host_os_release_id, const char *required_host_os_release_version_id, const char *required_host_os_release_sysext_level, const char *required_host_os_release_confext_level, const char *required_sysext_scope, VeritySettings *verity, DissectedImage **ret_image);
int dissect_fstype_ok(const char *fstype);
+2
View File
@@ -941,6 +941,7 @@ static int mount_in_namespace_legacy(
/* required_host_os_release_sysext_level= */ NULL,
/* required_host_os_release_confext_level= */ NULL,
/* required_sysext_scope= */ NULL,
/* verity= */ NULL,
/* ret_image= */ NULL);
else
r = mount_follow_verbose(LOG_DEBUG, FORMAT_PROC_FD_PATH(chased_src_fd), mount_tmp, NULL, MS_BIND, NULL);
@@ -1166,6 +1167,7 @@ static int mount_in_namespace(
/* required_host_os_release_sysext_level= */ NULL,
/* required_host_os_release_confext_level= */ NULL,
/* required_sysext_scope= */ NULL,
/* verity= */ NULL,
&img);
if (r < 0)
return log_debug_errno(