diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 50680e6b37a..05c8b3770e2 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -3167,6 +3167,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s IPCNamespacePath = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s RootImagePolicy = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s MountImagePolicy = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s ExtensionImagePolicy = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s KillMode = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly i KillSignal = ...; @@ -3724,6 +3730,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + + + + + @@ -4380,6 +4392,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + + + + + @@ -5147,6 +5165,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s IPCNamespacePath = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s RootImagePolicy = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s MountImagePolicy = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s ExtensionImagePolicy = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s KillMode = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly i KillSignal = ...; @@ -5718,6 +5742,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + + + + + @@ -6356,6 +6386,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + + + + + @@ -7002,6 +7038,12 @@ node /org/freedesktop/systemd1/unit/home_2emount { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s IPCNamespacePath = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s RootImagePolicy = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s MountImagePolicy = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s ExtensionImagePolicy = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s KillMode = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly i KillSignal = ...; @@ -7501,6 +7543,12 @@ node /org/freedesktop/systemd1/unit/home_2emount { + + + + + + @@ -8057,6 +8105,12 @@ node /org/freedesktop/systemd1/unit/home_2emount { + + + + + + @@ -8830,6 +8884,12 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s IPCNamespacePath = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s RootImagePolicy = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s MountImagePolicy = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s ExtensionImagePolicy = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s KillMode = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly i KillSignal = ...; @@ -9315,6 +9375,12 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { + + + + + + @@ -9857,6 +9923,12 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { + + + + + + diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 0246da4b45d..8bc533b20d8 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -109,6 +109,7 @@ bool arg_quiet = false; char *arg_profile = NULL; bool arg_legend = true; bool arg_table = false; +ImagePolicy *arg_image_policy = NULL; STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep); @@ -117,6 +118,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_image, freep); STATIC_DESTRUCTOR_REGISTER(arg_security_policy, freep); STATIC_DESTRUCTOR_REGISTER(arg_unit, freep); STATIC_DESTRUCTOR_REGISTER(arg_profile, freep); +STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); int acquire_bus(sd_bus **bus, bool *use_full_bus) { int r; @@ -268,6 +270,7 @@ static int help(int argc, char *argv[], void *userdata) { " -q --quiet Do not emit hints\n" " --root=PATH Operate on an alternate filesystem root\n" " --image=PATH Operate on disk image as filesystem root\n" + " --image-policy=POLICY Specify disk image dissection policy\n" "\nSee the %s for details.\n", program_invocation_short_name, ansi_highlight(), @@ -307,6 +310,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_PROFILE, ARG_TABLE, ARG_NO_LEGEND, + ARG_IMAGE_POLICY, }; static const struct option options[] = { @@ -339,6 +343,7 @@ static int parse_argv(int argc, char *argv[]) { { "profile", required_argument, NULL, ARG_PROFILE }, { "table", optional_argument, NULL, ARG_TABLE }, { "no-legend", optional_argument, NULL, ARG_NO_LEGEND }, + { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, {} }; @@ -522,6 +527,18 @@ static int parse_argv(int argc, char *argv[]) { arg_legend = false; break; + case ARG_IMAGE_POLICY: { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + + r = image_policy_from_string(optarg, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", optarg); + + image_policy_free(arg_image_policy); + arg_image_policy = TAKE_PTR(p); + break; + } + case '?': return -EINVAL; @@ -643,6 +660,7 @@ static int run(int argc, char *argv[]) { r = mount_image_privately_interactively( arg_image, + arg_image_policy, DISSECT_IMAGE_GENERIC_ROOT | DISSECT_IMAGE_RELAX_VAR_CHECK | DISSECT_IMAGE_READ_ONLY, diff --git a/src/analyze/analyze.h b/src/analyze/analyze.h index 2f623e32012..84575cd9a9d 100644 --- a/src/analyze/analyze.h +++ b/src/analyze/analyze.h @@ -38,6 +38,7 @@ extern bool arg_quiet; extern char *arg_profile; extern bool arg_legend; extern bool arg_table; +extern ImagePolicy *arg_image_policy; int acquire_bus(sd_bus **bus, bool *use_full_bus); diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 82c7e498ba6..b9d034d5503 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -52,6 +52,7 @@ char *arg_image = NULL; InstallSource arg_install_source = ARG_INSTALL_SOURCE_AUTO; char *arg_efi_boot_option_description = NULL; bool arg_dry_run = false; +ImagePolicy *arg_image_policy = NULL; STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep); STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep); @@ -60,6 +61,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_entry_token, freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_image, freep); STATIC_DESTRUCTOR_REGISTER(arg_efi_boot_option_description, freep); +STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); int acquire_esp( bool unprivileged_mode, @@ -168,6 +170,8 @@ static int help(int argc, char *argv[], void *userdata) { " --boot-path=PATH Path to the $BOOT partition\n" " --root=PATH Operate on an alternate filesystem root\n" " --image=PATH Operate on disk image as filesystem root\n" + " --image-policy=POLICY\n" + " Specify disk image dissection policy\n" " --install-source=auto|image|host\n" " Where to pick files when using --root=/--image=\n" " -p --print-esp-path Print path to the EFI System Partition mount point\n" @@ -218,6 +222,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_ARCH_ALL, ARG_EFI_BOOT_OPTION_DESCRIPTION, ARG_DRY_RUN, + ARG_IMAGE_POLICY, }; static const struct option options[] = { @@ -244,6 +249,7 @@ static int parse_argv(int argc, char *argv[]) { { "all-architectures", no_argument, NULL, ARG_ARCH_ALL }, { "efi-boot-option-description", required_argument, NULL, ARG_EFI_BOOT_OPTION_DESCRIPTION }, { "dry-run", no_argument, NULL, ARG_DRY_RUN }, + { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, {} }; @@ -376,6 +382,18 @@ static int parse_argv(int argc, char *argv[]) { arg_dry_run = true; break; + case ARG_IMAGE_POLICY: { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + + r = image_policy_from_string(optarg, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", optarg); + + image_policy_free(arg_image_policy); + arg_image_policy = TAKE_PTR(p); + break; + } + case '?': return -EINVAL; @@ -478,6 +496,7 @@ static int run(int argc, char *argv[]) { r = mount_image_privately_interactively( arg_image, + arg_image_policy, DISSECT_IMAGE_GENERIC_ROOT | DISSECT_IMAGE_RELAX_VAR_CHECK, &unlink_dir, diff --git a/src/boot/bootctl.h b/src/boot/bootctl.h index c87d43694f8..dd98b959c29 100644 --- a/src/boot/bootctl.h +++ b/src/boot/bootctl.h @@ -4,6 +4,7 @@ #include "sd-id128.h" #include "boot-entry.h" +#include "image-policy.h" #include "json.h" #include "pager.h" @@ -34,6 +35,7 @@ extern char *arg_image; extern InstallSource arg_install_source; extern char *arg_efi_boot_option_description; extern bool arg_dry_run; +extern ImagePolicy *arg_image_policy; static inline const char *arg_dollar_boot_path(void) { /* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */ diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index d5ef796e522..d77842bdabd 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -1156,6 +1156,30 @@ static int bus_property_get_exec_dir_symlink( return sd_bus_message_close_container(reply); } +static int property_get_image_policy( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ImagePolicy **pp = ASSERT_PTR(userdata); + _cleanup_free_ char *s = NULL; + int r; + + assert(bus); + assert(property); + assert(reply); + + r = image_policy_to_string(*pp ?: &image_policy_service, /* simplify= */ true, &s); + if (r < 0) + return r; + + return sd_bus_message_append(reply, "s", s); +} + const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST), @@ -1324,6 +1348,9 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("ProtectHostname", "b", bus_property_get_bool, offsetof(ExecContext, protect_hostname), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("NetworkNamespacePath", "s", NULL, offsetof(ExecContext, network_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("IPCNamespacePath", "s", NULL, offsetof(ExecContext, ipc_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RootImagePolicy", "s", property_get_image_policy, offsetof(ExecContext, root_image_policy), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MountImagePolicy", "s", property_get_image_policy, offsetof(ExecContext, mount_image_policy), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ExtensionImagePolicy", "s", property_get_image_policy, offsetof(ExecContext, extension_image_policy), SD_BUS_VTABLE_PROPERTY_CONST), /* Obsolete/redundant properties: */ SD_BUS_PROPERTY("Capabilities", "s", property_get_empty_string, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), @@ -3900,6 +3927,40 @@ int bus_exec_context_set_transient_property( return 1; + } else if (STR_IN_SET(name, "RootImagePolicy", "MountImagePolicy", "ExtensionImagePolicy")) { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + const char *s; + + r = sd_bus_message_read(message, "s", &s); + if (r < 0) + return r; + + r = image_policy_from_string(s, &p); + if (r < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to parse image policy string: %s", s); + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + _cleanup_free_ char *t = NULL; + ImagePolicy **pp = + streq(name, "RootImagePolicy") ? &c->root_image_policy : + streq(name, "MountImagePolicy") ? &c->mount_image_policy : + &c->extension_image_policy; + + r = image_policy_to_string(p, /* simplify= */ true, &t); + if (r < 0) + return r; + + image_policy_free(*pp); + *pp = TAKE_PTR(p); + + unit_write_settingf( + u, flags, name, + "%s=%s", + name, + t); /* no escaping necessary */ + } + + return 1; } return 0; diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index 0f6e3152330..6041a37e560 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -197,15 +197,23 @@ static int bus_service_method_mount(sd_bus_message *message, void *userdata, sd_ propagate_directory = strjoina("/run/systemd/propagate/", u->id); if (is_image) - r = mount_image_in_namespace(unit_pid, - propagate_directory, - "/run/systemd/incoming/", - src, dest, read_only, make_file_or_directory, options); + r = mount_image_in_namespace( + unit_pid, + propagate_directory, + "/run/systemd/incoming/", + src, dest, + read_only, + make_file_or_directory, + options, + c->mount_image_policy ?: &image_policy_service); else - r = bind_mount_in_namespace(unit_pid, - propagate_directory, - "/run/systemd/incoming/", - src, dest, read_only, make_file_or_directory); + r = bind_mount_in_namespace( + unit_pid, + propagate_directory, + "/run/systemd/incoming/", + src, dest, + read_only, + make_file_or_directory); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to mount %s on %s in unit's namespace: %m", src, dest); diff --git a/src/core/execute.c b/src/core/execute.c index aff07e7b744..cd11683407e 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -3823,36 +3823,43 @@ static int apply_mount_namespace( goto finalize; } - r = setup_namespace(root_dir, root_image, context->root_image_options, - &ns_info, read_write_paths, - needs_sandboxing ? context->read_only_paths : NULL, - needs_sandboxing ? context->inaccessible_paths : NULL, - needs_sandboxing ? context->exec_paths : NULL, - needs_sandboxing ? context->no_exec_paths : NULL, - empty_directories, - symlinks, - bind_mounts, - n_bind_mounts, - context->temporary_filesystems, - context->n_temporary_filesystems, - context->mount_images, - context->n_mount_images, - tmp_dir, - var_tmp_dir, - creds_path, - context->log_namespace, - context->mount_propagation_flag, - context->root_hash, context->root_hash_size, context->root_hash_path, - context->root_hash_sig, context->root_hash_sig_size, context->root_hash_sig_path, - context->root_verity, - context->extension_images, - context->n_extension_images, - context->extension_directories, - propagate_dir, - incoming_dir, - extension_dir, - root_dir || root_image ? params->notify_socket : NULL, - error_path); + r = setup_namespace( + root_dir, + root_image, + context->root_image_options, + context->root_image_policy ?: &image_policy_service, + &ns_info, + read_write_paths, + needs_sandboxing ? context->read_only_paths : NULL, + needs_sandboxing ? context->inaccessible_paths : NULL, + needs_sandboxing ? context->exec_paths : NULL, + needs_sandboxing ? context->no_exec_paths : NULL, + empty_directories, + symlinks, + bind_mounts, + n_bind_mounts, + context->temporary_filesystems, + context->n_temporary_filesystems, + context->mount_images, + context->n_mount_images, + context->mount_image_policy ?: &image_policy_service, + tmp_dir, + var_tmp_dir, + creds_path, + context->log_namespace, + context->mount_propagation_flag, + context->root_hash, context->root_hash_size, context->root_hash_path, + context->root_hash_sig, context->root_hash_sig_size, context->root_hash_sig_path, + context->root_verity, + context->extension_images, + context->n_extension_images, + context->extension_image_policy ?: &image_policy_sysext, + context->extension_directories, + propagate_dir, + incoming_dir, + extension_dir, + root_dir || root_image ? params->notify_socket : NULL, + error_path); /* If we couldn't set up the namespace this is probably due to a missing capability. setup_namespace() reports * that with a special, recognizable error ENOANO. In this case, silently proceed, but only if exclusively @@ -5789,6 +5796,10 @@ void exec_context_done(ExecContext *c) { c->load_credentials = hashmap_free(c->load_credentials); c->set_credentials = hashmap_free(c->set_credentials); + + c->root_image_policy = image_policy_free(c->root_image_policy); + c->mount_image_policy = image_policy_free(c->mount_image_policy); + c->extension_image_policy = image_policy_free(c->extension_image_policy); } int exec_context_destroy_runtime_directory(const ExecContext *c, const char *runtime_prefix) { diff --git a/src/core/execute.h b/src/core/execute.h index 254a1ee2d13..123fc1ec604 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -359,6 +359,8 @@ struct ExecContext { Hashmap *set_credentials; /* output id → ExecSetCredential */ Hashmap *load_credentials; /* output id → ExecLoadCredential */ + + ImagePolicy *root_image_policy, *mount_image_policy, *extension_image_policy; }; static inline bool exec_context_restrict_namespaces_set(const ExecContext *c) { diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in index 50ff57a9f8d..f35c7436550 100644 --- a/src/core/load-fragment-gperf.gperf.in +++ b/src/core/load-fragment-gperf.gperf.in @@ -6,12 +6,15 @@ {{type}}.RootDirectory, config_parse_unit_path_printf, true, offsetof({{type}}, exec_context.root_directory) {{type}}.RootImage, config_parse_unit_path_printf, true, offsetof({{type}}, exec_context.root_image) {{type}}.RootImageOptions, config_parse_root_image_options, 0, offsetof({{type}}, exec_context) +{{type}}.RootImagePolicy, config_parse_image_policy, 0, offsetof({{type}}, exec_context.root_image_policy) {{type}}.RootHash, config_parse_exec_root_hash, 0, offsetof({{type}}, exec_context) {{type}}.RootHashSignature, config_parse_exec_root_hash_sig, 0, offsetof({{type}}, exec_context) {{type}}.RootVerity, config_parse_unit_path_printf, true, offsetof({{type}}, exec_context.root_verity) {{type}}.ExtensionDirectories, config_parse_namespace_path_strv, 0, offsetof({{type}}, exec_context.extension_directories) {{type}}.ExtensionImages, config_parse_extension_images, 0, offsetof({{type}}, exec_context) +{{type}}.ExtensionImagePolicy, config_parse_image_policy, 0, offsetof({{type}}, exec_context.extension_image_policy) {{type}}.MountImages, config_parse_mount_images, 0, offsetof({{type}}, exec_context) +{{type}}.MountImagePolicy, config_parse_image_policy, 0, offsetof({{type}}, exec_context.mount_image_policy) {{type}}.User, config_parse_user_group_compat, 0, offsetof({{type}}, exec_context.user) {{type}}.Group, config_parse_user_group_compat, 0, offsetof({{type}}, exec_context.group) {{type}}.SupplementaryGroups, config_parse_user_group_strv_compat, 0, offsetof({{type}}, exec_context.supplementary_groups) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 533c09f72ea..99d40b74908 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1705,6 +1705,45 @@ int config_parse_root_image_options( return 0; } +int config_parse_image_policy( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_(image_policy_freep) ImagePolicy *np = NULL; + ImagePolicy **p = ASSERT_PTR(data); + int r; + + assert(rvalue); + + if (isempty(rvalue)) { + *p = image_policy_free(*p); + return 0; + } + + r = image_policy_from_string(rvalue, &np); + if (r == -ENOTUNIQ) + return log_syntax(unit, LOG_ERR, filename, line, r, "Duplicate rule in image policy, refusing: %s", rvalue); + if (r == -EBADSLT) + return log_syntax(unit, LOG_ERR, filename, line, r, "Unknown partition type in image policy, refusing: %s", rvalue); + if (r == -EBADRQC) + return log_syntax(unit, LOG_ERR, filename, line, r, "Unknown partition policy flag in image policy, refusing: %s", rvalue); + if (r < 0) + return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse image policy, refusing: %s", rvalue); + + image_policy_free(*p); + *p = TAKE_PTR(np); + + return 0; +} + int config_parse_exec_root_hash( const char *unit, const char *filename, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 91dc9174584..ab682ee23e7 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -52,6 +52,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_affinity); CONFIG_PARSER_PROTOTYPE(config_parse_exec_mount_apivfs); CONFIG_PARSER_PROTOTYPE(config_parse_exec_secure_bits); CONFIG_PARSER_PROTOTYPE(config_parse_root_image_options); +CONFIG_PARSER_PROTOTYPE(config_parse_image_policy); CONFIG_PARSER_PROTOTYPE(config_parse_exec_root_hash); CONFIG_PARSER_PROTOTYPE(config_parse_exec_root_hash_sig); CONFIG_PARSER_PROTOTYPE(config_parse_capability_set); diff --git a/src/core/namespace.c b/src/core/namespace.c index 8b141a24848..2668bca1bb1 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -1240,7 +1240,10 @@ static int mount_mqueuefs(const MountEntry *m) { return 0; } -static int mount_image(const MountEntry *m, const char *root_directory) { +static int mount_image( + const MountEntry *m, + const char *root_directory, + const ImagePolicy *image_policy) { _cleanup_free_ char *host_os_release_id = NULL, *host_os_release_version_id = NULL, *host_os_release_sysext_level = NULL; @@ -1262,8 +1265,15 @@ static int mount_image(const MountEntry *m, const char *root_directory) { } r = verity_dissect_and_mount( - /* src_fd= */ -1, mount_entry_source(m), mount_entry_path(m), m->image_options, - host_os_release_id, host_os_release_version_id, host_os_release_sysext_level, NULL); + /* src_fd= */ -1, + mount_entry_source(m), + mount_entry_path(m), + m->image_options, + image_policy, + host_os_release_id, + host_os_release_version_id, + host_os_release_sysext_level, + NULL); if (r == -ENOENT && m->ignore) return 0; if (r == -ESTALE && host_os_release_id) @@ -1336,6 +1346,8 @@ static int follow_symlink( static int apply_one_mount( const char *root_directory, MountEntry *m, + const ImagePolicy *mount_image_policy, + const ImagePolicy *extension_image_policy, const NamespaceInfo *ns_info) { _cleanup_free_ char *inaccessible = NULL; @@ -1505,10 +1517,10 @@ static int apply_one_mount( return mount_mqueuefs(m); case MOUNT_IMAGES: - return mount_image(m, NULL); + return mount_image(m, NULL, mount_image_policy); case EXTENSION_IMAGES: - return mount_image(m, root_directory); + return mount_image(m, root_directory, extension_image_policy); case OVERLAY_MOUNT: return mount_overlay(m); @@ -1778,6 +1790,8 @@ static int create_symlinks_from_tuples(const char *root, char **strv_symlinks) { static int apply_mounts( const char *root, + const ImagePolicy *mount_image_policy, + const ImagePolicy *extension_image_policy, const NamespaceInfo *ns_info, MountEntry *mounts, size_t *n_mounts, @@ -1832,7 +1846,7 @@ static int apply_mounts( break; } - r = apply_one_mount(root, m, ns_info); + r = apply_one_mount(root, m, mount_image_policy, extension_image_policy, ns_info); if (r < 0) { if (error_path && mount_entry_path(m)) *error_path = strdup(mount_entry_path(m)); @@ -2011,7 +2025,8 @@ static int verity_settings_prepare( int setup_namespace( const char* root_directory, const char* root_image, - const MountOptions *root_image_options, + const MountOptions *root_image_mount_options, + const ImagePolicy *root_image_policy, const NamespaceInfo *ns_info, char** read_write_paths, char** read_only_paths, @@ -2026,6 +2041,7 @@ int setup_namespace( size_t n_temporary_filesystems, const MountImage *mount_images, size_t n_mount_images, + const ImagePolicy *mount_image_policy, const char* tmp_dir, const char* var_tmp_dir, const char *creds_path, @@ -2040,6 +2056,7 @@ int setup_namespace( const char *verity_data_path, const MountImage *extension_images, size_t n_extension_images, + const ImagePolicy *extension_image_policy, char **extension_directories, const char *propagate_dir, const char *incoming_dir, @@ -2113,7 +2130,8 @@ int setup_namespace( r = dissect_loop_device( loop_device, &verity, - root_image_options, + root_image_mount_options, + root_image_policy, dissect_image_flags, &dissected_image); if (r < 0) @@ -2501,7 +2519,7 @@ int setup_namespace( (void) base_filesystem_create(root, UID_INVALID, GID_INVALID); /* Now make the magic happen */ - r = apply_mounts(root, ns_info, mounts, &n_mounts, exec_dir_symlinks, error_path); + r = apply_mounts(root, mount_image_policy, extension_image_policy, ns_info, mounts, &n_mounts, exec_dir_symlinks, error_path); if (r < 0) goto finish; diff --git a/src/core/namespace.h b/src/core/namespace.h index 1cd4fdd9213..39b510f41d9 100644 --- a/src/core/namespace.h +++ b/src/core/namespace.h @@ -103,6 +103,7 @@ int setup_namespace( const char *root_directory, const char *root_image, const MountOptions *root_image_options, + const ImagePolicy *root_image_policy, const NamespaceInfo *ns_info, char **read_write_paths, char **read_only_paths, @@ -117,6 +118,7 @@ int setup_namespace( size_t n_temporary_filesystems, const MountImage *mount_images, size_t n_mount_images, + const ImagePolicy *mount_image_policy, const char *tmp_dir, const char *var_tmp_dir, const char *creds_path, @@ -131,6 +133,7 @@ int setup_namespace( const char *root_verity, const MountImage *extension_images, size_t n_extension_images, + const ImagePolicy *extension_image_policy, char **extension_directories, const char *propagate_dir, const char *incoming_dir, diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index 60da536d4eb..076b35f0987 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -64,9 +64,11 @@ static const char* arg_output = NULL; static bool arg_reverse = false; static bool arg_quiet = false; static bool arg_all = false; +static ImagePolicy *arg_image_policy = NULL; STATIC_DESTRUCTOR_REGISTER(arg_debugger_args, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_file, strv_freep); +STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); static int add_match(sd_journal *j, const char *match) { _cleanup_free_ char *p = NULL; @@ -198,6 +200,7 @@ static int verb_help(int argc, char **argv, void *userdata) { " --all Look at all journal files instead of local ones\n" " --root=PATH Operate on an alternate filesystem root\n" " --image=PATH Operate on disk image as filesystem root\n" + " --image-policy=POLICY Specify disk image dissection policy\n" "\nSee the %2$s for details.\n", program_invocation_short_name, link, @@ -220,29 +223,31 @@ static int parse_argv(int argc, char *argv[]) { ARG_ROOT, ARG_IMAGE, ARG_ALL, + ARG_IMAGE_POLICY, }; int c, r; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version" , no_argument, NULL, ARG_VERSION }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, - { "debugger", required_argument, NULL, ARG_DEBUGGER }, - { "debugger-arguments", required_argument, NULL, 'A' }, - { "output", required_argument, NULL, 'o' }, - { "field", required_argument, NULL, 'F' }, - { "file", required_argument, NULL, ARG_FILE }, - { "directory", required_argument, NULL, 'D' }, - { "reverse", no_argument, NULL, 'r' }, - { "since", required_argument, NULL, 'S' }, - { "until", required_argument, NULL, 'U' }, - { "quiet", no_argument, NULL, 'q' }, - { "json", required_argument, NULL, ARG_JSON }, - { "root", required_argument, NULL, ARG_ROOT }, - { "image", required_argument, NULL, ARG_IMAGE }, - { "all", no_argument, NULL, ARG_ALL }, + { "help", no_argument, NULL, 'h' }, + { "version" , no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, + { "debugger", required_argument, NULL, ARG_DEBUGGER }, + { "debugger-arguments", required_argument, NULL, 'A' }, + { "output", required_argument, NULL, 'o' }, + { "field", required_argument, NULL, 'F' }, + { "file", required_argument, NULL, ARG_FILE }, + { "directory", required_argument, NULL, 'D' }, + { "reverse", no_argument, NULL, 'r' }, + { "since", required_argument, NULL, 'S' }, + { "until", required_argument, NULL, 'U' }, + { "quiet", no_argument, NULL, 'q' }, + { "json", required_argument, NULL, ARG_JSON }, + { "root", required_argument, NULL, ARG_ROOT }, + { "image", required_argument, NULL, ARG_IMAGE }, + { "all", no_argument, NULL, ARG_ALL }, + { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, {} }; @@ -363,6 +368,18 @@ static int parse_argv(int argc, char *argv[]) { arg_all = true; break; + case ARG_IMAGE_POLICY: { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + + r = image_policy_from_string(optarg, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", optarg); + + image_policy_free(arg_image_policy); + arg_image_policy = TAKE_PTR(p); + break; + } + case '?': return -EINVAL; @@ -1361,6 +1378,7 @@ static int run(int argc, char *argv[]) { r = mount_image_privately_interactively( arg_image, + arg_image_policy, DISSECT_IMAGE_GENERIC_ROOT | DISSECT_IMAGE_REQUIRE_ROOT | DISSECT_IMAGE_RELAX_VAR_CHECK | diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index ff00c4f567d..b3f20e193e5 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -83,6 +83,7 @@ static bool arg_rmdir = false; static bool arg_in_memory = false; static char **arg_argv = NULL; static char *arg_loop_ref = NULL; +static ImagePolicy* arg_image_policy = NULL; STATIC_DESTRUCTOR_REGISTER(arg_image, freep); STATIC_DESTRUCTOR_REGISTER(arg_path, freep); @@ -126,6 +127,8 @@ static int help(void) { " 'base64:'\n" " --verity-data=PATH Specify data file with hash tree for verity if it is\n" " not embedded in IMAGE\n" + " --image-policy=POLICY\n" + " Specify image dissection policy\n" " --json=pretty|short|off\n" " Generate JSON output\n" " --loop-ref=NAME Set reference string for loopback device\n" @@ -221,6 +224,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_ATTACH, ARG_DETACH, ARG_LOOP_REF, + ARG_IMAGE_POLICY, }; static const struct option options[] = { @@ -250,6 +254,7 @@ static int parse_argv(int argc, char *argv[]) { { "json", required_argument, NULL, ARG_JSON }, { "discover", no_argument, NULL, ARG_DISCOVER }, { "loop-ref", required_argument, NULL, ARG_LOOP_REF }, + { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, {} }; @@ -457,6 +462,18 @@ static int parse_argv(int argc, char *argv[]) { return r; break; + case ARG_IMAGE_POLICY: { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + + r = image_policy_from_string(optarg, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", optarg); + + image_policy_free(arg_image_policy); + arg_image_policy = TAKE_PTR(p); + break; + } + case '?': return -EINVAL; @@ -1750,7 +1767,8 @@ static int run(int argc, char *argv[]) { r = dissect_loop_device_and_warn( d, &arg_verity_settings, - NULL, + /* mount_options= */ NULL, + arg_image_policy, arg_flags, &m); if (r < 0) diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 3e68ed1cb02..54c72eceaf5 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -73,6 +73,7 @@ static bool arg_delete_root_password = false; static bool arg_root_password_is_hashed = false; static bool arg_welcome = true; static bool arg_reset = false; +static ImagePolicy *arg_image_policy = NULL; STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_image, freep); @@ -82,6 +83,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_keymap, freep); STATIC_DESTRUCTOR_REGISTER(arg_timezone, freep); STATIC_DESTRUCTOR_REGISTER(arg_hostname, freep); STATIC_DESTRUCTOR_REGISTER(arg_root_password, erase_and_freep); +STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); static bool press_any_key(void) { char k = 0; @@ -1145,7 +1147,8 @@ static int help(void) { " -h --help Show this help\n" " --version Show package version\n" " --root=PATH Operate on an alternate filesystem root\n" - " --image=PATH Operate on an alternate filesystem image\n" + " --image=PATH Operate on disk image as filesystem root\n" + " --image-policy=POLICY Specify disk image dissection policy\n" " --locale=LOCALE Set primary locale (LANG=)\n" " --locale-messages=LOCALE Set message locale (LC_MESSAGES=)\n" " --keymap=KEYMAP Set keymap\n" @@ -1216,6 +1219,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_DELETE_ROOT_PASSWORD, ARG_WELCOME, ARG_RESET, + ARG_IMAGE_POLICY, }; static const struct option options[] = { @@ -1252,6 +1256,7 @@ static int parse_argv(int argc, char *argv[]) { { "delete-root-password", no_argument, NULL, ARG_DELETE_ROOT_PASSWORD }, { "welcome", required_argument, NULL, ARG_WELCOME }, { "reset", no_argument, NULL, ARG_RESET }, + { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, {} }; @@ -1458,6 +1463,17 @@ static int parse_argv(int argc, char *argv[]) { arg_reset = true; break; + case ARG_IMAGE_POLICY: { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + + r = image_policy_from_string(optarg, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", optarg); + + image_policy_free(arg_image_policy); + arg_image_policy = TAKE_PTR(p); + break; + } case '?': return -EINVAL; @@ -1518,6 +1534,7 @@ static int run(int argc, char *argv[]) { r = mount_image_privately_interactively( arg_image, + arg_image_policy, DISSECT_IMAGE_GENERIC_ROOT | DISSECT_IMAGE_REQUIRE_ROOT | DISSECT_IMAGE_VALIDATE_OS | diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 9ccd78af658..09c63a31b2f 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -23,6 +23,7 @@ #include "fstab-util.h" #include "generator.h" #include "gpt.h" +#include "image-policy.h" #include "initrd-util.h" #include "mkdir.h" #include "mountpoint-util.h" @@ -43,6 +44,9 @@ static bool arg_root_enabled = true; static char *arg_root_fstype = NULL; static char *arg_root_options = NULL; static int arg_root_rw = -1; +static ImagePolicy *arg_image_policy = NULL; + +STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); STATIC_DESTRUCTOR_REGISTER(arg_root_fstype, freep); STATIC_DESTRUCTOR_REGISTER(arg_root_options, freep); @@ -744,7 +748,9 @@ static int enumerate_partitions(dev_t devnum) { r = dissect_loop_device( loop, - NULL, NULL, + /* verity= */ NULL, + /* mount_options= */ NULL, + arg_image_policy ?: &image_policy_host, DISSECT_IMAGE_GPT_ONLY| DISSECT_IMAGE_USR_NO_ROOT| DISSECT_IMAGE_DISKSEQ_DEVNODE, @@ -882,6 +888,20 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat arg_root_rw = true; else if (proc_cmdline_key_streq(key, "ro") && !value) arg_root_rw = false; + else if (proc_cmdline_key_streq(key, "systemd.image_policy")) { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + + if (proc_cmdline_value_missing(key, value)) + return 0; + + r = image_policy_from_string(value, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", value); + + image_policy_free(arg_image_policy); + arg_image_policy = TAKE_PTR(p); + return 0; + } return 0; } diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 97e9c1aafc4..abacbb03066 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -134,6 +134,7 @@ static Set *arg_output_fields = NULL; static const char *arg_pattern = NULL; static pcre2_code *arg_compiled_pattern = NULL; static PatternCompileCase arg_case = PATTERN_COMPILE_CASE_AUTO; +ImagePolicy *arg_image_policy = NULL; STATIC_DESTRUCTOR_REGISTER(arg_file, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_facilities, set_freep); @@ -145,6 +146,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_image, freep); STATIC_DESTRUCTOR_REGISTER(arg_output_fields, set_freep); STATIC_DESTRUCTOR_REGISTER(arg_compiled_pattern, pattern_freep); +STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); static enum { ACTION_SHOW, @@ -326,8 +328,9 @@ static int help(void) { " -m --merge Show entries from all available journals\n" " -D --directory=PATH Show journal files from directory\n" " --file=PATH Show journal file\n" - " --root=ROOT Operate on files below a root directory\n" - " --image=IMAGE Operate on files in filesystem image\n" + " --root=PATH Operate on an alternate filesystem root\n" + " --image=PATH Operate on disk image as filesystem root\n" + " --image-policy=POLICY Specify disk image dissection policy\n" " --namespace=NAMESPACE Show journal data from specified journal namespace\n" "\n%3$sFiltering Options:%4$s\n" " -S --since=DATE Show entries not older than the specified date\n" @@ -444,6 +447,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_NO_HOSTNAME, ARG_OUTPUT_FIELDS, ARG_NAMESPACE, + ARG_IMAGE_POLICY, }; static const struct option options[] = { @@ -511,6 +515,7 @@ static int parse_argv(int argc, char *argv[]) { { "no-hostname", no_argument, NULL, ARG_NO_HOSTNAME }, { "output-fields", required_argument, NULL, ARG_OUTPUT_FIELDS }, { "namespace", required_argument, NULL, ARG_NAMESPACE }, + { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, {} }; @@ -1033,7 +1038,17 @@ static int parse_argv(int argc, char *argv[]) { break; } + case ARG_IMAGE_POLICY: { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + r = image_policy_from_string(optarg, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", optarg); + + image_policy_free(arg_image_policy); + arg_image_policy = TAKE_PTR(p); + break; + } case '?': return -EINVAL; @@ -2126,6 +2141,7 @@ static int run(int argc, char *argv[]) { r = mount_image_privately_interactively( arg_image, + arg_image_policy, DISSECT_IMAGE_GENERIC_ROOT | DISSECT_IMAGE_REQUIRE_ROOT | DISSECT_IMAGE_VALIDATE_OS | diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c index 223164ea1bd..c5b22d5d768 100644 --- a/src/machine-id-setup/machine-id-setup-main.c +++ b/src/machine-id-setup/machine-id-setup-main.c @@ -22,9 +22,11 @@ static char *arg_root = NULL; static char *arg_image = NULL; static bool arg_commit = false; static bool arg_print = false; +static ImagePolicy *arg_image_policy = NULL; STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_image, freep); +STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); static int help(void) { _cleanup_free_ char *link = NULL; @@ -36,12 +38,13 @@ static int help(void) { printf("%s [OPTIONS...]\n" "\n%sInitialize /etc/machine-id from a random source.%s\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " --root=PATH Operate relative to root path\n" - " --image=PATH Operate relative to image file\n" - " --commit Commit transient ID\n" - " --print Print used machine ID\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --root=PATH Operate on an alternate filesystem root\n" + " --image=PATH Operate on disk image as filesystem root\n" + " --image-policy=POLICY Specify disk image dissection policy\n" + " --commit Commit transient ID\n" + " --print Print used machine ID\n" "\nSee the %s for details.\n", program_invocation_short_name, ansi_highlight(), @@ -59,15 +62,17 @@ static int parse_argv(int argc, char *argv[]) { ARG_IMAGE, ARG_COMMIT, ARG_PRINT, + ARG_IMAGE_POLICY, }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "root", required_argument, NULL, ARG_ROOT }, - { "image", required_argument, NULL, ARG_IMAGE }, - { "commit", no_argument, NULL, ARG_COMMIT }, - { "print", no_argument, NULL, ARG_PRINT }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "root", required_argument, NULL, ARG_ROOT }, + { "image", required_argument, NULL, ARG_IMAGE }, + { "commit", no_argument, NULL, ARG_COMMIT }, + { "print", no_argument, NULL, ARG_PRINT }, + { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, {} }; @@ -106,6 +111,17 @@ static int parse_argv(int argc, char *argv[]) { arg_print = true; break; + case ARG_IMAGE_POLICY: { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + + r = image_policy_from_string(optarg, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", optarg); + + image_policy_free(arg_image_policy); + arg_image_policy = TAKE_PTR(p); + break; + } case '?': return -EINVAL; @@ -141,6 +157,7 @@ static int run(int argc, char *argv[]) { r = mount_image_privately_interactively( arg_image, + arg_image_policy, DISSECT_IMAGE_REQUIRE_ROOT | DISSECT_IMAGE_VALIDATE_OS | DISSECT_IMAGE_RELAX_VAR_CHECK | diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index bf65eecfdd4..336b42b7e51 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -313,7 +313,7 @@ int bus_image_method_get_hostname( int r; if (!image->metadata_valid) { - r = image_read_metadata(image); + r = image_read_metadata(image, &image_policy_container); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m"); } @@ -331,7 +331,7 @@ int bus_image_method_get_machine_id( int r; if (!image->metadata_valid) { - r = image_read_metadata(image); + r = image_read_metadata(image, &image_policy_container); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m"); } @@ -359,7 +359,7 @@ int bus_image_method_get_machine_info( int r; if (!image->metadata_valid) { - r = image_read_metadata(image); + r = image_read_metadata(image, &image_policy_container); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m"); } @@ -376,7 +376,7 @@ int bus_image_method_get_os_release( int r; if (!image->metadata_valid) { - r = image_read_metadata(image); + r = image_read_metadata(image, &image_policy_container); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m"); } diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 8abb0167910..6b74a3df131 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -234,6 +234,7 @@ static char **arg_bind_user = NULL; static bool arg_suppress_sync = false; static char *arg_settings_filename = NULL; static Architecture arg_architecture = _ARCHITECTURE_INVALID; +static ImagePolicy *arg_image_policy = NULL; STATIC_DESTRUCTOR_REGISTER(arg_directory, freep); STATIC_DESTRUCTOR_REGISTER(arg_template, freep); @@ -268,6 +269,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_cpu_set, cpu_set_reset); STATIC_DESTRUCTOR_REGISTER(arg_sysctl, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_bind_user, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_settings_filename, freep); +STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); static int handle_arg_console(const char *arg) { if (streq(arg, "help")) { @@ -330,6 +332,7 @@ static int help(void) { " remove it after exit\n" " -i --image=PATH Root file system disk image (or device node) for\n" " the container\n" + " --image-policy=POLICY Specify disk image dissection policy\n" " --oci-bundle=PATH OCI bundle directory\n" " --read-only Mount the root directory read-only\n" " --volatile[=MODE] Run the system in volatile mode\n" @@ -732,6 +735,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_LOAD_CREDENTIAL, ARG_BIND_USER, ARG_SUPPRESS_SYNC, + ARG_IMAGE_POLICY, }; static const struct option options[] = { @@ -805,6 +809,7 @@ static int parse_argv(int argc, char *argv[]) { { "load-credential", required_argument, NULL, ARG_LOAD_CREDENTIAL }, { "bind-user", required_argument, NULL, ARG_BIND_USER }, { "suppress-sync", required_argument, NULL, ARG_SUPPRESS_SYNC }, + { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, {} }; @@ -1696,6 +1701,18 @@ static int parse_argv(int argc, char *argv[]) { arg_settings_mask |= SETTING_SUPPRESS_SYNC; break; + case ARG_IMAGE_POLICY: { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + + r = image_policy_from_string(optarg, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", optarg); + + image_policy_free(arg_image_policy); + arg_image_policy = TAKE_PTR(p); + break; + } + case '?': return -EINVAL; @@ -5755,7 +5772,8 @@ static int run(int argc, char *argv[]) { r = dissect_loop_device_and_warn( loop, &arg_verity_settings, - NULL, + /* mount_options=*/ NULL, + arg_image_policy ?: &image_policy_container, dissect_image_flags, &dissected_image); if (r == -ENOPKG) { diff --git a/src/partition/repart.c b/src/partition/repart.c index e4ae8a2c89f..bc3bfa15fb6 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -148,6 +148,7 @@ static FilterPartitionsType arg_filter_partitions_type = FILTER_PARTITIONS_NONE; static sd_id128_t *arg_defer_partitions = NULL; static size_t arg_n_defer_partitions = 0; static uint64_t arg_sector_size = 0; +static ImagePolicy *arg_image_policy = NULL; STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_image, freep); @@ -158,6 +159,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_certificate, X509_freep); STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep); STATIC_DESTRUCTOR_REGISTER(arg_tpm2_public_key, freep); STATIC_DESTRUCTOR_REGISTER(arg_filter_partitions, freep); +STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); typedef struct FreeArea FreeArea; @@ -5632,6 +5634,8 @@ static int help(void) { " --can-factory-reset Test whether factory reset is defined\n" " --root=PATH Operate relative to root path\n" " --image=PATH Operate relative to image file\n" + " --image-policy=POLICY\n" + " Specify disk image dissection policy\n" " --definitions=DIR Find partition definitions in specified directory\n" " --key-file=PATH Key to use when encrypting partitions\n" " --private-key=PATH Private key to use when generating verity roothash\n" @@ -5697,6 +5701,8 @@ static int parse_argv(int argc, char *argv[]) { ARG_EXCLUDE_PARTITIONS, ARG_DEFER_PARTITIONS, ARG_SECTOR_SIZE, + ARG_SKIP_PARTITIONS, + ARG_IMAGE_POLICY, }; static const struct option options[] = { @@ -5728,6 +5734,7 @@ static int parse_argv(int argc, char *argv[]) { { "exclude-partitions", required_argument, NULL, ARG_EXCLUDE_PARTITIONS }, { "defer-partitions", required_argument, NULL, ARG_DEFER_PARTITIONS }, { "sector-size", required_argument, NULL, ARG_SECTOR_SIZE }, + { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, {} }; @@ -6022,6 +6029,18 @@ static int parse_argv(int argc, char *argv[]) { break; + case ARG_IMAGE_POLICY: { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + + r = image_policy_from_string(optarg, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", optarg); + + image_policy_free(arg_image_policy); + arg_image_policy = TAKE_PTR(p); + break; + } + case '?': return -EINVAL; @@ -6522,6 +6541,7 @@ static int run(int argc, char *argv[]) { * systems */ r = mount_image_privately_interactively( arg_image, + arg_image_policy, DISSECT_IMAGE_MOUNT_READ_ONLY | (arg_node ? DISSECT_IMAGE_DEVICE_READ_ONLY : 0) | /* If a different node to make changes to is specified let's open the device in read-only mode) */ DISSECT_IMAGE_GPT_ONLY | diff --git a/src/portable/portable.c b/src/portable/portable.c index adfd846bab7..23420abab25 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -324,6 +324,7 @@ static int portable_extract_by_path( bool path_is_extension, bool relax_extension_release_check, char **matches, + const ImagePolicy *image_policy, PortableMetadata **ret_os_release, Hashmap **ret_unit_files, sd_bus_error *error) { @@ -369,7 +370,9 @@ static int portable_extract_by_path( r = dissect_loop_device( d, - NULL, NULL, + /* verity= */ NULL, + /* mount_options= */ NULL, + image_policy, DISSECT_IMAGE_READ_ONLY | DISSECT_IMAGE_GENERIC_ROOT | DISSECT_IMAGE_REQUIRE_ROOT | @@ -510,6 +513,7 @@ static int extract_image_and_extensions( char **extension_image_paths, bool validate_sysext, bool relax_extension_release_check, + const ImagePolicy *image_policy, Image **ret_image, OrderedHashmap **ret_extension_images, OrderedHashmap **ret_extension_releases, @@ -558,7 +562,15 @@ static int extract_image_and_extensions( } } - r = portable_extract_by_path(image->path, /* path_is_extension= */ false, /* relax_extension_release_check= */ false, matches, &os_release, &unit_files, error); + r = portable_extract_by_path( + image->path, + /* path_is_extension= */ false, + /* relax_extension_release_check= */ false, + matches, + image_policy, + &os_release, + &unit_files, + error); if (r < 0) return r; @@ -591,7 +603,15 @@ static int extract_image_and_extensions( _cleanup_strv_free_ char **extension_release = NULL; const char *e; - r = portable_extract_by_path(ext->path, /* path_is_extension= */ true, relax_extension_release_check, matches, &extension_release_meta, &extra_unit_files, error); + r = portable_extract_by_path( + ext->path, + /* path_is_extension= */ true, + relax_extension_release_check, + matches, + image_policy, + &extension_release_meta, + &extra_unit_files, + error); if (r < 0) return r; @@ -657,6 +677,7 @@ int portable_extract( const char *name_or_path, char **matches, char **extension_image_paths, + const ImagePolicy *image_policy, PortableFlags flags, PortableMetadata **ret_os_release, OrderedHashmap **ret_extension_releases, @@ -679,6 +700,7 @@ int portable_extract( extension_image_paths, /* validate_sysext= */ false, /* relax_extension_release_check= */ FLAGS_SET(flags, PORTABLE_FORCE_SYSEXT), + image_policy, &image, &extension_images, &extension_releases, @@ -1392,6 +1414,7 @@ int portable_attach( char **matches, const char *profile, char **extension_image_paths, + const ImagePolicy *image_policy, PortableFlags flags, PortableChange **changes, size_t *n_changes, @@ -1412,6 +1435,7 @@ int portable_attach( extension_image_paths, /* validate_sysext= */ true, /* relax_extension_release_check= */ FLAGS_SET(flags, PORTABLE_FORCE_SYSEXT), + image_policy, &image, &extension_images, &extension_releases, diff --git a/src/portable/portable.h b/src/portable/portable.h index 1a33f30944c..c61d65fed35 100644 --- a/src/portable/portable.h +++ b/src/portable/portable.h @@ -3,6 +3,7 @@ #include "sd-bus.h" +#include "dissect-image.h" #include "hashmap.h" #include "macro.h" #include "set.h" @@ -67,9 +68,9 @@ 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, PortableFlags flags, PortableMetadata **ret_os_release, OrderedHashmap **ret_extension_releases, Hashmap **ret_unit_files, char ***ret_valid_prefixes, sd_bus_error *error); +int portable_extract(const char *image, char **matches, char **extension_image_paths, const ImagePolicy *image_policy, PortableFlags flags, PortableMetadata **ret_os_release, OrderedHashmap **ret_extension_releases, 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_attach(sd_bus *bus, const char *name_or_path, char **matches, const char *profile, char **extension_images, const ImagePolicy* image_policy, 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); int portable_get_state(sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableState *ret, sd_bus_error *error); diff --git a/src/portable/portabled-image-bus.c b/src/portable/portabled-image-bus.c index 6c4cb6ec9de..262518d15cc 100644 --- a/src/portable/portabled-image-bus.c +++ b/src/portable/portabled-image-bus.c @@ -60,7 +60,7 @@ int bus_image_common_get_os_release( return 1; if (!image->metadata_valid) { - r = image_read_metadata(image); + r = image_read_metadata(image, &image_policy_service); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m"); } @@ -163,6 +163,7 @@ int bus_image_common_get_metadata( image->path, matches, extension_images, + /* image_policy= */ NULL, flags, &os_release, &extension_releases, @@ -385,6 +386,7 @@ int bus_image_common_attach( matches, profile, extension_images, + /* image_policy= */ NULL, flags, &changes, &n_changes, @@ -729,6 +731,7 @@ int bus_image_common_reattach( matches, profile, extension_images, + /* image_policy= */ NULL, flags, &changes_attached, &n_changes_attached, diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 6966cfd8389..81eef8b0583 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -959,7 +959,10 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con "ProcSubset", "NetworkNamespacePath", "IPCNamespacePath", - "LogNamespace")) + "LogNamespace", + "RootImagePolicy", + "MountImagePolicy", + "ExtensionImagePolicy")) return bus_append_string(m, field, eq); if (STR_IN_SET(field, "IgnoreSIGPIPE", diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c index eed0a5629e4..86ff5d6d93a 100644 --- a/src/shared/discover-image.c +++ b/src/shared/discover-image.c @@ -1133,7 +1133,7 @@ int image_set_limit(Image *i, uint64_t referenced_max) { return btrfs_subvol_set_subtree_quota_limit(i->path, 0, referenced_max); } -int image_read_metadata(Image *i) { +int image_read_metadata(Image *i, const ImagePolicy *image_policy) { _cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT; int r; @@ -1214,7 +1214,9 @@ int image_read_metadata(Image *i) { r = dissect_loop_device( d, - NULL, NULL, + /* verity= */ NULL, + /* mount_options= */ NULL, + image_policy, DISSECT_IMAGE_GENERIC_ROOT | DISSECT_IMAGE_REQUIRE_ROOT | DISSECT_IMAGE_RELAX_VAR_CHECK | diff --git a/src/shared/discover-image.h b/src/shared/discover-image.h index 3c6928619c0..c423132a62b 100644 --- a/src/shared/discover-image.h +++ b/src/shared/discover-image.h @@ -7,6 +7,7 @@ #include "sd-id128.h" #include "hashmap.h" +#include "image-policy.h" #include "lock-util.h" #include "macro.h" #include "path-util.h" @@ -85,7 +86,7 @@ int image_name_lock(const char *name, int operation, LockFile *ret); int image_set_limit(Image *i, uint64_t referenced_max); -int image_read_metadata(Image *i); +int image_read_metadata(Image *i, const ImagePolicy *image_policy); bool image_in_search_path(ImageClass class, const char *root, const char *image); diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 6000af0ce05..83b0581ff1a 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -543,6 +543,7 @@ static int dissect_image( const char *devname, const VeritySettings *verity, const MountOptions *mount_options, + const ImagePolicy *policy, DissectImageFlags flags) { sd_id128_t root_uuid = SD_ID128_NULL, root_verity_uuid = SD_ID128_NULL; @@ -1331,6 +1332,7 @@ int dissect_image_file( const char *path, const VeritySettings *verity, const MountOptions *mount_options, + const ImagePolicy *image_policy, DissectImageFlags flags, DissectedImage **ret) { @@ -1358,7 +1360,7 @@ int dissect_image_file( if (r < 0) return r; - r = dissect_image(m, fd, path, verity, mount_options, flags); + r = dissect_image(m, fd, path, verity, mount_options, image_policy, flags); if (r < 0) return r; @@ -3250,6 +3252,7 @@ int dissect_loop_device( LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, + const ImagePolicy *image_policy, DissectImageFlags flags, DissectedImage **ret) { @@ -3267,7 +3270,7 @@ int dissect_loop_device( m->loop = loop_device_ref(loop); m->sector_size = m->loop->sector_size; - r = dissect_image(m, loop->fd, loop->node, verity, mount_options, flags); + r = dissect_image(m, loop->fd, loop->node, verity, mount_options, image_policy, flags); if (r < 0) return r; @@ -3282,6 +3285,7 @@ int dissect_loop_device_and_warn( LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, + const ImagePolicy *image_policy, DissectImageFlags flags, DissectedImage **ret) { @@ -3293,7 +3297,7 @@ int dissect_loop_device_and_warn( name = ASSERT_PTR(loop->backing_file ?: loop->node); - r = dissect_loop_device(loop, verity, mount_options, flags, ret); + r = dissect_loop_device(loop, verity, mount_options, image_policy, flags, ret); switch (r) { case -EOPNOTSUPP: @@ -3407,6 +3411,7 @@ const char* mount_options_from_designator(const MountOptions *options, Partition int mount_image_privately_interactively( const char *image, + const ImagePolicy *image_policy, DissectImageFlags flags, char **ret_directory, int *ret_dir_fd, @@ -3449,7 +3454,13 @@ int mount_image_privately_interactively( if (r < 0) return log_error_errno(r, "Failed to set up loopback device for %s: %m", image); - r = dissect_loop_device_and_warn(d, &verity, NULL, flags, &dissected_image); + r = dissect_loop_device_and_warn( + d, + &verity, + /* mount_options= */ NULL, + image_policy, + flags, + &dissected_image); if (r < 0) return r; @@ -3513,6 +3524,7 @@ int verity_dissect_and_mount( const char *src, const char *dest, const MountOptions *options, + const ImagePolicy *image_policy, const char *required_host_os_release_id, const char *required_host_os_release_version_id, const char *required_host_os_release_sysext_level, @@ -3556,6 +3568,7 @@ int verity_dissect_and_mount( loop_device, &verity, options, + image_policy, dissect_image_flags, &dissected_image); /* No partition table? Might be a single-filesystem image, try again */ @@ -3564,6 +3577,7 @@ int verity_dissect_and_mount( loop_device, &verity, options, + image_policy, dissect_image_flags | DISSECT_IMAGE_NO_PARTITION_TABLE, &dissected_image); if (r < 0) diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index 2e741e82676..3af0c439bcf 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -133,6 +133,9 @@ struct VeritySettings { .designator = _PARTITION_DESIGNATOR_INVALID \ } +/* We include image-policy.h down here, since ImagePolicy wants a complete definition of PartitionDesignator first. */ +#include "image-policy.h" + MountOptions* mount_options_free_all(MountOptions *options); DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all); const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator); @@ -141,14 +144,10 @@ int probe_filesystem_full(int fd, const char *path, uint64_t offset, uint64_t si static inline int probe_filesystem(const char *path, char **ret_fstype) { return probe_filesystem_full(-1, path, 0, UINT64_MAX, ret_fstype); } -int dissect_image_file( - const char *path, - const VeritySettings *verity, - const MountOptions *mount_options, - DissectImageFlags flags, - DissectedImage **ret); -int dissect_loop_device(LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret); -int dissect_loop_device_and_warn(LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret); + +int dissect_image_file(const char *path, const VeritySettings *verity, const MountOptions *mount_options, const ImagePolicy *image_policy, DissectImageFlags flags, DissectedImage **ret); +int dissect_loop_device(LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, const ImagePolicy *image_policy, DissectImageFlags flags, DissectedImage **ret); +int dissect_loop_device_and_warn(LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, const ImagePolicy *image_policy, DissectImageFlags flags, DissectedImage **ret); DissectedImage* dissected_image_unref(DissectedImage *m); DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref); @@ -185,9 +184,9 @@ bool dissected_image_verity_candidate(const DissectedImage *image, PartitionDesi bool dissected_image_verity_ready(const DissectedImage *image, PartitionDesignator d); bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesignator d); -int mount_image_privately_interactively(const char *path, DissectImageFlags flags, char **ret_directory, int *ret_dir_fd, LoopDevice **ret_loop_device); +int mount_image_privately_interactively(const char *path, const ImagePolicy *image_policy, DissectImageFlags flags, char **ret_directory, int *ret_dir_fd, LoopDevice **ret_loop_device); -int verity_dissect_and_mount(int src_fd, 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, const char *required_sysext_scope); +int verity_dissect_and_mount(int src_fd, const char *src, const char *dest, const MountOptions *options, const ImagePolicy *image_policy, const char *required_host_os_release_id, const char *required_host_os_release_version_id, const char *required_host_os_release_sysext_level, const char *required_sysext_scope); int dissect_fstype_ok(const char *fstype); diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c index 1eac51b81ea..edf01fe0921 100644 --- a/src/shared/mount-util.c +++ b/src/shared/mount-util.c @@ -805,6 +805,7 @@ static int mount_in_namespace( bool read_only, bool make_file_or_directory, const MountOptions *options, + const ImagePolicy *image_policy, bool is_image) { _cleanup_close_pair_ int errno_pipe_fd[2] = PIPE_EBADF; @@ -892,7 +893,7 @@ static int mount_in_namespace( mount_tmp_created = true; if (is_image) - r = verity_dissect_and_mount(chased_src_fd, chased_src_path, mount_tmp, options, NULL, NULL, NULL, NULL); + r = verity_dissect_and_mount(chased_src_fd, chased_src_path, mount_tmp, options, image_policy, NULL, NULL, NULL, NULL); else r = mount_follow_verbose(LOG_DEBUG, FORMAT_PROC_FD_PATH(chased_src_fd), mount_tmp, NULL, MS_BIND, NULL); if (r < 0) @@ -1042,7 +1043,7 @@ int bind_mount_in_namespace( bool read_only, bool make_file_or_directory) { - return mount_in_namespace(target, propagate_path, incoming_path, src, dest, read_only, make_file_or_directory, NULL, false); + return mount_in_namespace(target, propagate_path, incoming_path, src, dest, read_only, make_file_or_directory, /* options= */ NULL, /* image_policy= */ NULL, /* is_image= */ false); } int mount_image_in_namespace( @@ -1053,9 +1054,10 @@ int mount_image_in_namespace( const char *dest, bool read_only, bool make_file_or_directory, - const MountOptions *options) { + const MountOptions *options, + const ImagePolicy *image_policy) { - return mount_in_namespace(target, propagate_path, incoming_path, src, dest, read_only, make_file_or_directory, options, true); + return mount_in_namespace(target, propagate_path, incoming_path, src, dest, read_only, make_file_or_directory, options, image_policy, /* is_image=*/ true); } int make_mount_point(const char *path) { diff --git a/src/shared/mount-util.h b/src/shared/mount-util.h index 84ea4b63927..f52687828a6 100644 --- a/src/shared/mount-util.h +++ b/src/shared/mount-util.h @@ -81,7 +81,7 @@ static inline char* umount_and_rmdir_and_free(char *p) { DEFINE_TRIVIAL_CLEANUP_FUNC(char*, umount_and_rmdir_and_free); int bind_mount_in_namespace(pid_t target, const char *propagate_path, const char *incoming_path, const char *src, const char *dest, bool read_only, bool make_file_or_directory); -int mount_image_in_namespace(pid_t target, const char *propagate_path, const char *incoming_path, const char *src, const char *dest, bool read_only, bool make_file_or_directory, const MountOptions *options); +int mount_image_in_namespace(pid_t target, const char *propagate_path, const char *incoming_path, const char *src, const char *dest, bool read_only, bool make_file_or_directory, const MountOptions *options, const ImagePolicy *image_policy); int make_mount_point(const char *path); diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index 5632b72f3d2..ce076f665a6 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -45,9 +45,11 @@ static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; static PagerFlags arg_pager_flags = 0; static bool arg_legend = true; static bool arg_force = false; +static ImagePolicy *arg_image_policy = NULL; STATIC_DESTRUCTOR_REGISTER(arg_hierarchies, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); +STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); static int is_our_mount_point(const char *p) { _cleanup_free_ char *buf = NULL, *f = NULL; @@ -523,7 +525,8 @@ static int merge_subprocess(Hashmap *images, const char *workspace) { r = dissect_loop_device_and_warn( d, &verity_settings, - NULL, + /* mount_options= */ NULL, + arg_image_policy ?: &image_policy_sysext, flags, &m); if (r < 0) @@ -734,7 +737,7 @@ static int image_discover_and_read_metadata(Hashmap **ret_images) { return log_error_errno(r, "Failed to discover extension images: %m"); HASHMAP_FOREACH(img, images) { - r = image_read_metadata(img); + r = image_read_metadata(img, &image_policy_sysext); if (r < 0) return log_error_errno(r, "Failed to read metadata for image %s: %m", img->name); } @@ -886,6 +889,8 @@ static int verb_help(int argc, char **argv, void *userdata) { " --json=pretty|short|off\n" " Generate JSON output\n" " --force Ignore version incompatibilities\n" + " --image-policy=POLICY\n" + " Specify disk image dissection policy\n" "\nSee the %2$s for details.\n", program_invocation_short_name, link, @@ -906,16 +911,18 @@ static int parse_argv(int argc, char *argv[]) { ARG_ROOT, ARG_JSON, ARG_FORCE, + ARG_IMAGE_POLICY, }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, - { "root", required_argument, NULL, ARG_ROOT }, - { "json", required_argument, NULL, ARG_JSON }, - { "force", no_argument, NULL, ARG_FORCE }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, + { "root", required_argument, NULL, ARG_ROOT }, + { "json", required_argument, NULL, ARG_JSON }, + { "force", no_argument, NULL, ARG_FORCE }, + { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, {} }; @@ -959,6 +966,17 @@ static int parse_argv(int argc, char *argv[]) { arg_force = true; break; + case ARG_IMAGE_POLICY: { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + + r = image_policy_from_string(optarg, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", optarg); + + image_policy_free(arg_image_policy); + arg_image_policy = TAKE_PTR(p); + break; + } case '?': return -EINVAL; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 1a5beabc722..df4cf684355 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -121,6 +121,7 @@ bool arg_read_only = false; bool arg_mkdir = false; bool arg_marked = false; const char *arg_drop_in = NULL; +ImagePolicy *arg_image_policy = NULL; STATIC_DESTRUCTOR_REGISTER(arg_types, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_states, strv_freep); @@ -135,6 +136,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_host, unsetp); STATIC_DESTRUCTOR_REGISTER(arg_boot_loader_entry, unsetp); STATIC_DESTRUCTOR_REGISTER(arg_clean_what, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_drop_in, unsetp); +STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); static int systemctl_help(void) { _cleanup_free_ char *link = NULL; @@ -305,7 +307,9 @@ static int systemctl_help(void) { " --root=PATH Edit/enable/disable/mask unit files in the specified\n" " root directory\n" " --image=PATH Edit/enable/disable/mask unit files in the specified\n" - " image\n" + " disk image\n" + " --image-policy=POLICY\n" + " Specify disk image dissection policy\n" " -n --lines=INTEGER Number of journal entries to show\n" " -o --output=STRING Change journal output mode (short, short-precise,\n" " short-iso, short-iso-precise, short-full,\n" @@ -450,6 +454,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_NO_WARN, ARG_DROP_IN, ARG_WHEN, + ARG_IMAGE_POLICY, }; static const struct option options[] = { @@ -515,6 +520,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "marked", no_argument, NULL, ARG_MARKED }, { "drop-in", required_argument, NULL, ARG_DROP_IN }, { "when", required_argument, NULL, ARG_WHEN }, + { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, {} }; @@ -1003,6 +1009,18 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; + case ARG_IMAGE_POLICY: { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + + r = image_policy_from_string(optarg, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", optarg); + + image_policy_free(arg_image_policy); + arg_image_policy = TAKE_PTR(p); + break; + } + case '.': /* Output an error mimicking getopt, and print a hint afterwards */ log_error("%s: invalid option -- '.'", program_invocation_name); @@ -1248,6 +1266,7 @@ static int run(int argc, char *argv[]) { r = mount_image_privately_interactively( arg_image, + arg_image_policy, DISSECT_IMAGE_GENERIC_ROOT | DISSECT_IMAGE_REQUIRE_ROOT | DISSECT_IMAGE_RELAX_VAR_CHECK | diff --git a/src/systemctl/systemctl.h b/src/systemctl/systemctl.h index 8c96ee0b4f0..03645624ee8 100644 --- a/src/systemctl/systemctl.h +++ b/src/systemctl/systemctl.h @@ -5,6 +5,7 @@ #include "bus-print-properties.h" #include "bus-util.h" +#include "image-policy.h" #include "install.h" #include "output-mode.h" #include "pager.h" @@ -100,6 +101,7 @@ extern bool arg_read_only; extern bool arg_mkdir; extern bool arg_marked; extern const char *arg_drop_in; +extern ImagePolicy *arg_image_policy; static inline const char* arg_job_mode(void) { return _arg_job_mode ?: "replace"; diff --git a/src/sysupdate/sysupdate.c b/src/sysupdate/sysupdate.c index 6cb09dae50d..f62e1930562 100644 --- a/src/sysupdate/sysupdate.c +++ b/src/sysupdate/sysupdate.c @@ -46,11 +46,13 @@ static char *arg_image = NULL; static bool arg_reboot = false; static char *arg_component = NULL; static int arg_verify = -1; +static ImagePolicy *arg_image_policy = NULL; STATIC_DESTRUCTOR_REGISTER(arg_definitions, freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_image, freep); STATIC_DESTRUCTOR_REGISTER(arg_component, freep); +STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); typedef struct Context { Transfer **transfers; @@ -872,6 +874,7 @@ static int process_image( r = mount_image_privately_interactively( arg_image, + arg_image_policy, (ro ? DISSECT_IMAGE_READ_ONLY : 0) | DISSECT_IMAGE_FSCK | DISSECT_IMAGE_MKDIR | @@ -1022,7 +1025,7 @@ static int verb_pending_or_reboot(int argc, char **argv, void *userdata) { if (arg_image || arg_root) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "The --root=/--image switches may not be combined with the '%s' operation.", argv[0]); + "The --root=/--image= switches may not be combined with the '%s' operation.", argv[0]); r = context_make_offline(&context, NULL); if (r < 0) @@ -1205,8 +1208,10 @@ static int verb_help(int argc, char **argv, void *userdata) { "\n%3$sOptions:%4$s\n" " -C --component=NAME Select component to update\n" " --definitions=DIR Find transfer definitions in specified directory\n" - " --root=PATH Operate relative to root path\n" - " --image=PATH Operate relative to image file\n" + " --root=PATH Operate on an alternate filesystem root\n" + " --image=PATH Operate on disk image as filesystem root\n" + " --image-policy=POLICY\n" + " Specify disk image dissection policy\n" " -m --instances-max=INT How many instances to maintain\n" " --sync=BOOL Controls whether to sync data to disk\n" " --verify=BOOL Force signature verification on or off\n" @@ -1238,6 +1243,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_IMAGE, ARG_REBOOT, ARG_VERIFY, + ARG_IMAGE_POLICY, }; static const struct option options[] = { @@ -1254,6 +1260,7 @@ static int parse_argv(int argc, char *argv[]) { { "reboot", no_argument, NULL, ARG_REBOOT }, { "component", required_argument, NULL, 'C' }, { "verify", required_argument, NULL, ARG_VERIFY }, + { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, {} }; @@ -1351,6 +1358,17 @@ static int parse_argv(int argc, char *argv[]) { break; } + case ARG_IMAGE_POLICY: { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + + r = image_policy_from_string(optarg, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", optarg); + + image_policy_free(arg_image_policy); + arg_image_policy = TAKE_PTR(p); + break; + } case '?': return -EINVAL; diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index f9f694bd549..a2d62121e0b 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -99,6 +99,7 @@ static const char *arg_replace = NULL; static bool arg_dry_run = false; static bool arg_inline = false; static PagerFlags arg_pager_flags = 0; +static ImagePolicy *arg_image_policy = NULL; static OrderedHashmap *users = NULL, *groups = NULL; static OrderedHashmap *todo_uids = NULL, *todo_gids = NULL; @@ -128,6 +129,7 @@ STATIC_DESTRUCTOR_REGISTER(database_groups, set_free_freep); STATIC_DESTRUCTOR_REGISTER(uid_range, uid_range_freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_image, freep); +STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); static int errno_is_not_exists(int code) { /* See getpwnam(3) and getgrnam(3): those codes and others can be returned if the user or group are @@ -1964,6 +1966,7 @@ static int help(void) { " --cat-config Show configuration files\n" " --root=PATH Operate on an alternate filesystem root\n" " --image=PATH Operate on disk image as filesystem root\n" + " --image-policy=POLICY Specify disk image dissection policy\n" " --replace=PATH Treat arguments as replacement for PATH\n" " --dry-run Just print what would be done\n" " --inline Treat arguments as configuration lines\n" @@ -1986,18 +1989,20 @@ static int parse_argv(int argc, char *argv[]) { ARG_DRY_RUN, ARG_INLINE, ARG_NO_PAGER, + ARG_IMAGE_POLICY, }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "cat-config", no_argument, NULL, ARG_CAT_CONFIG }, - { "root", required_argument, NULL, ARG_ROOT }, - { "image", required_argument, NULL, ARG_IMAGE }, - { "replace", required_argument, NULL, ARG_REPLACE }, - { "dry-run", no_argument, NULL, ARG_DRY_RUN }, - { "inline", no_argument, NULL, ARG_INLINE }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "cat-config", no_argument, NULL, ARG_CAT_CONFIG }, + { "root", required_argument, NULL, ARG_ROOT }, + { "image", required_argument, NULL, ARG_IMAGE }, + { "replace", required_argument, NULL, ARG_REPLACE }, + { "dry-run", no_argument, NULL, ARG_DRY_RUN }, + { "inline", no_argument, NULL, ARG_INLINE }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, {} }; @@ -2058,6 +2063,17 @@ static int parse_argv(int argc, char *argv[]) { arg_pager_flags |= PAGER_DISABLE; break; + case ARG_IMAGE_POLICY: { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + + r = image_policy_from_string(optarg, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", optarg); + + image_policy_free(arg_image_policy); + arg_image_policy = TAKE_PTR(p); + break; + } case '?': return -EINVAL; @@ -2173,6 +2189,7 @@ static int run(int argc, char *argv[]) { r = mount_image_privately_interactively( arg_image, + arg_image_policy, DISSECT_IMAGE_GENERIC_ROOT | DISSECT_IMAGE_REQUIRE_ROOT | DISSECT_IMAGE_VALIDATE_OS | diff --git a/src/test/test-loop-block.c b/src/test/test-loop-block.c index 97c2f66ac99..d8f48798cb0 100644 --- a/src/test/test-loop-block.c +++ b/src/test/test-loop-block.c @@ -82,7 +82,7 @@ static void* thread_func(void *ptr) { log_notice("Acquired loop device %s, will mount on %s", loop->node, mounted); - r = dissect_loop_device(loop, NULL, NULL, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES, &dissected); + r = dissect_loop_device(loop, NULL, NULL, NULL, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES, &dissected); if (r < 0) log_error_errno(r, "Failed dissect loopback device %s: %m", loop->node); assert_se(r >= 0); @@ -213,7 +213,7 @@ static int run(int argc, char *argv[]) { sfdisk = NULL; #if HAVE_BLKID - assert_se(dissect_image_file(p, NULL, NULL, 0, &dissected) >= 0); + assert_se(dissect_image_file(p, NULL, NULL, NULL, 0, &dissected) >= 0); verify_dissected_image(dissected); dissected = dissected_image_unref(dissected); #endif @@ -231,7 +231,7 @@ static int run(int argc, char *argv[]) { assert_se(loop_device_make(fd, O_RDWR, 0, UINT64_MAX, 0, LO_FLAGS_PARTSCAN, LOCK_EX, &loop) >= 0); #if HAVE_BLKID - assert_se(dissect_loop_device(loop, NULL, NULL, DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES, &dissected) >= 0); + assert_se(dissect_loop_device(loop, NULL, NULL, NULL, DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES, &dissected) >= 0); verify_dissected_image(dissected); FOREACH_STRING(fs, "vfat", "ext4") { @@ -267,12 +267,12 @@ static int run(int argc, char *argv[]) { /* Try to read once, without pinning or adding partitions, i.e. by only accessing the whole block * device. */ - assert_se(dissect_loop_device(loop, NULL, NULL, 0, &dissected) >= 0); + assert_se(dissect_loop_device(loop, NULL, NULL, NULL, 0, &dissected) >= 0); verify_dissected_image_harder(dissected); dissected = dissected_image_unref(dissected); /* Now go via the loopback device after all, but this time add/pin, because now we want to mount it. */ - assert_se(dissect_loop_device(loop, NULL, NULL, DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES, &dissected) >= 0); + assert_se(dissect_loop_device(loop, NULL, NULL, NULL, DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES, &dissected) >= 0); verify_dissected_image_harder(dissected); assert_se(mkdtemp_malloc(NULL, &mounted) >= 0); diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c index 72155127c1e..82be09dd6a6 100644 --- a/src/test/test-namespace.c +++ b/src/test/test-namespace.c @@ -176,6 +176,7 @@ TEST(protect_kernel_logs) { assert_se(fd > 0); r = setup_namespace(NULL, + NULL, NULL, NULL, &ns_info, @@ -193,6 +194,7 @@ TEST(protect_kernel_logs) { NULL, NULL, NULL, + NULL, 0, NULL, 0, @@ -208,6 +210,7 @@ TEST(protect_kernel_logs) { NULL, NULL, NULL, + NULL, NULL); assert_se(r == 0); diff --git a/src/test/test-ns.c b/src/test/test-ns.c index 7eb29d109d1..485069670b4 100644 --- a/src/test/test-ns.c +++ b/src/test/test-ns.c @@ -77,6 +77,7 @@ int main(int argc, char *argv[]) { log_info("Not chrooted"); r = setup_namespace(root_directory, + NULL, NULL, NULL, &ns_info, @@ -91,6 +92,7 @@ int main(int argc, char *argv[]) { &(TemporaryFileSystem) { .path = (char*) "/var", .options = (char*) "ro" }, 1, NULL, 0, + NULL, tmp_dir, var_tmp_dir, NULL, @@ -110,6 +112,7 @@ int main(int argc, char *argv[]) { NULL, NULL, NULL, + NULL, NULL); if (r < 0) { log_error_errno(r, "Failed to set up namespace: %m"); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 6cd76e8df84..fdabd7d2c56 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -206,6 +206,7 @@ static char **arg_exclude_prefixes = NULL; static char *arg_root = NULL; static char *arg_image = NULL; static char *arg_replace = NULL; +static ImagePolicy *arg_image_policy = NULL; #define MAX_DEPTH 256 @@ -219,6 +220,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_include_prefixes, freep); STATIC_DESTRUCTOR_REGISTER(arg_exclude_prefixes, freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_image, freep); +STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); static const char *const creation_mode_verb_table[_CREATION_MODE_MAX] = { [CREATION_NORMAL] = "Created", @@ -3699,6 +3701,7 @@ static int help(void) { " -E Ignore rules prefixed with /dev, /proc, /run, /sys\n" " --root=PATH Operate on an alternate filesystem root\n" " --image=PATH Operate on disk image as filesystem root\n" + " --image-policy=POLICY Specify disk image dissection policy\n" " --replace=PATH Treat arguments as replacement for PATH\n" " --no-pager Do not pipe output into a pager\n" "\nSee the %s for details.\n", @@ -3726,6 +3729,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_IMAGE, ARG_REPLACE, ARG_NO_PAGER, + ARG_IMAGE_POLICY, }; static const struct option options[] = { @@ -3743,6 +3747,7 @@ static int parse_argv(int argc, char *argv[]) { { "image", required_argument, NULL, ARG_IMAGE }, { "replace", required_argument, NULL, ARG_REPLACE }, { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, {} }; @@ -3833,6 +3838,17 @@ static int parse_argv(int argc, char *argv[]) { arg_pager_flags |= PAGER_DISABLE; break; + case ARG_IMAGE_POLICY: { + _cleanup_(image_policy_freep) ImagePolicy *p = NULL; + + r = image_policy_from_string(optarg, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", optarg); + + image_policy_free(arg_image_policy); + arg_image_policy = TAKE_PTR(p); + break; + } case '?': return -EINVAL; @@ -4153,6 +4169,7 @@ static int run(int argc, char *argv[]) { r = mount_image_privately_interactively( arg_image, + arg_image_policy, DISSECT_IMAGE_GENERIC_ROOT | DISSECT_IMAGE_REQUIRE_ROOT | DISSECT_IMAGE_VALIDATE_OS |