diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index e733e206e40..52207661cf6 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -61,19 +61,33 @@ static char *arg_path = NULL; static bool arg_print_path = false; static bool arg_touch_variables = true; -static int find_esp_and_warn(uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) { +static int acquire_esp( + bool unprivileged_mode, + uint32_t *ret_part, + uint64_t *ret_pstart, + uint64_t *ret_psize, + sd_id128_t *ret_uuid) { + + char *np; int r; - r = find_esp(&arg_path, part, pstart, psize, uuid); - if (r == -ENOENT) + /* Find the ESP, and log about errors. Note that find_esp_and_warn() will log in all error cases on its own, + * except for ENOKEY (which is good, we want to show our own message in that case, suggesting use of --path=) + * and EACCESS (only when we request unprivileged mode; in this case we simply eat up the error here, so that + * --list and --status work too, without noise about this). */ + + r = find_esp_and_warn(arg_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid); + if (r == -ENOKEY) return log_error_errno(r, - "Couldn't find EFI system partition. It is recommended to mount it to /boot.\n" + "Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n" "Alternatively, use --path= to specify path to mount point."); - else if (r < 0) - return log_error_errno(r, - "Couldn't find EFI system partition: %m"); + if (r < 0) + return r; + + free_and_replace(arg_path, np); log_debug("Using EFI System Partition at %s.", arg_path); + return 0; } @@ -925,9 +939,12 @@ static int verb_status(int argc, char *argv[], void *userdata) { sd_id128_t uuid = SD_ID128_NULL; int r, k; - r = find_esp_and_warn(NULL, NULL, NULL, &uuid); + r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid); if (arg_print_path) { + if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only + * error the find_esp_and_warn() won't log on its own) */ + return log_error_errno(r, "Failed to determine ESP: %m"); if (r < 0) return r; @@ -935,6 +952,9 @@ static int verb_status(int argc, char *argv[], void *userdata) { return 0; } + r = 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just show what we + * can show */ + if (is_efi_boot()) { _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL; sd_id128_t loader_part_uuid = SD_ID128_NULL; @@ -997,13 +1017,18 @@ static int verb_status(int argc, char *argv[], void *userdata) { } static int verb_list(int argc, char *argv[], void *userdata) { - sd_id128_t uuid = SD_ID128_NULL; - int r; - unsigned n; - _cleanup_(boot_config_free) BootConfig config = {}; + sd_id128_t uuid = SD_ID128_NULL; + unsigned n; + int r; - r = find_esp_and_warn(NULL, NULL, NULL, &uuid); + /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn + * off logging about access errors and turn off potentially privileged device probing. Here we're interested in + * the latter but not the former, hence request the mode, and log about EACCES. */ + + r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid); + if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */ + return log_error_errno(r, "Failed to determine ESP: %m"); if (r < 0) return r; @@ -1071,7 +1096,7 @@ static int verb_install(int argc, char *argv[], void *userdata) { if (r < 0) return r; - r = find_esp_and_warn(&part, &pstart, &psize, &uuid); + r = acquire_esp(false, &part, &pstart, &psize, &uuid); if (r < 0) return r; @@ -1106,7 +1131,7 @@ static int verb_remove(int argc, char *argv[], void *userdata) { if (r < 0) return r; - r = find_esp_and_warn(NULL, NULL, NULL, &uuid); + r = acquire_esp(false, NULL, NULL, NULL, &uuid); if (r < 0) return r; diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index dea3c5212ad..acd9711839b 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -413,8 +413,9 @@ int boot_entries_load_config(const char *esp_path, BootConfig *config) { /********************************************************************************/ static int verify_esp( - bool searching, const char *p, + bool searching, + bool unprivileged_mode, uint32_t *ret_part, uint64_t *ret_pstart, uint64_t *ret_psize, @@ -430,21 +431,19 @@ static int verify_esp( struct statfs sfs; sd_id128_t uuid = SD_ID128_NULL; uint32_t part = 0; - bool quiet; int r; assert(p); - /* Non-root user can only check the status, so if an error occured in the following, - * it does not cause any issues. Let's silence the error messages. */ - quiet = geteuid() != 0; + /* Non-root user can only check the status, so if an error occured in the following, it does not cause any + * issues. Let's also, silence the error messages. */ if (statfs(p, &sfs) < 0) { /* If we are searching for the mount point, don't generate a log message if we can't find the path */ if (errno == ENOENT && searching) return -ENOENT; - return log_full_errno(quiet && errno == EACCES ? LOG_DEBUG : LOG_ERR, errno, + return log_full_errno(unprivileged_mode && errno == EACCES ? LOG_DEBUG : LOG_ERR, errno, "Failed to check file system type of \"%s\": %m", p); } @@ -457,7 +456,7 @@ static int verify_esp( } if (stat(p, &st) < 0) - return log_full_errno(quiet && errno == EACCES ? LOG_DEBUG : LOG_ERR, errno, + return log_full_errno(unprivileged_mode && errno == EACCES ? LOG_DEBUG : LOG_ERR, errno, "Failed to determine block device node of \"%s\": %m", p); if (major(st.st_dev) == 0) { @@ -468,7 +467,7 @@ static int verify_esp( t2 = strjoina(p, "/.."); r = stat(t2, &st2); if (r < 0) - return log_full_errno(quiet && errno == EACCES ? LOG_DEBUG : LOG_ERR, errno, + return log_full_errno(unprivileged_mode && errno == EACCES ? LOG_DEBUG : LOG_ERR, errno, "Failed to determine block device node of parent of \"%s\": %m", p); if (st.st_dev == st2.st_dev) { @@ -478,7 +477,7 @@ static int verify_esp( /* In a container we don't have access to block devices, skip this part of the verification, we trust the * container manager set everything up correctly on its own. Also skip the following verification for non-root user. */ - if (detect_container() > 0 || geteuid() != 0) + if (detect_container() > 0 || unprivileged_mode) goto finish; #if HAVE_BLKID @@ -579,29 +578,53 @@ finish: return 0; } -int find_esp(char **path, - uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) { +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) { - const char *p; int r; - if (*path) - return verify_esp(false, *path, part, pstart, psize, uuid); + /* This logs about all errors except: + * + * -ENOKEY → when we can't find the partition + * -EACCESS → when unprivileged_mode is true, and we can't access something + */ - FOREACH_STRING(p, "/efi", "/boot", "/boot/efi") { - - r = verify_esp(true, p, part, pstart, psize, uuid); - if (IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */ - continue; + if (path) { + r = verify_esp(path, false, unprivileged_mode, ret_part, ret_pstart, ret_psize, ret_uuid); if (r < 0) return r; - *path = strdup(p); - if (!*path) - return log_oom(); - - return 0; + goto found; } - return -ENOENT; + FOREACH_STRING(path, "/efi", "/boot", "/boot/efi") { + + r = verify_esp(path, true, unprivileged_mode, ret_part, ret_pstart, ret_psize, ret_uuid); + if (r >= 0) + goto found; + if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */ + return r; + } + + /* No logging here */ + return -ENOKEY; + +found: + if (ret_path) { + char *c; + + c = strdup(path); + if (!c) + return log_oom(); + + *ret_path = c; + } + + return 0; } diff --git a/src/shared/bootspec.h b/src/shared/bootspec.h index fb8c10a69ae..d9c641bf081 100644 --- a/src/shared/bootspec.h +++ b/src/shared/bootspec.h @@ -61,5 +61,4 @@ static inline const char* boot_entry_title(const BootEntry *entry) { return entry->show_title ?: entry->title ?: entry->filename; } -int find_esp(char **path, - uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid); +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); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 33fbaf99501..0a39a7e26c7 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3497,7 +3497,7 @@ static int prepare_firmware_setup(void) { static int load_kexec_kernel(void) { _cleanup_(boot_config_free) BootConfig config = {}; - _cleanup_free_ char *kernel = NULL, *initrd = NULL, *options = NULL; + _cleanup_free_ char *where = NULL, *kernel = NULL, *initrd = NULL, *options = NULL; const BootEntry *e; pid_t pid; int r; @@ -3507,14 +3507,15 @@ static int load_kexec_kernel(void) { return 0; } - r = find_esp(&arg_esp_path, NULL, NULL, NULL, NULL); - if (r < 0) - return log_error_errno(r, "Cannot find the ESP partition mount point: %m"); + r = find_esp_and_warn(arg_esp_path, false, &where, NULL, NULL, NULL, NULL); + if (r == -ENOKEY) /* find_esp_and_warn() doesn't warn about this case */ + return log_error_errno(r, "Cannot find the ESP partition mount point."); + if (r < 0) /* But it logs about all these cases, hence don't log here again */ + return r; - r = boot_entries_load_config(arg_esp_path, &config); + r = boot_entries_load_config(where, &config); if (r < 0) - return log_error_errno(r, "Failed to load bootspec config from \"%s/loader\": %m", - arg_esp_path); + return log_error_errno(r, "Failed to load bootspec config from \"%s/loader\": %m", where); if (config.default_entry < 0) { log_error("No entry suitable as default, refusing to guess."); @@ -3527,9 +3528,9 @@ static int load_kexec_kernel(void) { return -EINVAL; } - kernel = path_join(NULL, arg_esp_path, e->kernel); + kernel = path_join(NULL, where, e->kernel); if (!strv_isempty(e->initrd)) - initrd = path_join(NULL, arg_esp_path, *e->initrd); + initrd = path_join(NULL, where, *e->initrd); options = strv_join(e->options, " "); if (!options) return log_oom();