sysext: Check for /etc/initrd-release in given --root= tree (#39473)

This commit is contained in:
Yu Watanabe
2025-11-05 02:51:25 +09:00
committed by GitHub
3 changed files with 51 additions and 9 deletions
+14 -6
View File
@@ -619,6 +619,7 @@ static int image_make(
static int pick_image_search_path(
RuntimeScope scope,
ImageClass class,
const char *root,
char ***ret) {
int r;
@@ -635,11 +636,11 @@ static int pick_image_search_path(
if (scope < 0) {
_cleanup_strv_free_ char **a = NULL, **b = NULL;
r = pick_image_search_path(RUNTIME_SCOPE_USER, class, &a);
r = pick_image_search_path(RUNTIME_SCOPE_USER, class, root, &a);
if (r < 0)
return r;
r = pick_image_search_path(RUNTIME_SCOPE_SYSTEM, class, &b);
r = pick_image_search_path(RUNTIME_SCOPE_SYSTEM, class, root, &b);
if (r < 0)
return r;
@@ -655,8 +656,15 @@ static int pick_image_search_path(
case RUNTIME_SCOPE_SYSTEM: {
const char *ns;
bool is_initrd;
r = chase_and_access("/etc/initrd-release", root, CHASE_PREFIX_ROOT, F_OK, /* ret_path= */ NULL);
if (r < 0 && r != -ENOENT)
return r;
is_initrd = r >= 0;
/* Use the initrd search path if there is one, otherwise use the common one */
ns = in_initrd() && image_search_path_initrd[class] ?
ns = is_initrd && image_search_path_initrd[class] ?
image_search_path_initrd[class] :
image_search_path[class];
if (!ns)
@@ -763,7 +771,7 @@ int image_find(RuntimeScope scope,
return -ENOMEM;
_cleanup_strv_free_ char **search = NULL;
r = pick_image_search_path(scope, class, &search);
r = pick_image_search_path(scope, class, root, &search);
if (r < 0)
return r;
@@ -954,7 +962,7 @@ int image_discover(
assert(images);
_cleanup_strv_free_ char **search = NULL;
r = pick_image_search_path(scope, class, &search);
r = pick_image_search_path(scope, class, root, &search);
if (r < 0)
return r;
@@ -2101,7 +2109,7 @@ bool image_in_search_path(
assert(image);
_cleanup_strv_free_ char **search = NULL;
r = pick_image_search_path(scope, class, &search);
r = pick_image_search_path(scope, class, root, &search);
if (r < 0)
return r;
+11 -3
View File
@@ -1707,9 +1707,11 @@ static const ImagePolicy *pick_image_policy(const Image *img) {
/* If located in /.extra/ in the initrd, then it was placed there by systemd-stub, and was
* picked up from an untrusted ESP. Thus, require a stricter policy by default for them. (For the
* other directories we assume the appropriate level of trust was already established already. */
* other directories we assume the appropriate level of trust was already established.)
* With --root= we default to the regular policy, though. (To change that, the check would need
* to prepend (or cut away) arg_root.) */
if (in_initrd()) {
if (in_initrd() && !arg_root) {
if (path_startswith(img->path, "/.extra/sysext/"))
return &image_policy_sysext_strict;
if (path_startswith(img->path, "/.extra/global_sysext/"))
@@ -1905,13 +1907,19 @@ static int merge_subprocess(
if (force)
log_debug("Force mode enabled, skipping version validation.");
else {
bool is_initrd;
r = chase_and_access("/etc/initrd-release", arg_root, CHASE_PREFIX_ROOT, F_OK, /* ret_path= */ NULL);
if (r < 0 && r != -ENOENT)
return log_error_errno(r, "Failed to check for /etc/initrd-release: %m");
is_initrd = r >= 0;
r = extension_release_validate(
img->name,
host_os_release_id,
host_os_release_id_like,
host_os_release_version_id,
host_os_release_api_level,
in_initrd() ? "initrd" : "system",
is_initrd ? "initrd" : "system",
image_extension_release(img, image_class),
image_class);
if (r < 0)
+26
View File
@@ -1130,10 +1130,13 @@ extension_verify_after_unmerge "$fake_root" "$hierarchy" -h
fake_root=${roots_dir:+"$roots_dir/mutable-directory-with-invalid-permissions"}
hierarchy=/opt
extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy"
extension_data_dir_usr="$fake_root/var/lib/extensions.mutable/usr"
prepare_root "$fake_root" "$hierarchy"
prepare_extension_image "$fake_root" "$hierarchy"
prepare_extension_mutable_dir "$extension_data_dir"
prepend_trap "rm -rf ${extension_data_dir@Q}"
prepend_trap "rm -rf ${extension_data_dir_usr@Q}"
prepare_hierarchy "$fake_root" "$hierarchy"
old_mode=$(stat --format '%#a' "$fake_root$hierarchy")
@@ -1144,6 +1147,29 @@ chmod 0700 "$extension_data_dir"
(! run_systemd_sysext "$fake_root" --mutable=yes merge)
)
( init_trap
: "Check if merging fails in case of --root= being an initrd but the extension is not for it"
# Since this is really about whether --root= gets prepended for the /etc/initrd-release check,
# this also tests the more interesting reverse case that we are in the initrd and prepare
# the mounts for the final system with --root=/sysroot
fake_root=${roots_dir:+"$roots_dir/initrd-env-with-non-initrd-extension"}
hierarchy=/opt
prepare_root "$fake_root" "$hierarchy"
prepare_extension_image "$fake_root" "$hierarchy"
mkdir -p "${fake_root}/etc"
touch "${fake_root}/etc/initrd-release"
prepare_read_only_hierarchy "$fake_root" "$hierarchy"
# Should be a no-op, thus we also don't run unmerge afterwards (otherwise the test is broken)
run_systemd_sysext "$fake_root" merge
if run_systemd_sysext "$fake_root" status --json=pretty | jq -r '.[].extensions' | grep -v '^none$' ; then
echo >&2 "Extension got loaded for an initrd structure passed as --root= while the extension does not declare itself compatible with the initrd scope"
exit 1
fi
rm "${fake_root}/etc/initrd-release"
)
} # End of run_sysext_tests