Merge pull request #18018 from bluca/mount_images_overlay
Add ExtensionImages directive to form overlays
This commit is contained in:
@@ -1766,6 +1766,110 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (streq(field, "ExtensionImages")) {
|
||||
const char *p = eq;
|
||||
|
||||
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *source = NULL, *tuple = NULL;
|
||||
const char *q = NULL, *s = NULL;
|
||||
bool permissive = false;
|
||||
|
||||
r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
q = tuple;
|
||||
r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
s = source;
|
||||
if (s[0] == '-') {
|
||||
permissive = true;
|
||||
s++;
|
||||
}
|
||||
|
||||
r = sd_bus_message_open_container(m, 'r', "sba(ss)");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(m, "sb", s, permissive);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "(ss)");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *partition = NULL, *mount_options = NULL;
|
||||
|
||||
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
/* Single set of options, applying to the root partition/single filesystem */
|
||||
if (r == 1) {
|
||||
r = sd_bus_message_append(m, "(ss)", "root", partition);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (partition_designator_from_string(partition) < 0)
|
||||
return bus_log_create_error(-EINVAL);
|
||||
|
||||
r = sd_bus_message_append(m, "(ss)", partition, mount_options);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "dissect-image.h"
|
||||
#include "dm-util.h"
|
||||
#include "env-file.h"
|
||||
#include "extension-release.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
@@ -2621,7 +2622,14 @@ static const char *const partition_designator_table[] = {
|
||||
[PARTITION_VAR] = "var",
|
||||
};
|
||||
|
||||
int verity_dissect_and_mount(const char *src, const char *dest, const MountOptions *options) {
|
||||
int verity_dissect_and_mount(
|
||||
const char *src,
|
||||
const char *dest,
|
||||
const MountOptions *options,
|
||||
const char *required_host_os_release_id,
|
||||
const char *required_host_os_release_version_id,
|
||||
const char *required_host_os_release_sysext_level) {
|
||||
|
||||
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
|
||||
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
||||
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
||||
@@ -2683,6 +2691,30 @@ int verity_dissect_and_mount(const char *src, const char *dest, const MountOptio
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to mount image: %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
|
||||
* available, or else fallback to VERSION_ID. */
|
||||
if (required_host_os_release_id &&
|
||||
(required_host_os_release_version_id || required_host_os_release_sysext_level)) {
|
||||
_cleanup_strv_free_ char **extension_release = NULL;
|
||||
|
||||
r = load_extension_release_pairs(dest, dissected_image->image_name, &extension_release);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse image %s extension-release metadata: %m", dissected_image->image_name);
|
||||
|
||||
r = extension_release_validate(
|
||||
dissected_image->image_name,
|
||||
required_host_os_release_id,
|
||||
required_host_os_release_version_id,
|
||||
required_host_os_release_sysext_level,
|
||||
extension_release);
|
||||
if (r == 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "Image %s extension-release metadata does not match the root's", dissected_image->image_name);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to compare image %s extension-release metadata with the root's os-release: %m", dissected_image->image_name);
|
||||
}
|
||||
|
||||
if (decrypted_image) {
|
||||
r = decrypted_image_relinquish(decrypted_image);
|
||||
if (r < 0)
|
||||
|
||||
@@ -164,4 +164,4 @@ bool dissected_image_has_verity(const DissectedImage *image, PartitionDesignator
|
||||
|
||||
int mount_image_privately_interactively(const char *path, DissectImageFlags flags, char **ret_directory, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image);
|
||||
|
||||
int verity_dissect_and_mount(const char *src, const char *dest, const MountOptions *options);
|
||||
int verity_dissect_and_mount(const char *src, const char *dest, const MountOptions *options, const char *required_host_os_release_id, const char *required_host_os_release_version_id, const char *required_host_os_release_sysext_level);
|
||||
|
||||
@@ -77,3 +77,18 @@ int extension_release_validate(
|
||||
log_debug("Version info of extension '%s' matches host.", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse_env_extension_hierarchies(char ***ret_hierarchies) {
|
||||
int r;
|
||||
|
||||
r = getenv_path_list("SYSTEMD_SYSEXT_HIERARCHIES", ret_hierarchies);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse SYSTEMD_SYSEXT_HIERARCHIES environment variable : %m");
|
||||
if (!*ret_hierarchies) {
|
||||
*ret_hierarchies = strv_new("/usr", "/opt");
|
||||
if (!*ret_hierarchies)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,3 +10,6 @@ int extension_release_validate(
|
||||
const char *host_os_release_version_id,
|
||||
const char *host_os_release_sysext_level,
|
||||
char **extension_release);
|
||||
|
||||
/* Parse SYSTEMD_SYSEXT_HIERARCHIES and if not set, return "/usr /opt" */
|
||||
int parse_env_extension_hierarchies(char ***ret_hierarchies);
|
||||
|
||||
@@ -855,7 +855,7 @@ static int mount_in_namespace(
|
||||
mount_tmp_created = true;
|
||||
|
||||
if (is_image)
|
||||
r = verity_dissect_and_mount(chased_src, mount_tmp, options);
|
||||
r = verity_dissect_and_mount(chased_src, mount_tmp, options, NULL, NULL, NULL);
|
||||
else
|
||||
r = mount_follow_verbose(LOG_DEBUG, chased_src, mount_tmp, NULL, MS_BIND, NULL);
|
||||
if (r < 0)
|
||||
|
||||
Reference in New Issue
Block a user