Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:vlefebvre:unified
systemd
2003-systemd-stub-addons-load-generic-addons-vi...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 2003-systemd-stub-addons-load-generic-addons-via-EFI-prot.patch of Package systemd
From 8bbf480b695824d0bcbc11699a1dcc1af16e047d Mon Sep 17 00:00:00 2001 From: Raito Bezarius <masterancpp@gmail.com> Date: Sun, 18 Jun 2023 04:26:05 +0200 Subject: [PATCH 3/7] systemd-stub(addons): load generic addons via EFI protocol - reads from EFI protocol - make the loading phase agnostic from the "read source" - restructure the addon entry to be generic and not only cmdline for future initrd loading, etc. - add a feature called `OFFER_ADDONS` on sd-boot to signal support for this EFI protocol --- src/boot/efi/boot.c | 1 + src/boot/efi/stub.c | 133 ++++++++++++++++++++------ src/fundamental/efivars-fundamental.h | 1 + 3 files changed, 106 insertions(+), 29 deletions(-) diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 1debd591b3..15b365cf40 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -2554,6 +2554,7 @@ static void export_variables( EFI_LOADER_FEATURE_SECUREBOOT_ENROLL | EFI_LOADER_FEATURE_RETAIN_SHIM | EFI_LOADER_FEATURE_MENU_DISABLE | + EFI_LOADER_FEATURE_OFFER_ADDONS | 0; _cleanup_free_ char16_t *infostr = NULL, *typestr = NULL; diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index 572ea480f0..94a34e953c 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -26,6 +26,18 @@ DECLARE_NOALLOC_SECTION(".sdmagic", "#### LoaderInfo: systemd-stub " GIT_VERSION DECLARE_SBAT(SBAT_STUB_SECTION_TEXT); +struct addon_entry { + char16_t *source_path; + const EFI_DEVICE_PATH *device_path; +}; + +static int cmp_addon_entry(const struct addon_entry *s1, const struct addon_entry *s2) { + assert(s1); + assert(s2); + + return strcmp16((const char16_t*)&s1->source_path, (const char16_t*)&s2->source_path); +} + static EFI_STATUS combine_initrd( EFI_PHYSICAL_ADDRESS initrd_base, size_t initrd_size, const void * const extra_initrds[], const size_t extra_initrd_sizes[], size_t n_extra_initrds, @@ -191,20 +203,23 @@ static bool use_load_options( } static EFI_STATUS load_addons_from_dir( + EFI_LOADED_IMAGE_PROTOCOL *current_image, EFI_FILE *root, const char16_t *prefix, - char16_t ***items, + struct addon_entry **addons, size_t *n_items, size_t *n_allocated) { _cleanup_(file_closep) EFI_FILE *extra_dir = NULL; _cleanup_free_ EFI_FILE_INFO *dirent = NULL; + char16_t *addon_spath = NULL; + EFI_DEVICE_PATH *addon_path = NULL; size_t dirent_size = 0; EFI_STATUS err; assert(root); assert(prefix); - assert(items); + assert(addons); assert(n_items); assert(n_allocated); @@ -237,18 +252,76 @@ static EFI_STATUS load_addons_from_dir( d = xstrdup16(dirent->FileName); + if (*n_items + 2 > *n_allocated) { /* We allocate 16 entries at a time, as a matter of optimization */ - if (*n_items > (SIZE_MAX / sizeof(uint16_t)) - 16) /* Overflow check, just in case */ + if (*n_items > (SIZE_MAX / sizeof(struct addon_entry)) - 16) /* Overflow check, just in case */ return log_oom(); size_t m = *n_items + 16; - *items = xrealloc(*items, *n_allocated * sizeof(uint16_t *), m * sizeof(uint16_t *)); + *addons = xrealloc(*addons, *n_allocated + sizeof(struct addon_entry), m * + sizeof(struct addon_entry)); *n_allocated = m; } - (*items)[(*n_items)++] = TAKE_PTR(d); - (*items)[*n_items] = NULL; /* Let's always NUL terminate, to make freeing via strv_free() easy */ + addon_spath = xasprintf("%ls\\%ls", prefix, d); + err = make_file_device_path(current_image, addon_spath, &addon_path); + if (err != EFI_SUCCESS) + return log_error_status(err, "Error making device path for %ls: %m", addon_spath); + + (*addons)[*n_items] = (struct addon_entry) { + .source_path = TAKE_PTR(d), + .device_path = TAKE_PTR(addon_path) + }; + *n_items = *n_items + 1; + } + + return EFI_SUCCESS; +} + +static EFI_STATUS load_addons_from_efi( + EFI_LOADED_IMAGE_PROTOCOL *image, + struct addon_entry **addons, + size_t *n_items, + size_t *n_allocated) { + + EFI_STATUS err; + EFI_DEVICE_PATH **addon_paths = NULL; + + err = BS->HandleProtocol(image->DeviceHandle, MAKE_GUID_PTR(SYSTEMD_ADDON_MEDIA), (void **) &addon_paths); + + if (err == EFI_NOT_FOUND) + /* No addons from EFI, that's OK */ + return EFI_SUCCESS; + if (err != EFI_SUCCESS) + return log_error_status(err, "Failed to load addons from EFI protocol: %m"); + + while (*addon_paths) { + char16_t *spath = NULL; + /* If we increment this pointer instead of addon_paths_split, we will arrive on a end node + * marker */ + const EFI_DEVICE_PATH *addon_dpath = *addon_paths; + err = device_path_to_str(addon_dpath, &spath); + if (err != EFI_SUCCESS) + return err; + + if (*n_items + 2 > *n_allocated) { + /* We allocate 16 entries at a time, as a matter of optimization */ + if (*n_items > (SIZE_MAX / sizeof(struct addon_entry)) - 16) /* Overflow check, just in case */ + return log_oom(); + + size_t m = *n_items + 16; + *addons = xrealloc(*addons, *n_allocated + sizeof(struct addon_entry), m * + sizeof(struct addon_entry)); + *n_allocated = m; + } + + (*addons)[*n_items] = (struct addon_entry) { + .source_path = TAKE_PTR(spath), + .device_path = TAKE_PTR(addon_dpath) + }; + *n_items = *n_items + 1; + addon_paths++; } return EFI_SUCCESS; @@ -358,13 +431,14 @@ static EFI_STATUS load_addons( char16_t ***ret_dt_filenames, size_t *ret_n_dt) { + _cleanup_free_ struct addon_entry *addons = NULL; _cleanup_free_ size_t *dt_sizes = NULL; - _cleanup_(strv_freep) char16_t **items = NULL; _cleanup_(file_closep) EFI_FILE *root = NULL; _cleanup_free_ char16_t *cmdline = NULL; size_t n_items = 0, n_allocated = 0, n_dt = 0; char16_t **dt_filenames = NULL; void **dt_bases = NULL; + char16_t **items = NULL; EFI_STATUS err; assert(stub_image); @@ -379,6 +453,7 @@ static EFI_STATUS load_addons( CLEANUP_ARRAY(dt_bases, n_dt, dt_bases_free); CLEANUP_ARRAY(dt_filenames, n_dt, dt_filenames_free); + CLEANUP_ARRAY(items, n_items, strv_free); err = open_volume(loaded_image->DeviceHandle, &root); if (err == EFI_UNSUPPORTED) @@ -388,7 +463,11 @@ static EFI_STATUS load_addons( if (err != EFI_SUCCESS) return log_error_status(err, "Unable to open root directory: %m"); - err = load_addons_from_dir(root, prefix, &items, &n_items, &n_allocated); + err = load_addons_from_dir(loaded_image, root, prefix, &addons, &n_items, &n_allocated); + if (err != EFI_SUCCESS) + return err; + + err = load_addons_from_efi(loaded_image, &addons, &n_items, &n_allocated); if (err != EFI_SUCCESS) return err; @@ -397,28 +476,19 @@ static EFI_STATUS load_addons( /* Now, sort the files we found, to make this uniform and stable (and to ensure the TPM measurements * are not dependent on read order) */ - sort_pointer_array((void**) items, n_items, (compare_pointer_func_t) strcmp16); + sort_pointer_array((void**) addons, n_items, (compare_pointer_func_t) cmp_addon_entry); for (size_t i = 0; i < n_items; i++) { size_t addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {}; - _cleanup_free_ EFI_DEVICE_PATH *addon_path = NULL; _cleanup_(unload_imagep) EFI_HANDLE addon = NULL; EFI_LOADED_IMAGE_PROTOCOL *loaded_addon = NULL; - _cleanup_free_ char16_t *addon_spath = NULL; - - addon_spath = xasprintf("%ls\\%ls", prefix, items[i]); - err = make_file_device_path(loaded_image->DeviceHandle, addon_spath, &addon_path); - if (err != EFI_SUCCESS) - return log_error_status(err, "Error making device path for %ls: %m", addon_spath); /* By using shim_load_image, we cover both the case where the PE files are signed with MoK * and with DB, and running with or without shim. */ - err = shim_load_image(stub_image, addon_path, &addon); + err = shim_load_image(stub_image, addons[i].device_path, &addon); if (err != EFI_SUCCESS) { log_error_status(err, - "Failed to read '%ls' from '%ls', ignoring: %m", - items[i], - addon_spath); + "Failed to read '%ls', ignoring: %m", addons[i].source_path); continue; } @@ -426,7 +496,8 @@ static EFI_STATUS load_addons( MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), (void **) &loaded_addon); if (err != EFI_SUCCESS) - return log_error_status(err, "Failed to find protocol in %ls: %m", items[i]); + return log_error_status(err, "Failed to find protocol in %ls: %m", + addons[i].source_path); err = pe_memory_locate_sections(loaded_addon->ImageBase, unified_sections, addrs, szs); if (err != EFI_SUCCESS || @@ -434,14 +505,15 @@ static EFI_STATUS load_addons( if (err == EFI_SUCCESS) err = EFI_NOT_FOUND; log_error_status(err, - "Unable to locate embedded .cmdline/.dtb sections in %ls, ignoring: %m", - items[i]); + "Unable to locate embedded .cmdline/.dtb section in %ls, ignoring: %m", + addons[i].source_path); continue; } /* We want to enforce that addons are not UKIs, i.e.: they must not embed a kernel. */ if (szs[UNIFIED_SECTION_LINUX] > 0) { - log_error_status(EFI_INVALID_PARAMETER, "%ls is a UKI, not an addon, ignoring: %m", items[i]); + log_error_status(EFI_INVALID_PARAMETER, "%ls is a UKI, not an addon, ignoring: %m", + addons[i].source_path); continue; } @@ -451,7 +523,7 @@ static EFI_STATUS load_addons( !strneq8(uname, (char *)loaded_addon->ImageBase + addrs[UNIFIED_SECTION_UNAME], szs[UNIFIED_SECTION_UNAME])) { - log_error(".uname mismatch between %ls and UKI, ignoring", items[i]); + log_error(".uname mismatch between %ls and UKI, ignoring", addons[i].source_path); continue; } @@ -529,10 +601,13 @@ static EFI_STATUS run(EFI_HANDLE image) { } err = pe_memory_locate_sections(loaded_image->ImageBase, unified_sections, addrs, szs); - if (err != EFI_SUCCESS || szs[UNIFIED_SECTION_LINUX] == 0) { - if (err == EFI_SUCCESS) - err = EFI_NOT_FOUND; - return log_error_status(err, "Unable to locate embedded .linux section: %m"); + if (err != EFI_SUCCESS) + return log_error_status(err, "Unable to locate embedded sections in the current binary: %m"); + + if (szs[UNIFIED_SECTION_LINUX] == 0) { + err = EFI_NOT_FOUND; + log_error_status(err, "Unable to locate embedded .linux section: %m, will skip..."); + err = EFI_SUCCESS; } CLEANUP_ARRAY(dt_bases_addons_global, n_dts_addons_global, dt_bases_free); diff --git a/src/fundamental/efivars-fundamental.h b/src/fundamental/efivars-fundamental.h index 2d25d2248f..749e8520f8 100644 --- a/src/fundamental/efivars-fundamental.h +++ b/src/fundamental/efivars-fundamental.h @@ -23,6 +23,7 @@ #define EFI_LOADER_FEATURE_SECUREBOOT_ENROLL (UINT64_C(1) << 11) #define EFI_LOADER_FEATURE_RETAIN_SHIM (UINT64_C(1) << 12) #define EFI_LOADER_FEATURE_MENU_DISABLE (UINT64_C(1) << 13) +#define EFI_LOADER_FEATURE_OFFER_ADDONS (UINT64_C(1) << 14) /* Features of the stub, i.e. systemd-stub */ #define EFI_STUB_FEATURE_REPORT_BOOT_PARTITION (UINT64_C(1) << 0) -- 2.35.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor