summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdrian Vovk <adrianvovk@gmail.com>2024-10-01 22:54:22 +0200
committerAdrian Vovk <adrianvovk@gmail.com>2024-11-27 04:25:29 +0100
commitf2751d757f76f6e50e452431815370a3a45fdfc0 (patch)
tree272bd82e216b21ad3586366b3a336436ea0744e4 /src
parentbootspec: Fixup loading of local addons for UKIs (diff)
downloadsystemd-f2751d757f76f6e50e452431815370a3a45fdfc0.tar.xz
systemd-f2751d757f76f6e50e452431815370a3a45fdfc0.zip
bootspec: Look at /loader/addons in XBOOTLDR
The bootspec util-lib's handling of global addons didn't previously match the behavior of sd-stub, and this commit corrects that. First, bootspec didn't load global addons from the XBOOTLDR dir, but the stub does. So, bootspec now enumerates addons in XBOOTLDR, not just ESP Second, the stub only loads resources (including addons) from the partition that it was found on. Thus, we must keep track of which partition the global addons come from, and which partition each boot entry comes from. In other words: global addons found on the ESP will NOT apply to UKIs found in XBOOTLDR, and bootspec now reflects that.
Diffstat (limited to 'src')
-rw-r--r--src/bootctl/bootctl-status.c1
-rw-r--r--src/fuzz/fuzz-bootspec.c2
-rw-r--r--src/shared/bootspec.c85
-rw-r--r--src/shared/bootspec.h19
4 files changed, 77 insertions, 30 deletions
diff --git a/src/bootctl/bootctl-status.c b/src/bootctl/bootctl-status.c
index 229c1ad535..6bcb348935 100644
--- a/src/bootctl/bootctl-status.c
+++ b/src/bootctl/bootctl-status.c
@@ -92,7 +92,6 @@ static int status_entries(
r = show_boot_entry(
boot_config_default_entry(config),
- &config->global_addons,
/* show_as_default= */ false,
/* show_as_selected= */ false,
/* show_discovered= */ false);
diff --git a/src/fuzz/fuzz-bootspec.c b/src/fuzz/fuzz-bootspec.c
index e49acafe31..561deb5977 100644
--- a/src/fuzz/fuzz-bootspec.c
+++ b/src/fuzz/fuzz-bootspec.c
@@ -55,7 +55,7 @@ static int json_dispatch_entries(const char *name, sd_json_variant *variant, sd_
_cleanup_fclose_ FILE *f = NULL;
assert_se(f = data_to_file((const uint8_t*) data, len));
- assert_se(boot_config_load_type1(config, f, "/", "/entries", id) != -ENOMEM);
+ assert_se(boot_config_load_type1(config, f, "/", BOOT_ENTRY_ESP, "/entries", id) != -ENOMEM);
}
}
diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c
index 6672c69f57..9c4877055a 100644
--- a/src/shared/bootspec.c
+++ b/src/shared/bootspec.c
@@ -44,6 +44,20 @@ static const char* const boot_entry_type_json_table[_BOOT_ENTRY_TYPE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_type_json, BootEntryType);
+static const char* const boot_entry_source_table[_BOOT_ENTRY_SOURCE_MAX] = {
+ [BOOT_ENTRY_ESP] = "EFI System Partition",
+ [BOOT_ENTRY_XBOOTLDR] = "Extended Boot Loader Partition",
+};
+
+DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_source, BootEntrySource);
+
+static const char* const boot_entry_source_json_table[_BOOT_ENTRY_SOURCE_MAX] = {
+ [BOOT_ENTRY_ESP] = "esp",
+ [BOOT_ENTRY_XBOOTLDR] = "xbootldr",
+};
+
+DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_source_json, BootEntrySource);
+
static void boot_entry_addons_done(BootEntryAddons *addons);
static void boot_entry_free(BootEntry *entry) {
@@ -285,11 +299,12 @@ nothing:
static int boot_entry_load_type1(
FILE *f,
const char *root,
+ const BootEntrySource source,
const char *dir,
const char *fname,
BootEntry *entry) {
- _cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_CONF);
+ _cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_CONF, source);
char *c;
int r;
@@ -395,6 +410,7 @@ int boot_config_load_type1(
BootConfig *config,
FILE *f,
const char *root,
+ const BootEntrySource source,
const char *dir,
const char *fname) {
int r;
@@ -408,10 +424,14 @@ int boot_config_load_type1(
if (!GREEDY_REALLOC0(config->entries, config->n_entries + 1))
return log_oom();
- r = boot_entry_load_type1(f, root, dir, fname, config->entries + config->n_entries);
+ BootEntry *entry = config->entries + config->n_entries;
+
+ r = boot_entry_load_type1(f, root, source, dir, fname, entry);
if (r < 0)
return r;
+ entry->global_addons = &config->global_addons[source];
+
config->n_entries++;
return 0;
}
@@ -429,7 +449,8 @@ void boot_config_free(BootConfig *config) {
boot_entry_free(i);
free(config->entries);
- boot_entry_addons_done(&config->global_addons);
+ FOREACH_ARRAY(i, config->global_addons, _BOOT_ENTRY_SOURCE_MAX)
+ boot_entry_addons_done(i);
set_free(config->inodes_seen);
}
@@ -595,6 +616,7 @@ static int config_check_inode_relevant_and_unseen(BootConfig *config, int fd, co
static int boot_entries_find_type1(
BootConfig *config,
const char *root,
+ const BootEntrySource source,
const char *dir) {
_cleanup_free_ DirectoryEntries *dentries = NULL;
@@ -638,7 +660,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, full, de->d_name);
+ r = boot_config_load_type1(config, f, root, source, full, de->d_name);
if (r == -ENOMEM) /* ignore all other errors */
return log_oom();
}
@@ -648,6 +670,7 @@ static int boot_entries_find_type1(
static int boot_entry_load_unified(
const char *root,
+ const BootEntrySource source,
const char *path,
unsigned profile,
const char *osrelease_text,
@@ -720,7 +743,7 @@ static int boot_entry_load_unified(
if (r < 0)
return log_error_errno(r, "Failed to extract file name from '%s': %m", path);
- _cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_UNIFIED);
+ _cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_UNIFIED, source);
r = boot_filename_extract_tries(fname, &tmp.id, &tmp.tries_left, &tmp.tries_done);
if (r < 0)
@@ -1133,18 +1156,21 @@ static int boot_entries_find_unified_addons(
static int boot_entries_find_unified_global_addons(
BootConfig *config,
const char *root,
- const char *d_name) {
+ const char *d_name,
+ BootEntryAddons *ret_addons) {
int r;
_cleanup_closedir_ DIR *d = NULL;
+ assert(ret_addons);
+
r = chase_and_opendir(root, NULL, CHASE_PROHIBIT_SYMLINKS, NULL, &d);
if (r == -ENOENT)
return 0;
if (r < 0)
return log_error_errno(r, "Failed to open '%s/%s': %m", root, d_name);
- return boot_entries_find_unified_addons(config, dirfd(d), d_name, root, &config->global_addons);
+ return boot_entries_find_unified_addons(config, dirfd(d), d_name, root, ret_addons);
}
static int boot_entries_find_unified_local_addons(
@@ -1168,6 +1194,7 @@ static int boot_entries_find_unified_local_addons(
static int boot_entries_find_unified(
BootConfig *config,
const char *root,
+ BootEntrySource source,
const char *dir) {
_cleanup_closedir_ DIR *d = NULL;
@@ -1220,12 +1247,15 @@ static int boot_entries_find_unified(
BootEntry *entry = config->entries + config->n_entries;
- if (boot_entry_load_unified(root, j, p, osrelease, profile, cmdline, entry) < 0)
+ if (boot_entry_load_unified(root, source, j, p, osrelease, profile, cmdline, config->entries + config->n_entries) < 0)
continue;
/* look for .efi.extra.d */
(void) boot_entries_find_unified_local_addons(config, dirfd(d), de->d_name, full, entry);
+ /* Set up the backpointer, so that we can find the global addons */
+ entry->global_addons = &config->global_addons[source];
+
config->n_entries++;
}
}
@@ -1443,32 +1473,37 @@ int boot_config_load(
int r;
assert(config);
- config->global_addons = (BootEntryAddons) {};
if (esp_path) {
r = boot_loader_read_conf_path(config, esp_path, "/loader/loader.conf");
if (r < 0)
return r;
- r = boot_entries_find_type1(config, esp_path, "/loader/entries");
+ r = boot_entries_find_type1(config, esp_path, BOOT_ENTRY_ESP, "/loader/entries");
if (r < 0)
return r;
- r = boot_entries_find_unified(config, esp_path, "/EFI/Linux/");
+ r = boot_entries_find_unified(config, esp_path, BOOT_ENTRY_ESP, "/EFI/Linux/");
if (r < 0)
return r;
- r = boot_entries_find_unified_global_addons(config, esp_path, "/loader/addons/");
+ r = boot_entries_find_unified_global_addons(config, esp_path, "/loader/addons/",
+ &config->global_addons[BOOT_ENTRY_ESP]);
if (r < 0)
return r;
}
if (xbootldr_path) {
- r = boot_entries_find_type1(config, xbootldr_path, "/loader/entries");
+ r = boot_entries_find_type1(config, xbootldr_path, BOOT_ENTRY_XBOOTLDR, "/loader/entries");
if (r < 0)
return r;
- r = boot_entries_find_unified(config, xbootldr_path, "/EFI/Linux/");
+ r = boot_entries_find_unified(config, xbootldr_path, BOOT_ENTRY_XBOOTLDR, "/EFI/Linux/");
+ if (r < 0)
+ return r;
+
+ r = boot_entries_find_unified_global_addons(config, xbootldr_path, "/loader/addons/",
+ &config->global_addons[BOOT_ENTRY_XBOOTLDR]);
if (r < 0)
return r;
}
@@ -1523,6 +1558,7 @@ int boot_config_augment_from_loader(
char **found_by_loader,
bool only_auto) {
+ static const BootEntryAddons no_addons = (BootEntryAddons) {};
static const char *const title_table[] = {
/* Pretty names for a few well-known automatically discovered entries. */
"auto-osx", "macOS",
@@ -1580,6 +1616,7 @@ int boot_config_augment_from_loader(
.reported_by_loader = true,
.tries_left = UINT_MAX,
.tries_done = UINT_MAX,
+ .global_addons = &no_addons,
};
}
@@ -1651,9 +1688,7 @@ static int indent_embedded_newlines(char *cmdline, char **ret_cmdline) {
return 0;
}
-static int print_cmdline(
- const BootEntry *e,
- const BootEntryAddons *global_arr) {
+static int print_cmdline(const BootEntry *e) {
_cleanup_free_ char *options = NULL, *combined_cmdline = NULL, *t2 = NULL;
@@ -1675,7 +1710,7 @@ static int print_cmdline(
return log_oom();
}
- FOREACH_ARRAY(addon, global_arr->items, global_arr->n_items) {
+ FOREACH_ARRAY(addon, e->global_addons->items, e->global_addons->n_items) {
print_addon(addon, "global-addon");
if (!strextend(&t2, " ", addon->cmdline))
return log_oom();
@@ -1723,7 +1758,6 @@ static int json_addon(
static int json_cmdline(
const BootEntry *e,
- const BootEntryAddons *global_arr,
const char *def_cmdline,
sd_json_variant **v) {
@@ -1739,7 +1773,7 @@ static int json_cmdline(
return log_oom();
}
- FOREACH_ARRAY(addon, global_arr->items, global_arr->n_items) {
+ FOREACH_ARRAY(addon, e->global_addons->items, e->global_addons->n_items) {
r = json_addon(addon, "globalAddon", &addons_array);
if (r < 0)
return r;
@@ -1766,7 +1800,6 @@ static int json_cmdline(
int show_boot_entry(
const BootEntry *e,
- const BootEntryAddons *global_addons,
bool show_as_default,
bool show_as_selected,
bool show_reported) {
@@ -1826,7 +1859,9 @@ int show_boot_entry(
if (e->type == BOOT_ENTRY_CONF)
(void) terminal_urlify_path(e->path, text, &link);
- printf(" source: %s\n", link ?: text ?: e->path);
+ printf(" source: %s (on the %s)\n",
+ link ?: text ?: e->path,
+ boot_entry_source_to_string(e->source));
}
if (e->tries_left != UINT_MAX) {
printf(" tries: %u left", e->tries_left);
@@ -1856,7 +1891,7 @@ int show_boot_entry(
*s,
&status);
- r = print_cmdline(e, global_addons);
+ r = print_cmdline(e);
if (r < 0)
return r;
@@ -1897,6 +1932,7 @@ int boot_entry_to_json(const BootConfig *c, size_t i, sd_json_variant **ret) {
r = sd_json_variant_merge_objectbo(
&v,
SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(boot_entry_type_json_to_string(e->type))),
+ SD_JSON_BUILD_PAIR("source", SD_JSON_BUILD_STRING(boot_entry_source_json_to_string(e->source))),
SD_JSON_BUILD_PAIR_CONDITION(!!e->id, "id", SD_JSON_BUILD_STRING(e->id)),
SD_JSON_BUILD_PAIR_CONDITION(!!e->path, "path", SD_JSON_BUILD_STRING(e->path)),
SD_JSON_BUILD_PAIR_CONDITION(!!e->root, "root", SD_JSON_BUILD_STRING(e->root)),
@@ -1928,7 +1964,7 @@ int boot_entry_to_json(const BootConfig *c, size_t i, sd_json_variant **ret) {
if (r < 0)
return log_oom();
- r = json_cmdline(e, &c->global_addons, opts, &v);
+ r = json_cmdline(e, opts, &v);
if (r < 0)
return log_oom();
@@ -1961,7 +1997,6 @@ int show_boot_entries(const BootConfig *config, sd_json_format_flags_t json_form
for (size_t n = 0; n < config->n_entries; n++) {
r = show_boot_entry(
config->entries + n,
- &config->global_addons,
/* show_as_default= */ n == (size_t) config->default_entry,
/* show_as_selected= */ n == (size_t) config->selected_entry,
/* show_discovered= */ true);
diff --git a/src/shared/bootspec.h b/src/shared/bootspec.h
index 0bb75669ce..6dda8549a1 100644
--- a/src/shared/bootspec.h
+++ b/src/shared/bootspec.h
@@ -21,6 +21,13 @@ typedef enum BootEntryType {
_BOOT_ENTRY_TYPE_INVALID = -EINVAL,
} BootEntryType;
+typedef enum BootEntrySource {
+ BOOT_ENTRY_ESP,
+ BOOT_ENTRY_XBOOTLDR,
+ _BOOT_ENTRY_SOURCE_MAX,
+ _BOOT_ENTRY_SOURCE_INVALID = -EINVAL,
+} BootEntrySource;
+
typedef struct BootEntryAddon {
char *location;
char *cmdline;
@@ -33,6 +40,7 @@ typedef struct BootEntryAddons {
typedef struct BootEntry {
BootEntryType type;
+ BootEntrySource source;
bool reported_by_loader;
char *id; /* This is the file basename (including extension!) */
char *id_old; /* Old-style ID, for deduplication purposes. */
@@ -47,6 +55,7 @@ typedef struct BootEntry {
char *architecture;
char **options;
BootEntryAddons local_addons;
+ const BootEntryAddons *global_addons; /* Backpointer into the BootConfig; we don't own this here */
char *kernel; /* linux is #defined to 1, yikes! */
char *efi;
char **initrd;
@@ -57,9 +66,10 @@ typedef struct BootEntry {
unsigned profile;
} BootEntry;
-#define BOOT_ENTRY_INIT(t) \
+#define BOOT_ENTRY_INIT(t, s) \
{ \
.type = (t), \
+ .source = (s), \
.tries_left = UINT_MAX, \
.tries_done = UINT_MAX, \
}
@@ -74,7 +84,7 @@ typedef struct BootConfig {
BootEntry *entries;
size_t n_entries;
- BootEntryAddons global_addons;
+ BootEntryAddons global_addons[_BOOT_ENTRY_SOURCE_MAX];
ssize_t default_entry;
ssize_t selected_entry;
@@ -91,6 +101,9 @@ typedef struct BootConfig {
const char* boot_entry_type_to_string(BootEntryType);
const char* boot_entry_type_json_to_string(BootEntryType);
+const char* boot_entry_source_to_string(BootEntrySource);
+const char* boot_entry_source_json_to_string(BootEntrySource);
+
BootEntry* boot_config_find_entry(BootConfig *config, const char *id);
static inline const BootEntry* boot_config_default_entry(const BootConfig *config) {
@@ -111,6 +124,7 @@ int boot_config_load_type1(
BootConfig *config,
FILE *f,
const char *root,
+ const BootEntrySource source,
const char *dir,
const char *id);
@@ -129,7 +143,6 @@ static inline const char* boot_entry_title(const BootEntry *entry) {
int show_boot_entry(
const BootEntry *e,
- const BootEntryAddons *global_addons,
bool show_as_default,
bool show_as_selected,
bool show_reported);