diff options
author | Lennart Poettering <lennart@poettering.net> | 2022-09-07 18:19:46 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2022-09-08 13:14:05 +0200 |
commit | 2683ae2d73b7afad50dc43c8dc9433478a8e73cc (patch) | |
tree | f27029bf7fd714d1933e2ad7e14966c73e2ecb51 /src/shared/bootspec.c | |
parent | update TODO (diff) | |
download | systemd-2683ae2d73b7afad50dc43c8dc9433478a8e73cc.tar.xz systemd-2683ae2d73b7afad50dc43c8dc9433478a8e73cc.zip |
bootspec: use chase_symlinks() where appropriate
Let's better be safe than sorry, and follow symlinks in ESP + XBOOTLDR
via chase_symlinks() relative to the root of these files systems. This is
not a big issue given that ESP/XBOOTLDR are supposed to be VFAT where
symlinks don't exist, but the specs don't strictly require this, and by
loading efifs drivers in uefi it would be possible to support symlinks,
but we'd rather not have that here.
No real change in behaviour, just stricter rules to make me sleep better
at night.
Diffstat (limited to '')
-rw-r--r-- | src/shared/bootspec.c | 95 |
1 files changed, 43 insertions, 52 deletions
diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index 33f2ea6652..7ca218f955 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -4,6 +4,7 @@ #include "bootspec-fundamental.h" #include "bootspec.h" +#include "chase-symlinks.h" #include "conf-files.h" #include "devnum-util.h" #include "dirent-util.h" @@ -498,21 +499,21 @@ int boot_loader_read_conf(BootConfig *config, FILE *file, const char *path) { return 1; } -static int boot_loader_read_conf_path(BootConfig *config, const char *path) { +static int boot_loader_read_conf_path(BootConfig *config, const char *root, const char *path) { + _cleanup_free_ char *full = NULL; _cleanup_fclose_ FILE *f = NULL; + int r; assert(config); assert(path); - f = fopen(path, "re"); - if (!f) { - if (errno == ENOENT) - return 0; - - return log_error_errno(errno, "Failed to open \"%s\": %m", path); - } + r = chase_symlinks_and_fopen_unlocked(path, root, CHASE_PREFIX_ROOT, "re", &full, &f); + if (r == -ENOENT) + return 0; + if (r < 0) + return log_error_errno(r, "Failed to open '%s/%s': %m", root, path); - return boot_loader_read_conf(config, f, path); + return boot_loader_read_conf(config, f, full); } static int boot_entry_compare(const BootEntry *a, const BootEntry *b) { @@ -600,6 +601,7 @@ static int boot_entries_find_type1( const char *dir) { _cleanup_free_ DirectoryEntries *dentries = NULL; + _cleanup_free_ char *full = NULL; _cleanup_close_ int dir_fd = -1; int r; @@ -607,17 +609,15 @@ static int boot_entries_find_type1( assert(root); assert(dir); - dir_fd = open(dir, O_DIRECTORY|O_CLOEXEC); - if (dir_fd < 0) { - if (errno == ENOENT) - return 0; - - return log_error_errno(errno, "Failed to open '%s': %m", dir); - } + dir_fd = chase_symlinks_and_open(dir, root, CHASE_PREFIX_ROOT, O_DIRECTORY|O_CLOEXEC, &full); + if (dir_fd == -ENOENT) + return 0; + if (dir_fd < 0) + return log_error_errno(dir_fd, "Failed to open '%s/%s': %m", root, dir); r = readdir_all(dir_fd, RECURSE_DIR_IGNORE_DOT, &dentries); if (r < 0) - return log_error_errno(r, "Failed to read directory '%s': %m", dir); + return log_error_errno(r, "Failed to read directory '%s': %m", full); for (size_t i = 0; i < dentries->n_entries; i++) { const struct dirent *de = dentries->entries[i]; @@ -631,7 +631,7 @@ static int boot_entries_find_type1( r = xfopenat(dir_fd, de->d_name, "re", 0, &f); if (r < 0) { - log_warning_errno(r, "Failed to open %s/%s, ignoring: %m", dir, de->d_name); + log_warning_errno(r, "Failed to open %s/%s, ignoring: %m", full, de->d_name); continue; } @@ -641,7 +641,7 @@ static int boot_entries_find_type1( if (r == 0) /* inode already seen or otherwise not relevant */ continue; - r = boot_config_load_type1(config, f, root, dir, de->d_name); + r = boot_config_load_type1(config, f, root, full, de->d_name); if (r == -ENOMEM) /* ignore all other errors */ return r; } @@ -863,20 +863,19 @@ static int boot_entries_find_unified( const char *dir) { _cleanup_(closedirp) DIR *d = NULL; + _cleanup_free_ char *full = NULL; int r; assert(config); assert(dir); - d = opendir(dir); - if (!d) { - if (errno == ENOENT) - return 0; - - return log_error_errno(errno, "Failed to open %s: %m", dir); - } + r = chase_symlinks_and_opendir(dir, root, CHASE_PREFIX_ROOT, &full, &d); + if (r == -ENOENT) + return 0; + if (r < 0) + return log_error_errno(r, "Failed to open '%s/%s': %m", root, dir); - FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read %s: %m", dir)) { + FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read %s: %m", full)) { _cleanup_free_ char *j = NULL, *osrelease = NULL, *cmdline = NULL; _cleanup_close_ int fd = -1; @@ -891,7 +890,7 @@ static int boot_entries_find_unified( fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC|O_NONBLOCK); if (fd < 0) { - log_warning_errno(errno, "Failed to open %s/%s, ignoring: %m", dir, de->d_name); + log_warning_errno(errno, "Failed to open %s/%s, ignoring: %m", full, de->d_name); continue; } @@ -901,7 +900,7 @@ static int boot_entries_find_unified( if (r == 0) /* inode already seen or otherwise not relevant */ continue; - j = path_join(dir, de->d_name); + j = path_join(full, de->d_name); if (!j) return log_oom(); @@ -1117,36 +1116,30 @@ int boot_config_load( const char *esp_path, const char *xbootldr_path) { - const char *p; int r; assert(config); if (esp_path) { - p = strjoina(esp_path, "/loader/loader.conf"); - r = boot_loader_read_conf_path(config, p); + r = boot_loader_read_conf_path(config, esp_path, "/loader/loader.conf"); if (r < 0) return r; - p = strjoina(esp_path, "/loader/entries"); - r = boot_entries_find_type1(config, esp_path, p); + r = boot_entries_find_type1(config, esp_path, "/loader/entries"); if (r < 0) return r; - p = strjoina(esp_path, "/EFI/Linux/"); - r = boot_entries_find_unified(config, esp_path, p); + r = boot_entries_find_unified(config, esp_path, "/EFI/Linux/"); if (r < 0) return r; } if (xbootldr_path) { - p = strjoina(xbootldr_path, "/loader/entries"); - r = boot_entries_find_type1(config, xbootldr_path, p); + r = boot_entries_find_type1(config, xbootldr_path, "/loader/entries"); if (r < 0) return r; - p = strjoina(xbootldr_path, "/EFI/Linux/"); - r = boot_entries_find_unified(config, xbootldr_path, p); + r = boot_entries_find_unified(config, xbootldr_path, "/EFI/Linux/"); if (r < 0) return r; } @@ -1262,16 +1255,6 @@ int boot_config_augment_from_loader( return 0; } -static int boot_entry_file_check(const char *root, const char *p) { - _cleanup_free_ char *path = NULL; - - path = path_join(root, p); - if (!path) - return log_oom(); - - return RET_NERRNO(access(path, F_OK)); -} - BootEntry* boot_config_find_entry(BootConfig *config, const char *id) { assert(config); assert(id); @@ -1284,8 +1267,16 @@ BootEntry* boot_config_find_entry(BootConfig *config, const char *id) { return NULL; } -static void boot_entry_file_list(const char *field, const char *root, const char *p, int *ret_status) { - int status = boot_entry_file_check(root, p); +static void boot_entry_file_list( + const char *field, + const char *root, + const char *p, + int *ret_status) { + + assert(p); + assert(ret_status); + + int status = chase_symlinks_and_access(p, root, CHASE_PREFIX_ROOT, F_OK, NULL, NULL); printf("%13s%s ", strempty(field), field ? ":" : " "); if (status < 0) { |