diff options
Diffstat (limited to 'src/boot/efi/stub.c')
-rw-r--r-- | src/boot/efi/stub.c | 98 |
1 files changed, 61 insertions, 37 deletions
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index 0d9df7e..9aa605b 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -26,28 +26,27 @@ DECLARE_NOALLOC_SECTION(".sdmagic", "#### LoaderInfo: systemd-stub " GIT_VERSION DECLARE_SBAT(SBAT_STUB_SECTION_TEXT); -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, +/* Combine initrds by concatenation in memory */ +static EFI_STATUS combine_initrds( + const void * const initrds[], const size_t initrd_sizes[], size_t n_initrds, Pages *ret_initr_pages, size_t *ret_initrd_size) { - size_t n; + size_t n = 0; assert(ret_initr_pages); assert(ret_initrd_size); - /* Combines four initrds into one, by simple concatenation in memory */ - - n = ALIGN4(initrd_size); /* main initrd might not be padded yet */ - - for (size_t i = 0; i < n_extra_initrds; i++) { - if (!extra_initrds[i]) + for (size_t i = 0; i < n_initrds; i++) { + if (!initrds[i]) continue; - if (n > SIZE_MAX - extra_initrd_sizes[i]) + /* some initrds (the ones from UKI sections) need padding, + * pad all to be safe */ + size_t initrd_size = ALIGN4(initrd_sizes[i]); + if (n > SIZE_MAX - initrd_size) return EFI_OUT_OF_RESOURCES; - n += extra_initrd_sizes[i]; + n += initrd_size; } _cleanup_pages_ Pages pages = xmalloc_pages( @@ -56,27 +55,21 @@ static EFI_STATUS combine_initrd( EFI_SIZE_TO_PAGES(n), UINT32_MAX /* Below 4G boundary. */); uint8_t *p = PHYSICAL_ADDRESS_TO_POINTER(pages.addr); - if (initrd_base != 0) { + for (size_t i = 0; i < n_initrds; i++) { + if (!initrds[i]) + continue; + size_t pad; - /* Order matters, the real initrd must come first, since it might include microcode updates - * which the kernel only looks for in the first cpio archive */ - p = mempcpy(p, PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size); + p = mempcpy(p, initrds[i], initrd_sizes[i]); - pad = ALIGN4(initrd_size) - initrd_size; + pad = ALIGN4(initrd_sizes[i]) - initrd_sizes[i]; if (pad > 0) { memzero(p, pad); p += pad; } } - for (size_t i = 0; i < n_extra_initrds; i++) { - if (!extra_initrds[i]) - continue; - - p = mempcpy(p, extra_initrds[i], extra_initrd_sizes[i]); - } - assert(PHYSICAL_ADDRESS_TO_POINTER(pages.addr + n) == p); *ret_initr_pages = pages; @@ -91,6 +84,7 @@ static void export_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) { EFI_STUB_FEATURE_REPORT_BOOT_PARTITION | /* We set LoaderDevicePartUUID */ EFI_STUB_FEATURE_PICK_UP_CREDENTIALS | /* We pick up credentials from the boot partition */ EFI_STUB_FEATURE_PICK_UP_SYSEXTS | /* We pick up system extensions from the boot partition */ + EFI_STUB_FEATURE_PICK_UP_CONFEXTS | /* We pick up configuration extensions from the boot partition */ EFI_STUB_FEATURE_THREE_PCRS | /* We can measure kernel image, parameters and sysext */ EFI_STUB_FEATURE_RANDOM_SEED | /* We pass a random seed to the kernel */ EFI_STUB_FEATURE_CMDLINE_ADDONS | /* We pick up .cmdline addons */ @@ -497,20 +491,20 @@ static EFI_STATUS load_addons( } static EFI_STATUS run(EFI_HANDLE image) { - _cleanup_free_ void *credential_initrd = NULL, *global_credential_initrd = NULL, *sysext_initrd = NULL, *pcrsig_initrd = NULL, *pcrpkey_initrd = NULL; - size_t credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0, pcrsig_initrd_size = 0, pcrpkey_initrd_size = 0; + _cleanup_free_ void *credential_initrd = NULL, *global_credential_initrd = NULL, *sysext_initrd = NULL, *confext_initrd = NULL, *pcrsig_initrd = NULL, *pcrpkey_initrd = NULL; + size_t credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0, confext_initrd_size = 0, pcrsig_initrd_size = 0, pcrpkey_initrd_size = 0; void **dt_bases_addons_global = NULL, **dt_bases_addons_uki = NULL; char16_t **dt_filenames_addons_global = NULL, **dt_filenames_addons_uki = NULL; _cleanup_free_ size_t *dt_sizes_addons_global = NULL, *dt_sizes_addons_uki = NULL; - size_t linux_size, initrd_size, dt_size, n_dts_addons_global = 0, n_dts_addons_uki = 0; - EFI_PHYSICAL_ADDRESS linux_base, initrd_base, dt_base; + size_t linux_size, initrd_size, ucode_size, dt_size, n_dts_addons_global = 0, n_dts_addons_uki = 0; + EFI_PHYSICAL_ADDRESS linux_base, initrd_base, ucode_base, dt_base; _cleanup_(devicetree_cleanup) struct devicetree_state dt_state = {}; EFI_LOADED_IMAGE_PROTOCOL *loaded_image; size_t addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {}; _cleanup_free_ char16_t *cmdline = NULL, *cmdline_addons_global = NULL, *cmdline_addons_uki = NULL; int sections_measured = -1, parameters_measured = -1; _cleanup_free_ char *uname = NULL; - bool sysext_measured = false, m; + bool sysext_measured = false, confext_measured = false, m; uint64_t loader_features = 0; EFI_STATUS err; @@ -660,8 +654,9 @@ static EFI_STATUS run(EFI_HANDLE image) { export_variables(loaded_image); if (pack_cpio(loaded_image, - NULL, + /* dropin_dir= */ NULL, u".cred", + /* exclude_suffix= */ NULL, ".extra/credentials", /* dir_mode= */ 0500, /* access_mode= */ 0400, @@ -675,6 +670,7 @@ static EFI_STATUS run(EFI_HANDLE image) { if (pack_cpio(loaded_image, u"\\loader\\credentials", u".cred", + /* exclude_suffix= */ NULL, ".extra/global_credentials", /* dir_mode= */ 0500, /* access_mode= */ 0400, @@ -686,8 +682,9 @@ static EFI_STATUS run(EFI_HANDLE image) { parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m); if (pack_cpio(loaded_image, - NULL, - u".raw", + /* dropin_dir= */ NULL, + u".raw", /* ideally we'd pick up only *.sysext.raw here, but for compat we pick up *.raw instead … */ + u".confext.raw", /* … but then exclude *.confext.raw again */ ".extra/sysext", /* dir_mode= */ 0555, /* access_mode= */ 0444, @@ -698,6 +695,20 @@ static EFI_STATUS run(EFI_HANDLE image) { &m) == EFI_SUCCESS) sysext_measured = m; + if (pack_cpio(loaded_image, + /* dropin_dir= */ NULL, + u".confext.raw", + /* exclude_suffix= */ NULL, + ".extra/confext", + /* dir_mode= */ 0555, + /* access_mode= */ 0444, + /* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG, + u"Configuration extension initrd", + &confext_initrd, + &confext_initrd_size, + &m) == EFI_SUCCESS) + confext_measured = m; + dt_size = szs[UNIFIED_SECTION_DTB]; dt_base = dt_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_DTB] : 0; @@ -728,6 +739,8 @@ static EFI_STATUS run(EFI_HANDLE image) { (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrKernelParameters", TPM2_PCR_KERNEL_CONFIG, 0); if (sysext_measured) (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrInitRDSysExts", TPM2_PCR_SYSEXTS, 0); + if (confext_measured) + (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrInitRDConfExts", TPM2_PCR_KERNEL_CONFIG, 0); /* If the PCR signature was embedded in the PE image, then let's wrap it in a cpio and also pass it * to the kernel, so that it can be read from /.extra/tpm2-pcr-signature.json. Note that this section @@ -772,26 +785,36 @@ static EFI_STATUS run(EFI_HANDLE image) { initrd_size = szs[UNIFIED_SECTION_INITRD]; initrd_base = initrd_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_INITRD] : 0; + ucode_size = szs[UNIFIED_SECTION_UCODE]; + ucode_base = ucode_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_UCODE] : 0; + _cleanup_pages_ Pages initrd_pages = {}; - if (credential_initrd || global_credential_initrd || sysext_initrd || pcrsig_initrd || pcrpkey_initrd) { - /* If we have generated initrds dynamically, let's combine them with the built-in initrd. */ - err = combine_initrd( - initrd_base, initrd_size, + if (ucode_base || credential_initrd || global_credential_initrd || sysext_initrd || confext_initrd || pcrsig_initrd || pcrpkey_initrd) { + /* If we have generated initrds dynamically or there is a microcode initrd, combine them with the built-in initrd. */ + err = combine_initrds( (const void*const[]) { + /* Microcode must always be first as kernel only scans uncompressed cpios + * and later initrds might be compressed. */ + PHYSICAL_ADDRESS_TO_POINTER(ucode_base), + PHYSICAL_ADDRESS_TO_POINTER(initrd_base), credential_initrd, global_credential_initrd, sysext_initrd, + confext_initrd, pcrsig_initrd, pcrpkey_initrd, }, (const size_t[]) { + ucode_size, + initrd_size, credential_initrd_size, global_credential_initrd_size, sysext_initrd_size, + confext_initrd_size, pcrsig_initrd_size, pcrpkey_initrd_size, }, - 5, + 8, &initrd_pages, &initrd_size); if (err != EFI_SUCCESS) return err; @@ -802,6 +825,7 @@ static EFI_STATUS run(EFI_HANDLE image) { credential_initrd = mfree(credential_initrd); global_credential_initrd = mfree(global_credential_initrd); sysext_initrd = mfree(sysext_initrd); + confext_initrd = mfree(confext_initrd); pcrsig_initrd = mfree(pcrsig_initrd); pcrpkey_initrd = mfree(pcrpkey_initrd); } |