static int pick_image_search_path(
RuntimeScope scope,
ImageClass class,
+ const char *root,
char ***ret) {
int r;
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;
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)
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;
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;
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;
/* 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/"))
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)
(! 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