diff options
author | Luca Boccassi <bluca@debian.org> | 2022-06-13 01:01:02 +0200 |
---|---|---|
committer | Luca Boccassi <bluca@debian.org> | 2022-07-08 17:58:15 +0200 |
commit | 80a2381d5c156cffedf41a3e7b95f7a00045a0fd (patch) | |
tree | c84b84deb3bb654c3d40cdd14f19293e474a49ad /src | |
parent | Merge pull request #23396 from msekletar/fix-idle-action-lock (diff) | |
download | systemd-80a2381d5c156cffedf41a3e7b95f7a00045a0fd.tar.xz systemd-80a2381d5c156cffedf41a3e7b95f7a00045a0fd.zip |
bootctl: add --root and --image
Operate on image/directory, and also take files to install from it
Diffstat (limited to 'src')
-rw-r--r-- | src/boot/bless-boot.c | 4 | ||||
-rw-r--r-- | src/boot/bootctl.c | 164 | ||||
-rw-r--r-- | src/fuzz/fuzz-bootspec.c | 2 | ||||
-rw-r--r-- | src/shared/bootspec.c | 12 | ||||
-rw-r--r-- | src/shared/bootspec.h | 2 | ||||
-rw-r--r-- | src/shared/find-esp.c | 135 | ||||
-rw-r--r-- | src/shared/find-esp.h | 4 | ||||
-rw-r--r-- | src/systemctl/systemctl-start-special.c | 2 |
8 files changed, 238 insertions, 87 deletions
diff --git a/src/boot/bless-boot.c b/src/boot/bless-boot.c index d9c901d73b..315a1a37ed 100644 --- a/src/boot/bless-boot.c +++ b/src/boot/bless-boot.c @@ -108,11 +108,11 @@ static int acquire_path(void) { if (!strv_isempty(arg_path)) return 0; - r = find_esp_and_warn(NULL, /* unprivileged_mode= */ false, &esp_path, NULL, NULL, NULL, NULL, &esp_devid); + r = find_esp_and_warn(NULL, NULL, /* unprivileged_mode= */ false, &esp_path, NULL, NULL, NULL, NULL, &esp_devid); if (r < 0 && r != -ENOKEY) /* ENOKEY means not found, and is the only error the function won't log about on its own */ return r; - r = find_xbootldr_and_warn(NULL, /* unprivileged_mode= */ false, &xbootldr_path, NULL, &xbootldr_devid); + r = find_xbootldr_and_warn(NULL, NULL, /* unprivileged_mode= */ false, &xbootldr_path, NULL, &xbootldr_devid); if (r < 0 && r != -ENOKEY) return r; diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index e50f96cb2f..6cb0f42539 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -15,9 +15,11 @@ #include "alloc-util.h" #include "blkid-util.h" #include "bootspec.h" +#include "chase-symlinks.h" #include "copy.h" #include "devnum-util.h" #include "dirent-util.h" +#include "dissect-image.h" #include "efi-api.h" #include "efi-loader.h" #include "efivars.h" @@ -31,6 +33,7 @@ #include "glyph-util.h" #include "main-func.h" #include "mkdir.h" +#include "mount-util.h" #include "os-util.h" #include "pager.h" #include "parse-argument.h" @@ -75,11 +78,15 @@ static enum { static char *arg_entry_token = NULL; static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; static bool arg_arch_all = false; +static char *arg_root = NULL; +static char *arg_image = NULL; STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep); STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep); STATIC_DESTRUCTOR_REGISTER(arg_install_layout, freep); STATIC_DESTRUCTOR_REGISTER(arg_entry_token, freep); +STATIC_DESTRUCTOR_REGISTER(arg_root, freep); +STATIC_DESTRUCTOR_REGISTER(arg_image, freep); static const char *arg_dollar_boot_path(void) { /* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */ @@ -104,7 +111,7 @@ static int acquire_esp( * we simply eat up the error here, so that --list and --status work too, without noise about * this). */ - r = find_esp_and_warn(arg_esp_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid); + r = find_esp_and_warn(arg_root, arg_esp_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid); if (r == -ENOKEY) { if (graceful) return log_full_errno(arg_quiet ? LOG_DEBUG : LOG_INFO, r, @@ -131,7 +138,7 @@ static int acquire_xbootldr( char *np; int r; - r = find_xbootldr_and_warn(arg_xbootldr_path, unprivileged_mode, &np, ret_uuid, ret_devid); + r = find_xbootldr_and_warn(arg_root, arg_xbootldr_path, unprivileged_mode, &np, ret_uuid, ret_devid); if (r == -ENOKEY) { log_debug_errno(r, "Didn't find an XBOOTLDR partition, using the ESP as $BOOT."); arg_xbootldr_path = mfree(arg_xbootldr_path); @@ -596,7 +603,6 @@ static int boot_config_load_and_select( const char *xbootldr_path, dev_t xbootldr_devid) { - _cleanup_strv_free_ char **efi_entries = NULL; int r; /* If XBOOTLDR and ESP actually refer to the same block device, suppress XBOOTLDR, since it would @@ -607,15 +613,19 @@ static int boot_config_load_and_select( if (r < 0) return r; - r = efi_loader_get_entries(&efi_entries); - if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r)) - log_debug_errno(r, "Boot loader reported no entries."); - else if (r < 0) - log_warning_errno(r, "Failed to determine entries reported by boot loader, ignoring: %m"); - else - (void) boot_config_augment_from_loader(config, efi_entries, /* only_auto= */ false); + if (!arg_root) { + _cleanup_strv_free_ char **efi_entries = NULL; - return boot_config_select_special_entries(config); + r = efi_loader_get_entries(&efi_entries); + if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r)) + log_debug_errno(r, "Boot loader reported no entries."); + else if (r < 0) + log_warning_errno(r, "Failed to determine entries reported by boot loader, ignoring: %m"); + else + (void) boot_config_augment_from_loader(config, efi_entries, /* only_auto= */ false); + } + + return boot_config_select_special_entries(config, /* skip_efivars= */ !!arg_root); } static int status_entries( @@ -833,48 +843,74 @@ static int create_subdirs(const char *root, const char * const *subdirs) { } static int copy_one_file(const char *esp_path, const char *name, bool force) { + _cleanup_free_ char *source_path = NULL, *dest_path = NULL, *p = NULL, *q = NULL; const char *e; - char *p, *q, *dest_name, *s; - int r; + char *dest_name, *s; + int r, ret; dest_name = strdupa_safe(name); s = endswith_no_case(dest_name, ".signed"); if (s) *s = 0; - p = strjoina(BOOTLIBDIR "/", name); - q = strjoina(esp_path, "/EFI/systemd/", dest_name); - r = copy_file_with_version_check(p, q, force); + p = path_join(BOOTLIBDIR, name); + if (!p) + return log_oom(); + + r = chase_symlinks(p, arg_root, CHASE_PREFIX_ROOT, &source_path, NULL); + if (r < 0) + return log_error_errno(r, + "Failed to resolve path %s%s%s: %m", + p, + arg_root ? " under directory " : "", + arg_root ? arg_root : ""); + + q = path_join("/EFI/systemd/", dest_name); + if (!q) + return log_oom(); + + r = chase_symlinks(q, esp_path, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &dest_path, NULL); + if (r < 0) + return log_error_errno(r, "Failed to resolve path %s under directory %s: %m", q, esp_path); + + /* Note that if this fails we do the second copy anyway, but return this error code, + * so we stash it away in a separate variable. */ + ret = copy_file_with_version_check(source_path, dest_path, force); e = startswith(dest_name, "systemd-boot"); if (e) { - int k; + _cleanup_free_ char *default_dest_path = NULL; char *v; /* Create the EFI default boot loader name (specified for removable devices) */ - v = strjoina(esp_path, "/EFI/BOOT/BOOT", e); + v = strjoina("/EFI/BOOT/BOOT", e); ascii_strupper(strrchr(v, '/') + 1); - k = copy_file_with_version_check(p, v, force); - if (k < 0 && r == 0) - r = k; + r = chase_symlinks(v, esp_path, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &default_dest_path, NULL); + if (r < 0) + return log_error_errno(r, "Failed to resolve path %s under directory %s: %m", v, esp_path); + + r = copy_file_with_version_check(source_path, default_dest_path, force); + if (r < 0 && ret == 0) + ret = r; } - return r; + return ret; } static int install_binaries(const char *esp_path, const char *arch, bool force) { _cleanup_closedir_ DIR *d = NULL; - int r = 0; + _cleanup_free_ char *path = NULL; + int r; - d = opendir(BOOTLIBDIR); - if (!d) - return log_error_errno(errno, "Failed to open \""BOOTLIBDIR"\": %m"); + r = chase_symlinks_and_opendir(BOOTLIBDIR, arg_root, CHASE_PREFIX_ROOT, &path, &d); + if (r < 0) + return log_error_errno(r, "Failed to open boot loader directory %s: %m", BOOTLIBDIR); const char *suffix = strjoina(arch, ".efi"); const char *suffix_signed = strjoina(arch, ".efi.signed"); - FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read \""BOOTLIBDIR"\": %m")) { + FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read \"%s\": %m", path)) { int k; if (!endswith_no_case(de->d_name, suffix) && !endswith_no_case(de->d_name, suffix_signed)) @@ -1022,6 +1058,12 @@ static int install_variables(const char *esp_path, uint16_t slot; int r; + if (arg_root) { + log_info("Acting on %s, skipping EFI variable setup.", + arg_image ? "image" : "root directory"); + return 0; + } + if (!is_efi_boot()) { log_warning("Not booted with EFI, skipping EFI variable setup."); return 0; @@ -1178,7 +1220,7 @@ static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) { uint16_t slot; int r; - if (!is_efi_boot()) + if (arg_root || !is_efi_boot()) return 0; r = find_slot(uuid, path, &slot); @@ -1350,6 +1392,8 @@ static int help(int argc, char *argv[], void *userdata) { " --version Print version\n" " --esp-path=PATH Path to the EFI System Partition (ESP)\n" " --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" " -p --print-esp-path Print path to the EFI System Partition\n" " -x --print-boot-path Print path to the $BOOT partition\n" " --no-variables Don't touch EFI variables\n" @@ -1380,6 +1424,8 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_ESP_PATH = 0x100, ARG_BOOT_PATH, + ARG_ROOT, + ARG_IMAGE, ARG_VERSION, ARG_NO_VARIABLES, ARG_NO_PAGER, @@ -1396,6 +1442,8 @@ static int parse_argv(int argc, char *argv[]) { { "esp-path", required_argument, NULL, ARG_ESP_PATH }, { "path", required_argument, NULL, ARG_ESP_PATH }, /* Compatibility alias */ { "boot-path", required_argument, NULL, ARG_BOOT_PATH }, + { "root", required_argument, NULL, ARG_ROOT }, + { "image", required_argument, NULL, ARG_IMAGE }, { "print-esp-path", no_argument, NULL, 'p' }, { "print-path", no_argument, NULL, 'p' }, /* Compatibility alias */ { "print-boot-path", no_argument, NULL, 'x' }, @@ -1439,6 +1487,18 @@ static int parse_argv(int argc, char *argv[]) { return log_oom(); break; + case ARG_ROOT: + r = parse_path_argument(optarg, /* suppress_root= */ true, &arg_root); + if (r < 0) + return r; + break; + + case ARG_IMAGE: + r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_image); + if (r < 0) + return r; + break; + case 'p': if (arg_print_dollar_boot_path) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), @@ -1523,6 +1583,15 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached(); } + if ((arg_root || arg_image) && argv[optind] && !STR_IN_SET(argv[optind], "status", "list", + "install", "update", "remove", "is-installed", "random-seed")) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Options --root= and --image= are not supported with verb %s.", + argv[optind]); + + if (arg_root && arg_image) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Please specify either --root= or --image=, the combination of both is not supported."); + return 1; } @@ -1608,7 +1677,7 @@ static int verb_status(int argc, char *argv[], void *userdata) { pager_open(arg_pager_flags); - if (is_efi_boot()) { + if (!arg_root && is_efi_boot()) { static const struct { uint64_t flag; const char *name; @@ -1722,7 +1791,7 @@ static int verb_status(int argc, char *argv[], void *userdata) { r = k; } - if (is_efi_boot()) { + if (!arg_root && is_efi_boot()) { k = status_variables(); if (k < 0) r = k; @@ -1846,6 +1915,12 @@ static int install_random_seed(const char *esp) { return 0; } + if (arg_root) { + log_warning("Acting on %s, skipping EFI variable setup.", + arg_image ? "image" : "root directory"); + return 0; + } + r = getenv_bool("SYSTEMD_WRITE_SYSTEM_TOKEN"); if (r < 0) { if (r != -ENXIO) @@ -2204,6 +2279,11 @@ static int parse_loader_entry_target_arg(const char *arg1, char16_t **ret_target static int verb_set_efivar(int argc, char *argv[], void *userdata) { int r; + if (arg_root) + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "Acting on %s, skipping EFI variable setup.", + arg_image ? "image" : "root directory"); + if (!is_efi_boot()) return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Not booted with UEFI."); @@ -2267,7 +2347,7 @@ static int verb_set_efivar(int argc, char *argv[], void *userdata) { static int verb_random_seed(int argc, char *argv[], void *userdata) { int r; - r = find_esp_and_warn(arg_esp_path, false, &arg_esp_path, NULL, NULL, NULL, NULL, NULL); + r = find_esp_and_warn(arg_root, arg_esp_path, false, &arg_esp_path, NULL, NULL, NULL, NULL, NULL); if (r == -ENOKEY) { /* find_esp_and_warn() doesn't warn about ENOKEY, so let's do that on our own */ if (!arg_graceful) @@ -2375,6 +2455,9 @@ static int bootctl_main(int argc, char *argv[]) { } static int run(int argc, char *argv[]) { + _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL; + _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL; + _cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL; int r; log_parse_environment(); @@ -2388,6 +2471,25 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; + /* Open up and mount the image */ + if (arg_image) { + assert(!arg_root); + + r = mount_image_privately_interactively( + arg_image, + DISSECT_IMAGE_GENERIC_ROOT | + DISSECT_IMAGE_RELAX_VAR_CHECK, + &unlink_dir, + &loop_device, + &decrypted_image); + if (r < 0) + return r; + + arg_root = strdup(unlink_dir); + if (!arg_root) + return log_oom(); + } + return bootctl_main(argc, argv); } diff --git a/src/fuzz/fuzz-bootspec.c b/src/fuzz/fuzz-bootspec.c index c26cc94db9..c08f76c14a 100644 --- a/src/fuzz/fuzz-bootspec.c +++ b/src/fuzz/fuzz-bootspec.c @@ -104,7 +104,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { assert_se(boot_config_finalize(&config) >= 0); - (void) boot_config_select_special_entries(&config); + (void) boot_config_select_special_entries(&config, /* skip_efivars= */ false); _cleanup_close_ int orig_stdout_fd = -1; if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0) { diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index 2c0ec6c272..1a47fff167 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -840,12 +840,12 @@ static int boot_entries_select_selected(const BootConfig *config) { return boot_config_find(config, config->entry_selected); } -static int boot_load_efi_entry_pointers(BootConfig *config) { +static int boot_load_efi_entry_pointers(BootConfig *config, bool skip_efivars) { int r; assert(config); - if (!is_efi_boot()) + if (skip_efivars || !is_efi_boot()) return 0; /* Loads the three "pointers" to boot loader entries from their EFI variables */ @@ -871,12 +871,12 @@ static int boot_load_efi_entry_pointers(BootConfig *config) { return 1; } -int boot_config_select_special_entries(BootConfig *config) { +int boot_config_select_special_entries(BootConfig *config, bool skip_efivars) { int r; assert(config); - r = boot_load_efi_entry_pointers(config); + r = boot_load_efi_entry_pointers(config, skip_efivars); if (r < 0) return r; @@ -967,11 +967,11 @@ int boot_config_load_auto( "Failed to determine whether /run/boot-loader-entries/ exists: %m"); } - r = find_esp_and_warn(override_esp_path, /* unprivileged_mode= */ false, &esp_where, NULL, NULL, NULL, NULL, &esp_devid); + r = find_esp_and_warn(NULL, override_esp_path, /* unprivileged_mode= */ false, &esp_where, NULL, NULL, NULL, NULL, &esp_devid); if (r < 0) /* we don't log about ENOKEY here, but propagate it, leaving it to the caller to log */ return r; - r = find_xbootldr_and_warn(override_xbootldr_path, /* unprivileged_mode= */ false, &xbootldr_where, NULL, &xbootldr_devid); + r = find_xbootldr_and_warn(NULL, override_xbootldr_path, /* unprivileged_mode= */ false, &xbootldr_where, NULL, &xbootldr_devid); if (r < 0 && r != -ENOKEY) return r; /* It's fine if the XBOOTLDR partition doesn't exist, hence we ignore ENOKEY here */ diff --git a/src/shared/bootspec.h b/src/shared/bootspec.h index ff54cc2e84..36a3489e87 100644 --- a/src/shared/bootspec.h +++ b/src/shared/bootspec.h @@ -100,7 +100,7 @@ int boot_config_load(BootConfig *config, const char *esp_path, const char *xboot int boot_config_load_auto(BootConfig *config, const char *override_esp_path, const char *override_xbootldr_path); int boot_config_augment_from_loader(BootConfig *config, char **list, bool only_auto); -int boot_config_select_special_entries(BootConfig *config); +int boot_config_select_special_entries(BootConfig *config, bool skip_efivars); static inline const char* boot_entry_title(const BootEntry *entry) { assert(entry); diff --git a/src/shared/find-esp.c b/src/shared/find-esp.c index ea27d7911a..87ac9d167e 100644 --- a/src/shared/find-esp.c +++ b/src/shared/find-esp.c @@ -8,6 +8,7 @@ #include "alloc-util.h" #include "blkid-util.h" +#include "chase-symlinks.h" #include "device-util.h" #include "devnum-util.h" #include "env-util.h" @@ -20,6 +21,12 @@ #include "string-util.h" #include "virt.h" +typedef enum VerifyESPFlags { + VERIFY_ESP_SEARCHING = 1 << 0, /* Downgrade various "not found" logs to debug level */ + VERIFY_ESP_UNPRIVILEGED_MODE = 1 << 1, /* Call into udev rather than blkid */ + VERIFY_ESP_RELAX_CHECKS = 1 << 2, /* Do not validate ESP partition */ +} VerifyESPFlags; + static int verify_esp_blkid( dev_t devid, bool searching, @@ -298,15 +305,15 @@ static int verify_fsroot_dir( static int verify_esp( const char *p, - bool searching, - bool unprivileged_mode, uint32_t *ret_part, uint64_t *ret_pstart, uint64_t *ret_psize, sd_id128_t *ret_uuid, - dev_t *ret_devid) { + dev_t *ret_devid, + VerifyESPFlags flags) { - bool relax_checks; + bool relax_checks, searching = FLAGS_SET(flags, VERIFY_ESP_SEARCHING), + unprivileged_mode = FLAGS_SET(flags, VERIFY_ESP_UNPRIVILEGED_MODE); dev_t devid; int r; @@ -319,7 +326,7 @@ static int verify_esp( * -EACESS → if 'unprivileged_mode' is set, and we have trouble accessing the thing */ - relax_checks = getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0; + relax_checks = getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0 || FLAGS_SET(flags, VERIFY_ESP_RELAX_CHECKS); /* Non-root user can only check the status, so if an error occurred in the following, it does not cause any * issues. Let's also, silence the error messages. */ @@ -381,6 +388,7 @@ finish: } int find_esp_and_warn( + const char *root, const char *path, bool unprivileged_mode, char **ret_path, @@ -390,6 +398,9 @@ int find_esp_and_warn( sd_id128_t *ret_uuid, dev_t *ret_devid) { + VerifyESPFlags flags = (unprivileged_mode ? VERIFY_ESP_UNPRIVILEGED_MODE : 0) | + (root ? VERIFY_ESP_RELAX_CHECKS : 0); + _cleanup_free_ char *p = NULL; int r; /* This logs about all errors except: @@ -399,7 +410,15 @@ int find_esp_and_warn( */ if (path) { - r = verify_esp(path, /* searching= */ false, unprivileged_mode, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid); + r = chase_symlinks(path, root, CHASE_PREFIX_ROOT, &p, NULL); + if (r < 0) + return log_error_errno(r, + "Failed to resolve path %s%s%s: %m", + path, + root ? " under directory " : "", + root ?: ""); + + r = verify_esp(p, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid, flags); if (r < 0) return r; @@ -410,19 +429,27 @@ int find_esp_and_warn( if (path) { struct stat st; - if (!path_is_valid(path) || !path_is_absolute(path)) + r = chase_symlinks(path, root, CHASE_PREFIX_ROOT, &p, NULL); + if (r < 0) + return log_error_errno(r, + "Failed to resolve path %s%s%s: %m", + path, + root ? " under directory " : "", + root ?: ""); + + if (!path_is_valid(p) || !path_is_absolute(p)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "$SYSTEMD_ESP_PATH does not refer to absolute path, refusing to use it: %s", - path); + p); /* Note: when the user explicitly configured things with an env var we won't validate the * path beyond checking it refers to a directory. After all we want this to be useful for * testing. */ - if (stat(path, &st) < 0) - return log_error_errno(errno, "Failed to stat '%s': %m", path); + if (stat(p, &st) < 0) + return log_error_errno(errno, "Failed to stat '%s': %m", p); if (!S_ISDIR(st.st_mode)) - return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR), "ESP path '%s' is not a directory.", path); + return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR), "ESP path '%s' is not a directory.", p); if (ret_part) *ret_part = 0; @@ -438,29 +465,33 @@ int find_esp_and_warn( goto found; } - FOREACH_STRING(_path, "/efi", "/boot", "/boot/efi") { - path = _path; - - r = verify_esp(path, /* searching= */ true, unprivileged_mode, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid); + FOREACH_STRING(dir, "/efi", "/boot", "/boot/efi") { + r = chase_symlinks(dir, root, CHASE_PREFIX_ROOT, &p, NULL); + if (r == -ENOENT) + continue; + if (r < 0) + return log_error_errno(r, + "Failed to resolve path %s%s%s: %m", + dir, + root ? " under directory " : "", + root ?: ""); + + r = verify_esp(p, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid, + flags | VERIFY_ESP_SEARCHING); if (r >= 0) goto found; if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */ return r; + + p = mfree(p); } /* No logging here */ return -ENOKEY; found: - if (ret_path) { - char *c; - - c = strdup(path); - if (!c) - return log_oom(); - - *ret_path = c; - } + if (ret_path) + *ret_path = TAKE_PTR(p); return 0; } @@ -662,18 +693,28 @@ finish: } int find_xbootldr_and_warn( + const char *root, const char *path, bool unprivileged_mode, char **ret_path, sd_id128_t *ret_uuid, dev_t *ret_devid) { + _cleanup_free_ char *p = NULL; int r; /* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */ if (path) { - r = verify_xbootldr(path, /* searching= */ false, unprivileged_mode, ret_uuid, ret_devid); + r = chase_symlinks(path, root, CHASE_PREFIX_ROOT, &p, NULL); + if (r < 0) + return log_error_errno(r, + "Failed to resolve path %s%s%s: %m", + path, + root ? " under directory " : "", + root ?: ""); + + r = verify_xbootldr(p, /* searching= */ false, unprivileged_mode, ret_uuid, ret_devid); if (r < 0) return r; @@ -684,15 +725,23 @@ int find_xbootldr_and_warn( if (path) { struct stat st; - if (!path_is_valid(path) || !path_is_absolute(path)) + r = chase_symlinks(path, root, CHASE_PREFIX_ROOT, &p, NULL); + if (r < 0) + return log_error_errno(r, + "Failed to resolve path %s%s%s: %m", + path, + root ? " under directory " : "", + root ?: ""); + + if (!path_is_valid(p) || !path_is_absolute(p)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "$SYSTEMD_XBOOTLDR_PATH does not refer to absolute path, refusing to use it: %s", - path); + p); - if (stat(path, &st) < 0) - return log_error_errno(errno, "Failed to stat '%s': %m", path); + if (stat(p, &st) < 0) + return log_error_errno(errno, "Failed to stat '%s': %m", p); if (!S_ISDIR(st.st_mode)) - return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR), "XBOOTLDR path '%s' is not a directory.", path); + return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR), "XBOOTLDR path '%s' is not a directory.", p); if (ret_uuid) *ret_uuid = SD_ID128_NULL; @@ -702,26 +751,26 @@ int find_xbootldr_and_warn( goto found; } - r = verify_xbootldr("/boot", true, unprivileged_mode, ret_uuid, ret_devid); - if (r >= 0) { - path = "/boot"; + r = chase_symlinks("/boot", root, CHASE_PREFIX_ROOT, &p, NULL); + if (r == -ENOENT) + return -ENOKEY; + if (r < 0) + return log_error_errno(r, + "Failed to resolve path /boot%s%s: %m", + root ? " under directory " : "", + root ?: ""); + + r = verify_xbootldr(p, true, unprivileged_mode, ret_uuid, ret_devid); + if (r >= 0) goto found; - } if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */ return r; return -ENOKEY; found: - if (ret_path) { - char *c; - - c = strdup(path); - if (!c) - return log_oom(); - - *ret_path = c; - } + if (ret_path) + *ret_path = TAKE_PTR(p); return 0; } diff --git a/src/shared/find-esp.h b/src/shared/find-esp.h index e4e65ac3e2..78d7f4551e 100644 --- a/src/shared/find-esp.h +++ b/src/shared/find-esp.h @@ -8,5 +8,5 @@ #include "sd-id128.h" -int find_esp_and_warn(const char *path, bool unprivileged_mode, char **ret_path, uint32_t *ret_part, uint64_t *ret_pstart, uint64_t *ret_psize, sd_id128_t *ret_uuid, dev_t *ret_devid); -int find_xbootldr_and_warn(const char *path, bool unprivileged_mode, char **ret_path, sd_id128_t *ret_uuid, dev_t *ret_devid); +int find_esp_and_warn(const char *root, const char *path, bool unprivileged_mode, char **ret_path, uint32_t *ret_part, uint64_t *ret_pstart, uint64_t *ret_psize, sd_id128_t *ret_uuid, dev_t *ret_devid); +int find_xbootldr_and_warn(const char *root, const char *path, bool unprivileged_mode, char **ret_path, sd_id128_t *ret_uuid, dev_t *ret_devid); diff --git a/src/systemctl/systemctl-start-special.c b/src/systemctl/systemctl-start-special.c index cfd0078964..9363764cd7 100644 --- a/src/systemctl/systemctl-start-special.c +++ b/src/systemctl/systemctl-start-special.c @@ -43,7 +43,7 @@ static int load_kexec_kernel(void) { if (r < 0) return r; - r = boot_config_select_special_entries(&config); + r = boot_config_select_special_entries(&config, /* skip_efivars= */ false); if (r < 0) return r; |