diff options
author | maanyagoenka <maanyagoenka@microsoft.com> | 2023-03-29 20:34:21 +0000 |
---|---|---|
committer | maanyagoenka <maanyagoenka@microsoft.com> | 2023-04-05 21:50:04 +0000 |
commit | 30dfe035eb8a6539f5997a798402d2d5225f8567 (patch) | |
tree | 65ea6bf109a3b66a316ef161df70b569629edcd9 /src | |
parent | b60e0f577740af89516f7c74967d7182637f27af (diff) | |
download | systemd-30dfe035eb8a6539f5997a798402d2d5225f8567.tar.gz |
extension-release: establish compatibility between host file and extension-release file
The release file that accompanies the confext images needs to be
host compatible to be able to be merged into the host /etc/ directory.
This commit checks for version compatibility between the image file and
the host file.
Diffstat (limited to 'src')
-rw-r--r-- | src/core/namespace.c | 5 | ||||
-rw-r--r-- | src/portable/portable.c | 2 | ||||
-rw-r--r-- | src/shared/dissect-image.c | 3 | ||||
-rw-r--r-- | src/shared/extension-util.c | 82 | ||||
-rw-r--r-- | src/shared/extension-util.h | 13 | ||||
-rw-r--r-- | src/sysext/sysext.c | 5 |
6 files changed, 62 insertions, 48 deletions
diff --git a/src/core/namespace.c b/src/core/namespace.c index 531970ee15..a71beeb18b 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -1435,7 +1435,8 @@ static int apply_one_mount( host_os_release_version_id, host_os_release_sysext_level, /* host_sysext_scope */ NULL, /* Leave empty, we need to accept both system and portable */ - extension_release); + extension_release, + IMAGE_SYSEXT); if (r == 0) return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "Directory %s extension-release metadata does not match the root's", extension_name); if (r < 0) @@ -2155,7 +2156,7 @@ int setup_namespace( } if (n_extension_images > 0 || !strv_isempty(extension_directories)) { - r = parse_env_extension_hierarchies(&hierarchies); + r = parse_env_extension_hierarchies(&hierarchies, "SYSTEMD_SYSEXT_HIERARCHIES"); if (r < 0) return r; } diff --git a/src/portable/portable.c b/src/portable/portable.c index 1878157e65..f3fc06f6fd 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -607,7 +607,7 @@ static int extract_image_and_extensions( return r; if (validate_sysext) { - r = extension_release_validate(ext->path, id, version_id, sysext_level, "portable", extension_release); + r = extension_release_validate(ext->path, id, version_id, sysext_level, "portable", extension_release, IMAGE_SYSEXT); if (r == 0) return sd_bus_error_set_errnof(error, SYNTHETIC_ERRNO(ESTALE), "Image %s extension-release metadata does not match the root's", ext->path); if (r < 0) diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 03dcd45e35..a68610b80e 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -3616,7 +3616,8 @@ int verity_dissect_and_mount( required_host_os_release_version_id, required_host_os_release_sysext_level, required_sysext_scope, - extension_release); + extension_release, + IMAGE_SYSEXT); 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) diff --git a/src/shared/extension-util.c b/src/shared/extension-util.c index fa83f6b6fd..43a19bf262 100644 --- a/src/shared/extension-util.c +++ b/src/shared/extension-util.c @@ -13,39 +13,42 @@ int extension_release_validate( const char *name, const char *host_os_release_id, const char *host_os_release_version_id, - const char *host_os_release_sysext_level, - const char *host_sysext_scope, - char **extension_release) { + const char *host_os_extension_release_level, + const char *host_extension_scope, + char **extension_release, + ImageClass image_class) { - const char *extension_release_id = NULL, *extension_release_sysext_level = NULL, *extension_architecture = NULL; + const char *extension_release_id = NULL, *extension_release_level = NULL, *extension_architecture = NULL; + const char *extension_level = image_class == IMAGE_CONFEXT ? "CONFEXT_LEVEL" : "SYSEXT_LEVEL"; + const char *extension_scope = image_class == IMAGE_CONFEXT ? "CONFEXT_SCOPE" : "SYSEXT_SCOPE"; assert(name); assert(!isempty(host_os_release_id)); - /* Now that we can look into the extension image, let's see if the OS version is compatible */ + /* Now that we can look into the extension/confext image, let's see if the OS version is compatible */ if (strv_isempty(extension_release)) { - log_debug("Extension '%s' carries no extension-release data, ignoring extension.", name); + log_debug("Extension '%s' carries no release data, ignoring.", name); return 0; } - if (host_sysext_scope) { - _cleanup_strv_free_ char **extension_sysext_scope_list = NULL; - const char *extension_sysext_scope; + if (host_extension_scope) { + _cleanup_strv_free_ char **scope_list = NULL; + const char *scope; bool valid; - extension_sysext_scope = strv_env_pairs_get(extension_release, "SYSEXT_SCOPE"); - if (extension_sysext_scope) { - extension_sysext_scope_list = strv_split(extension_sysext_scope, WHITESPACE); - if (!extension_sysext_scope_list) + scope = strv_env_pairs_get(extension_release, extension_scope); + if (scope) { + scope_list = strv_split(scope, WHITESPACE); + if (!scope_list) return -ENOMEM; } - /* by default extension are good for attachment in portable service and on the system */ + /* By default extension are good for attachment in portable service and on the system */ valid = strv_contains( - extension_sysext_scope_list ?: STRV_MAKE("system", "portable"), - host_sysext_scope); + scope_list ?: STRV_MAKE("system", "portable"), + host_extension_scope); if (!valid) { - log_debug("Extension '%s' is not suitable for scope %s, ignoring extension.", name, host_sysext_scope); + log_debug("Extension '%s' is not suitable for scope %s, ignoring.", name, host_extension_scope); return 0; } } @@ -54,21 +57,21 @@ int extension_release_validate( * the future we could check if the kernel also supports 32 bit or binfmt has a translator set up for the architecture */ extension_architecture = strv_env_pairs_get(extension_release, "ARCHITECTURE"); if (!isempty(extension_architecture) && !streq(extension_architecture, "_any") && - !streq(architecture_to_string(uname_architecture()), extension_architecture)) { + !streq(architecture_to_string(uname_architecture()), extension_architecture)) { log_debug("Extension '%s' is for architecture '%s', but deployed on top of '%s'.", - name, extension_architecture, architecture_to_string(uname_architecture())); + name, extension_architecture, architecture_to_string(uname_architecture())); return 0; } extension_release_id = strv_env_pairs_get(extension_release, "ID"); if (isempty(extension_release_id)) { - log_debug("Extension '%s' does not contain ID in extension-release but requested to match '%s' or be '_any'", - name, host_os_release_id); + log_debug("Extension '%s' does not contain ID in release file but requested to match '%s' or be '_any'", + name, host_os_release_id); return 0; } - /* A sysext with no host OS dependency (static binaries or scripts) can match - * '_any' host OS, and VERSION_ID or SYSEXT_LEVEL are not required anywhere */ + /* A sysext(or confext) with no host OS dependency (static binaries or scripts) can match + * '_any' host OS, and VERSION_ID or SYSEXT_LEVEL(or CONFEXT_LEVEL) are not required anywhere */ if (streq(extension_release_id, "_any")) { log_debug("Extension '%s' matches '_any' OS.", name); return 1; @@ -81,18 +84,18 @@ int extension_release_validate( } /* Rolling releases do not typically set VERSION_ID (eg: ArchLinux) */ - if (isempty(host_os_release_version_id) && isempty(host_os_release_sysext_level)) { + if (isempty(host_os_release_version_id) && isempty(host_os_extension_release_level)) { log_debug("No version info on the host (rolling release?), but ID in %s matched.", name); return 1; } /* If the extension has a sysext API level declared, then it must match the host API * level. Otherwise, compare OS version as a whole */ - extension_release_sysext_level = strv_env_pairs_get(extension_release, "SYSEXT_LEVEL"); - if (!isempty(host_os_release_sysext_level) && !isempty(extension_release_sysext_level)) { - if (!streq_ptr(host_os_release_sysext_level, extension_release_sysext_level)) { - log_debug("Extension '%s' is for sysext API level '%s', but running on sysext API level '%s'", - name, strna(extension_release_sysext_level), strna(host_os_release_sysext_level)); + extension_release_level = strv_env_pairs_get(extension_release, extension_level); + if (!isempty(host_os_extension_release_level) && !isempty(extension_release_level)) { + if (!streq_ptr(host_os_extension_release_level, extension_release_level)) { + log_debug("Extension '%s' is for API level '%s', but running on API level '%s'", + name, strna(extension_release_level), strna(host_os_extension_release_level)); return 0; } } else if (!isempty(host_os_release_version_id)) { @@ -100,7 +103,7 @@ int extension_release_validate( extension_release_version_id = strv_env_pairs_get(extension_release, "VERSION_ID"); if (isempty(extension_release_version_id)) { - log_debug("Extension '%s' does not contain VERSION_ID in extension-release but requested to match '%s'", + log_debug("Extension '%s' does not contain VERSION_ID in release file but requested to match '%s'", name, strna(host_os_release_version_id)); return 0; } @@ -110,7 +113,7 @@ int extension_release_validate( name, strna(extension_release_version_id), strna(host_os_release_version_id)); return 0; } - } else if (isempty(host_os_release_version_id) && isempty(host_os_release_sysext_level)) { + } else if (isempty(host_os_release_version_id) && isempty(host_os_extension_release_level)) { /* Rolling releases do not typically set VERSION_ID (eg: ArchLinux) */ log_debug("No version info on the host (rolling release?), but ID in %s matched.", name); return 1; @@ -120,16 +123,21 @@ int extension_release_validate( return 1; } -int parse_env_extension_hierarchies(char ***ret_hierarchies) { +int parse_env_extension_hierarchies(char ***ret_hierarchies, const char *hierarchy_env) { _cleanup_free_ char **l = NULL; int r; - r = getenv_path_list("SYSTEMD_SYSEXT_HIERARCHIES", &l); + assert(hierarchy_env); + r = getenv_path_list(hierarchy_env, &l); if (r == -ENXIO) { - /* Default when unset */ - l = strv_new("/usr", "/opt"); - if (!l) - return -ENOMEM; + if (streq(hierarchy_env, "SYSTEMD_CONFEXT_HIERARCHIES")) + /* Default for confext when unset */ + l = strv_new("/etc"); + else if (streq(hierarchy_env, "SYSTEMD_SYSEXT_HIERARCHIES")) + /* Default for sysext when unset */ + l = strv_new("/usr", "/opt"); + else + return -ENXIO; } else if (r < 0) return r; diff --git a/src/shared/extension-util.h b/src/shared/extension-util.h index fba8acaf19..3cad219d51 100644 --- a/src/shared/extension-util.h +++ b/src/shared/extension-util.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include "os-util.h" + /* Given an image name (for logging purposes), a set of os-release values from the host and a key-value pair * vector of extension-release variables, check that the distro and (system extension level or distro * version) match and return 1, and 0 otherwise. */ @@ -8,12 +10,13 @@ int extension_release_validate( const char *name, const char *host_os_release_id, const char *host_os_release_version_id, - const char *host_os_release_sysext_level, - const char *host_sysext_scope, - char **extension_release); + const char *host_os_extension_release_level, + const char *host_extension_scope, + char **extension_release, + ImageClass image_class); -/* Parse SYSTEMD_SYSEXT_HIERARCHIES and if not set, return "/usr /opt" */ -int parse_env_extension_hierarchies(char ***ret_hierarchies); +/* Parse hierarchy variables and if not set, return "/usr /opt" for sysext and "/etc" for confext */ +int parse_env_extension_hierarchies(char ***ret_hierarchies, const char *hierarchy_env); /* Insist that extension images do not overwrite the underlying OS release file (it's fine if they place one * in /etc/os-release, i.e. where things don't matter, as they aren't merged.) */ diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index e7d8e801fc..97cf8ba52e 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -574,7 +574,8 @@ static int merge_subprocess(Hashmap *images, const char *workspace) { host_os_release_version_id, host_os_release_sysext_level, in_initrd() ? "initrd" : "system", - img->extension_release); + img->extension_release, + IMAGE_SYSEXT); if (r < 0) return r; if (r == 0) { @@ -996,7 +997,7 @@ static int run(int argc, char *argv[]) { /* For debugging purposes it might make sense to do this for other hierarchies than /usr/ and * /opt/, but let's make that a hacker/debugging feature, i.e. env var instead of cmdline * switch. */ - r = parse_env_extension_hierarchies(&arg_hierarchies); + r = parse_env_extension_hierarchies(&arg_hierarchies, "SYSTEMD_SYSEXT_HIERARCHIES"); if (r < 0) return log_error_errno(r, "Failed to parse $SYSTEMD_SYSEXT_HIERARCHIES environment variable: %m"); |