os-release: add new PORTABLE_PREFIXES= field for declaring valid portable service match prefixes

This commit is contained in:
Lennart Poettering
2021-11-23 22:55:11 +01:00
parent 60c5f7002b
commit 8a129c808a
5 changed files with 154 additions and 44 deletions
+127 -43
View File
@@ -13,6 +13,7 @@
#include "discover-image.h"
#include "dissect-image.h"
#include "env-file.h"
#include "env-util.h"
#include "errno-list.h"
#include "escape.h"
#include "extension-release.h"
@@ -509,20 +510,20 @@ static int extract_image_and_extensions(
OrderedHashmap **ret_extension_images,
PortableMetadata **ret_os_release,
Hashmap **ret_unit_files,
char ***ret_valid_prefixes,
sd_bus_error *error) {
_cleanup_free_ char *id = NULL, *version_id = NULL, *sysext_level = NULL;
_cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
_cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL;
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
_cleanup_strv_free_ char **valid_prefixes = NULL;
_cleanup_(image_unrefp) Image *image = NULL;
Image *ext;
int r;
assert(name_or_path);
assert(matches);
assert(ret_image);
assert(ret_extension_images);
r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image);
if (r < 0)
@@ -553,10 +554,12 @@ static int extract_image_and_extensions(
if (r < 0)
return r;
/* If we are layering extension images on top of a runtime image, check that the os-release and extension-release metadata
* match, otherwise reject it immediately as invalid, or it will fail when the units are started. */
if (validate_sysext) {
/* If we are layering extension images on top of a runtime image, check that the os-release and
* extension-release metadata match, otherwise reject it immediately as invalid, or it will fail when
* the units are started. Also, collect valid portable prefixes if caller requested that. */
if (validate_sysext || ret_valid_prefixes) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *prefixes = NULL;
r = take_fdopen_unlocked(&os_release->fd, "r", &f);
if (r < 0)
@@ -565,9 +568,16 @@ static int extract_image_and_extensions(
r = parse_env_file(f, os_release->name,
"ID", &id,
"VERSION_ID", &version_id,
"SYSEXT_LEVEL", &sysext_level);
"SYSEXT_LEVEL", &sysext_level,
"PORTABLE_PREFIXES", &prefixes);
if (r < 0)
return r;
if (prefixes) {
valid_prefixes = strv_split(prefixes, WHITESPACE);
if (!valid_prefixes)
return -ENOMEM;
}
}
ORDERED_HASHMAP_FOREACH(ext, extension_images) {
@@ -575,6 +585,7 @@ static int extract_image_and_extensions(
_cleanup_hashmap_free_ Hashmap *extra_unit_files = NULL;
_cleanup_strv_free_ char **extension_release = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *e;
r = portable_extract_by_path(ext->path, /* path_is_extension= */ true, matches, &extension_release_meta, &extra_unit_files, error);
if (r < 0)
@@ -584,7 +595,7 @@ static int extract_image_and_extensions(
if (r < 0)
return r;
if (!validate_sysext)
if (!validate_sysext && !ret_valid_prefixes)
continue;
r = take_fdopen_unlocked(&extension_release_meta->fd, "r", &f);
@@ -595,19 +606,40 @@ static int extract_image_and_extensions(
if (r < 0)
return r;
r = extension_release_validate(ext->path, id, version_id, sysext_level, "portable", extension_release);
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)
return sd_bus_error_set_errnof(error, r, "Failed to compare image %s extension-release metadata with the root's os-release: %m", ext->path);
if (validate_sysext) {
r = extension_release_validate(ext->path, id, version_id, sysext_level, "portable", extension_release);
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)
return sd_bus_error_set_errnof(error, r, "Failed to compare image %s extension-release metadata with the root's os-release: %m", ext->path);
}
e = strv_env_pairs_get(extension_release, "PORTABLE_PREFIXES");
if (e) {
_cleanup_strv_free_ char **l = NULL;
l = strv_split(e, WHITESPACE);
if (!l)
return -ENOMEM;
r = strv_extend_strv(&valid_prefixes, l, true);
if (r < 0)
return r;
}
}
*ret_image = TAKE_PTR(image);
*ret_extension_images = TAKE_PTR(extension_images);
strv_sort(valid_prefixes);
if (ret_image)
*ret_image = TAKE_PTR(image);
if (ret_extension_images)
*ret_extension_images = TAKE_PTR(extension_images);
if (ret_os_release)
*ret_os_release = TAKE_PTR(os_release);
if (ret_unit_files)
*ret_unit_files = TAKE_PTR(unit_files);
if (ret_valid_prefixes)
*ret_valid_prefixes = TAKE_PTR(valid_prefixes);
return 0;
}
@@ -618,23 +650,29 @@ int portable_extract(
char **extension_image_paths,
PortableMetadata **ret_os_release,
Hashmap **ret_unit_files,
char ***ret_valid_prefixes,
sd_bus_error *error) {
_cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
_cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL;
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
_cleanup_(strv_freep) char **valid_prefixes = NULL;
_cleanup_(image_unrefp) Image *image = NULL;
int r;
r = extract_image_and_extensions(name_or_path,
matches,
extension_image_paths,
/* validate_sysext= */ false,
&image,
&extension_images,
&os_release,
&unit_files,
error);
assert(name_or_path);
r = extract_image_and_extensions(
name_or_path,
matches,
extension_image_paths,
/* validate_sysext= */ false,
&image,
&extension_images,
&os_release,
&unit_files,
ret_valid_prefixes ? &valid_prefixes : NULL,
error);
if (r < 0)
return r;
@@ -651,8 +689,12 @@ int portable_extract(
isempty(extensions) ? "" : extensions);
}
*ret_os_release = TAKE_PTR(os_release);
*ret_unit_files = TAKE_PTR(unit_files);
if (ret_os_release)
*ret_os_release = TAKE_PTR(os_release);
if (ret_unit_files)
*ret_unit_files = TAKE_PTR(unit_files);
if (ret_valid_prefixes)
*ret_valid_prefixes = TAKE_PTR(valid_prefixes);
return 0;
}
@@ -1211,6 +1253,18 @@ static int install_image_and_extensions_symlinks(
return 0;
}
static bool prefix_matches_compatible(char **matches, char **valid_prefixes) {
char **m;
/* Checks if all 'matches' are included in the list of 'valid_prefixes' */
STRV_FOREACH(m, matches)
if (!strv_contains(valid_prefixes, *m))
return false;
return true;
}
int portable_attach(
sd_bus *bus,
const char *name_or_path,
@@ -1225,33 +1279,63 @@ int portable_attach(
_cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL;
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
_cleanup_(lookup_paths_free) LookupPaths paths = {};
_cleanup_strv_free_ char **valid_prefixes = NULL;
_cleanup_(image_unrefp) Image *image = NULL;
PortableMetadata *item;
int r;
r = extract_image_and_extensions(name_or_path,
matches,
extension_image_paths,
/* validate_sysext= */ true,
&image,
&extension_images,
/* os_release= */ NULL,
&unit_files,
error);
r = extract_image_and_extensions(
name_or_path,
matches,
extension_image_paths,
/* validate_sysext= */ true,
&image,
&extension_images,
/* os_release= */ NULL,
&unit_files,
&valid_prefixes,
error);
if (r < 0)
return r;
if (hashmap_isempty(unit_files)) {
_cleanup_free_ char *extensions = strv_join(extension_image_paths, ", ");
if (!extensions)
if (valid_prefixes && !prefix_matches_compatible(matches, valid_prefixes)) {
_cleanup_free_ char *matches_joined = NULL, *extensions_joined = NULL, *valid_prefixes_joined = NULL;
matches_joined = strv_join(matches, "', '");
if (!matches_joined)
return -ENOMEM;
return sd_bus_error_setf(error,
SD_BUS_ERROR_INVALID_ARGS,
"Couldn't find any matching unit files in image '%s%s%s', refusing.",
image->path,
isempty(extensions) ? "" : "' or any of its extensions '",
isempty(extensions) ? "" : extensions);
extensions_joined = strv_join(extension_image_paths, ", ");
if (!extensions_joined)
return -ENOMEM;
valid_prefixes_joined = strv_join(valid_prefixes, ", ");
if (!valid_prefixes_joined)
return -ENOMEM;
return sd_bus_error_setf(
error,
SD_BUS_ERROR_INVALID_ARGS,
"Selected matches '%s' are not compatible with portable service image '%s%s%s', refusing. (Acceptable prefix matches are: %s)",
matches_joined,
image->path,
isempty(extensions_joined) ? "" : "' or any of its extensions '",
strempty(extensions_joined),
valid_prefixes_joined);
}
if (hashmap_isempty(unit_files)) {
_cleanup_free_ char *extensions_joined = strv_join(extension_image_paths, ", ");
if (!extensions_joined)
return -ENOMEM;
return sd_bus_error_setf(
error,
SD_BUS_ERROR_INVALID_ARGS,
"Couldn't find any matching unit files in image '%s%s%s', refusing.",
image->path,
isempty(extensions_joined) ? "" : "' or any of its extensions '",
strempty(extensions_joined));
}
r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL);
+1 -1
View File
@@ -65,7 +65,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(PortableMetadata*, portable_metadata_unref);
int portable_metadata_hashmap_to_sorted_array(Hashmap *unit_files, PortableMetadata ***ret);
int portable_extract(const char *image, char **matches, char **extension_image_paths, PortableMetadata **ret_os_release, Hashmap **ret_unit_files, sd_bus_error *error);
int portable_extract(const char *image, char **matches, char **extension_image_paths, PortableMetadata **ret_os_release, Hashmap **ret_unit_files, char ***ret_valid_prefixes, sd_bus_error *error);
int portable_attach(sd_bus *bus, const char *name_or_path, char **matches, const char *profile, char **extension_images, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error);
int portable_detach(sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error);
+1
View File
@@ -162,6 +162,7 @@ int bus_image_common_get_metadata(
extension_images,
&os_release,
&unit_files,
NULL,
error);
if (r < 0)
return r;