From: Lennart Poettering Date: Fri, 20 Mar 2026 20:48:12 +0000 (+0100) Subject: stub: load previous initrd that is already configured, too X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=426134b0e7112a09eae941d97f68b2fa1b76c4b7;p=thirdparty%2Fsystemd.git stub: load previous initrd that is already configured, too This changes the initrd combination logic to also include any initrd already configured via the "LINUX_INITRD_MEDIA_GUID" device in the initrd we pass to the linux kernel. Or in other words: with this systemd-stub starts operating purely incremental: it will extend any previously installed initrd with its own stuff, so that both the previous initrd(s) and systemd-stub's are in effect. --- diff --git a/src/boot/initrd.c b/src/boot/initrd.c index b81334ea06a..4780715e792 100644 --- a/src/boot/initrd.c +++ b/src/boot/initrd.c @@ -171,3 +171,47 @@ EFI_STATUS initrd_unregister(EFI_HANDLE initrd_handle) { free(loader); return EFI_SUCCESS; } + +EFI_STATUS initrd_read_previous(struct iovec *ret_initrd) { + EFI_STATUS err; + + /* If there's already an initrd registered, read it out, so that we can incorporate it in ours */ + + assert(ret_initrd); + + /* Get from the device path to the handle */ + EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *) &efi_initrd_device_path; + EFI_HANDLE handle; + err = BS->LocateDevicePath(MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL), &dp, &handle); + if (err != EFI_SUCCESS) + return err; + + /* Get from the handle to the protocol */ + EFI_LOAD_FILE2_PROTOCOL *protocol = NULL; + err = BS->HandleProtocol(handle, MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL), (void**) &protocol); + if (err != EFI_SUCCESS) + return err; + + size_t size = 0; + err = protocol->LoadFile(protocol, dp, /* bootPolicy= */ false, &size, /* Buffer= */ NULL); + if (err == EFI_SUCCESS) /* Success? Kinda unexpected given we set Buffer to NULL, but it probably + * means, that the file is zero-sized, let's treat it as such. */ + size = 0; + else if (err != EFI_BUFFER_TOO_SMALL) + return err; + + if (size == 0) + return EFI_NOT_FOUND; /* Treat empty initrds like missing ones */ + + _cleanup_free_ void *data = xmalloc(size); + err = protocol->LoadFile(protocol, dp, /* bootPolicy= */ false, &size, data); + if (err != EFI_SUCCESS) + return err; + + *ret_initrd = (struct iovec) { + .iov_base = TAKE_PTR(data), + .iov_len = size, + }; + + return EFI_SUCCESS; +} diff --git a/src/boot/initrd.h b/src/boot/initrd.h index 50987c497d6..d34f8ef4c4f 100644 --- a/src/boot/initrd.h +++ b/src/boot/initrd.h @@ -13,3 +13,5 @@ static inline void cleanup_initrd(EFI_HANDLE *initrd_handle) { (void) initrd_unregister(*initrd_handle); *initrd_handle = NULL; } + +EFI_STATUS initrd_read_previous(struct iovec *ret_initrd); diff --git a/src/boot/stub.c b/src/boot/stub.c index e2a8569cb33..664ee7cb851 100644 --- a/src/boot/stub.c +++ b/src/boot/stub.c @@ -10,6 +10,7 @@ #include "efi-string.h" #include "export-vars.h" #include "graphics.h" +#include "initrd.h" #include "iovec-util-fundamental.h" #include "linux.h" #include "measure.h" @@ -32,13 +33,10 @@ /* The list of initrds we combine into one, in the order we want to merge them */ enum { - /* The first two are part of the PE binary */ - INITRD_UCODE, - INITRD_BASE, - - /* The rest are dynamically generated, and hence in dynamic memory */ - _INITRD_DYNAMIC_FIRST, - INITRD_CREDENTIAL = _INITRD_DYNAMIC_FIRST, + INITRD_UCODE, /* Part of the PE binary */ + INITRD_PREVIOUS, /* initrd already configured via the EFI protocol before we were invoked */ + INITRD_BASE, /* Part of the PE binary */ + INITRD_CREDENTIAL, INITRD_GLOBAL_CREDENTIAL, INITRD_SYSEXT, INITRD_GLOBAL_SYSEXT, @@ -52,6 +50,8 @@ enum { _INITRD_MAX, }; +#define INITRD_IS_STATIC(idx) IN_SET(idx, INITRD_UCODE, INITRD_BASE) + /* magic string to find in the binary image */ DECLARE_NOALLOC_SECTION(".sdmagic", "#### LoaderInfo: systemd-stub " GIT_VERSION " ####"); @@ -550,6 +550,21 @@ static void extend_initrds( iovec_array_extend(all_initrds, n_all_initrds, *i); } +static void acquire_previous_initrd(struct iovec initrds[static _INITRD_MAX]) { + EFI_STATUS err; + + /* NB: the assumption here is that any previously installed initrd are measured by whatever + * registered them, and we just pass them on here. */ + + err = initrd_read_previous(initrds + INITRD_PREVIOUS); + if (err == EFI_NOT_FOUND) + log_debug_status(err, "No previous initrd registered."); + else if (err != EFI_SUCCESS) + log_warning_status(err, "Failed to read previously registered initrd, ignoring."); + else + log_debug("Successfully loaded previously registered initrd (%zu bytes).", initrds[INITRD_PREVIOUS].iov_len); +} + static EFI_STATUS load_addons( EFI_HANDLE stub_image, EFI_LOADED_IMAGE_PROTOCOL *loaded_image, @@ -821,10 +836,11 @@ static void cmdline_append_and_measure_smbios(char16_t **cmdline, int *parameter static void initrds_free(struct iovec (*initrds)[_INITRD_MAX]) { assert(initrds); - /* Free the dynamic initrds, but leave the non-dynamic ones around */ + /* Free the non-static initrds, but leave the static (i.e. PE embedded) ones around */ - for (size_t i = _INITRD_DYNAMIC_FIRST; i < _INITRD_MAX; i++) - iovec_done((*initrds) + i); + for (size_t i = 0; i < _INITRD_MAX; i++) + if (!INITRD_IS_STATIC(i)) + iovec_done((*initrds) + i); } static void generate_sidecar_initrds( @@ -1309,6 +1325,7 @@ static EFI_STATUS run(EFI_HANDLE image) { install_addon_devicetrees(&dt_state, dt_addons, n_dt_addons, ¶meters_measured); /* Generate & find all initrds */ + acquire_previous_initrd(initrds); generate_sidecar_initrds(loaded_image, initrds, ¶meters_measured, &sysext_measured, &confext_measured); generate_embedded_initrds(loaded_image, sections, initrds); generate_boot_secret_initrd(boot_secret, initrds); @@ -1319,9 +1336,10 @@ static EFI_STATUS run(EFI_HANDLE image) { * We want addons to take precedence over the base initrds, so the order is: * 1. Ucode addons * 2. UKI ucode - * 3. UKI initrd - * 4. Generated initrds - * 5. initrd addons */ + * 3. Previous initrds + * 4. UKI initrd + * 5. Generated initrds + * 6. initrd addons */ measure_and_append_ucode_addons(&all_initrds, &n_all_initrds, ucode_addons, n_ucode_addons, ¶meters_measured); extend_initrds(initrds, &all_initrds, &n_all_initrds); measure_and_append_initrd_addons(&all_initrds, &n_all_initrds, initrd_addons, n_initrd_addons, ¶meters_measured);