diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 03:50:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 03:50:45 +0000 |
commit | efeb864cb547a2cbf96dc0053a8bdb4d9190b364 (patch) | |
tree | c0b83368f18be983fcc763200c4c24d633244588 /src/boot/efi | |
parent | Releasing progress-linux version 255.5-1~progress7.99u1. (diff) | |
download | systemd-efeb864cb547a2cbf96dc0053a8bdb4d9190b364.tar.xz systemd-efeb864cb547a2cbf96dc0053a8bdb4d9190b364.zip |
Merging upstream version 256.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boot/efi')
-rw-r--r-- | src/boot/efi/UEFI_SECURITY.md | 57 | ||||
-rw-r--r-- | src/boot/efi/boot.c | 40 | ||||
-rw-r--r-- | src/boot/efi/cpio.c | 3 | ||||
-rw-r--r-- | src/boot/efi/cpio.h | 1 | ||||
-rw-r--r-- | src/boot/efi/efi-string.c | 8 | ||||
-rw-r--r-- | src/boot/efi/efi.h | 2 | ||||
-rw-r--r-- | src/boot/efi/measure.c | 158 | ||||
-rw-r--r-- | src/boot/efi/meson.build | 17 | ||||
-rw-r--r-- | src/boot/efi/part-discovery.c | 2 | ||||
-rw-r--r-- | src/boot/efi/proto/cc-measurement.h | 67 | ||||
-rw-r--r-- | src/boot/efi/proto/tcg.h | 34 | ||||
-rw-r--r-- | src/boot/efi/random-seed.c | 2 | ||||
-rw-r--r-- | src/boot/efi/secure-boot.c | 73 | ||||
-rw-r--r-- | src/boot/efi/stub.c | 98 | ||||
-rw-r--r-- | src/boot/efi/util.c | 2 | ||||
-rw-r--r-- | src/boot/efi/util.h | 4 | ||||
-rw-r--r-- | src/boot/efi/vmm.h | 2 |
17 files changed, 367 insertions, 203 deletions
diff --git a/src/boot/efi/UEFI_SECURITY.md b/src/boot/efi/UEFI_SECURITY.md index 9f750d8..55e66db 100644 --- a/src/boot/efi/UEFI_SECURITY.md +++ b/src/boot/efi/UEFI_SECURITY.md @@ -9,28 +9,28 @@ stub's role is that of the fundamental entrypoint to kernel execution from UEFI modern Linux boot protocol. `systemd-stub` on the other hand loads various resources, including the kernel image, via the EFI LoadImage/StartImage protocol (although it does support the legacy Linux boot protocol, as a fallback for older kernels on x86). The purpose of `systemd-stub` is to provide additional features and -functionality for either or both `systemd-boot` and `systemd` (userspace). +functionality for `systemd-boot` and `systemd` (in userspace). ## Fundamental Security Design Goals -The fundamental security design goals for these components are separation of security policy logic from the -rest of the functionality, achieved by offloading security-critical tasks to the firmware or earlier stages -of the boot process (e.g.: `Shim`). +The fundamental security design goal for these components is the separation of security policy logic from the +rest of the functionality. This is achieved by offloading security-critical tasks to the firmware or earlier stages +of the boot process (in particular `Shim`). -When SecureBoot is enabled, these components are designed to avoid executing, loading or using +When SecureBoot is enabled, these components are designed to avoid loading, executing, or using unauthenticated payloads that could compromise the boot process, with special care taken for anything that could affect the system before `ExitBootServices()` has been called. For example, when additional resources are loaded, if running with SecureBoot enabled, they will be validated before use. The only exceptions are -the bootloader's own textual configuration files, and parsing metadata out of images for displaying purposes +the bootloader's own textual configuration files, and metadata parsed out of kernel images for display purposes only. There are no build time or runtime configuration options that can be set to weaken the security model of these components when SecureBoot is enabled. The role of `systemd-boot` is to discover next stage components in the ESP (and XBOOTLDR if present), via -filesystem enumeration or explicit configuration files, and present a menu to the user, to choose the next -step. This auto discovery mechanism is described in details in the [BLS (Boot Loader +filesystem enumeration or explicit configuration files, and present a menu to the user to choose the next +step. This auto discovery mechanism is described in detail in the [BLS (Boot Loader Specification)](https://uapi-group.org/specifications/specs/boot_loader_specification/). The role of `systemd-stub` is to load and measure in the TPM the post-bootloader stages, such as the kernel, -initrd and kernel command line, and implement optional features such as augmenting the initrd with +initrd, and kernel command line, and implement optional features such as augmenting the initrd with additional content such as configuration or optional services. [Unified Kernel Images](https://uapi-group.org/specifications/specs/unified_kernel_image/) embed `systemd-stub`, a kernel and other optional components as sections in a PE signed binary, that can thus be executed in UEFI @@ -42,19 +42,19 @@ the image, given that the payload kernel was already authenticated and verified SecureBoot authentication is re-enabled immediately after the kernel image has been loaded. Various EFI variables, under the vendor UUID `4a67b082-0a4c-41cf-b6c7-440b29bb8c4f`, are set and read by -these components, to pass metadata and configuration between different stages of the boot process, as +these components. This is used to pass metadata and configuration between different stages of the boot process, as defined in the [Boot Loader Interface](https://systemd.io/BOOT_LOADER_INTERFACE/). ## Dependencies -Neither of these components implements cryptographic primitives, cryptographic checks or drivers. File +Neither of these components implements cryptographic primitives, cryptographic checks, or drivers. File access to the ESP is implemented solely via the appropriate UEFI file protocols. Verification of next stage -payloads is implementend solely via the appropriate UEFI image load protocols, which means authenticode +payloads is implementend solely via the appropriate UEFI image load protocols, which means `authenticode` signature checks are again done by the firmware or `Shim`. As a consequence, no external security-critical -libraries (such as OpenSSL or gnu-efi) are used, linked or embedded. +libraries (such as OpenSSL or gnu-efi) are linked, embedded, or used. ## Additional Resources BLS Type #1 entries allow the user to load two types of additional resources that can affect the system -before `ExitBootServices()` has been called, kernel command line arguments and Devicetree blobs, that are +before `ExitBootServices()` has been called — kernel command line arguments and Devicetree blobs — that are not validated before use, as they do not carry signatures. For this reason, when SecureBoot is enabled, loading these resources is automatically disabled. There is no override for this security mechanism, neither at build time nor at runtime. Note that initrds are also not verified in BLS Type #1 configurations, for @@ -62,8 +62,9 @@ compatibility with how SecureBoot has been traditionally handled on Linux-based only load them after `ExitBootServices()` has been called. Another mechanism is supported by `systemd-boot` and `systemd-stub` to add additional payloads to the boot -process: `addons`. Addons are PE signed binaries that can carry kernel command line arguments or Devicetree -blobs (more might be added in the future). In contrast to the user-specified additions in the Type #1 case +process: "addons". Addons are PE signed binaries that can carry kernel command line arguments or Devicetree +blobs (more payload types might be added in the future). +In contrast to the user-specified additions in the Type #1 case described above, these addons are loaded through the UEFI image loading protocol, and thus are subject to signature validation, and will be rejected if not signed or if the signature is invalid, following the standard SecureBoot model. They are also measured in the TPM. @@ -72,22 +73,22 @@ standard SecureBoot model. They are also measured in the TPM. firmware's capabilities. These are again PE signed binaries and will be verified using the appropriate UEFI protocol. -A random seed will be loaded and passed to the kernel for early-boot entropy pool filling if found in the -ESP. It is mixed with various other sources of entropy available in the UEFI environment, such as the RNG +A random seed will be loaded and passed to the kernel for early-boot entropy if found in the ESP. +It is mixed with various other sources of entropy available in the UEFI environment, such as the RNG protocol, the boot counter and the clock. Moreover, the seed is updated before the kernel is invoked, as well as after the kernel is invoked (from userspace), with a new seed derived from the Linux kernel entropy pool. When operating as a virtual machine payload, the loaded payloads can be customized via `SMBIOS Type 11 -Strings`, if the hypervisor specifies them. This is automatically disabled if running inside a confidential -computing VM. +Strings`. Those settings are specified by the hypervisor and trusted. +They are automatically disabled if running inside a confidential computing VM. ## Certificates Enrollment -When SecureBoot is supported but in `setup` mode, `systemd-boot` can enroll user certificates if a set of -`PK`, `KEK` and `db` certificates is found in the ESP, after which SecureBoot is enabled and a firmware -reset is performed. When running on bare metal, the certificate(s) will be shown to the user on the console, -and manual confirmation will be asked before proceeding. When running as a virtual machine payload, -enrollment is fully automated, without user interaction, unless disabled via a configuration file in the +When SecureBoot is supported, but in `setup` mode, `systemd-boot` can enroll user certificates if a set of +`PK`, `KEK` and `db` certificates is found in the ESP. Afterwards, SecureBoot is enabled and a firmware +reset is performed. When running on bare metal, the certificates will be shown to the user on the console, +and manual confirmation is required before proceeding. When running as a virtual machine payload, +enrollment is fully automated without user interaction, unless disabled via a configuration file in the ESP. The configuration file can also be used to disable enrollment completely. ## Compiler Hardening @@ -111,10 +112,10 @@ allow customizations of the metadata included in the section, that can be used b The `systemd` project will participate in the coordinated `SBAT` disclosure and metadata revision process as deemed necessary, in coordination with the Shim Review group. -The upstream project name used to be unified (`systemd`) for both components, but since version v255 has +The upstream project name used to be unified (`systemd`) for both components, but since version 255 has been split into separate `systemd-boot` and `systemd-stub` project names, so that each component can be -revisioned independently. Most of the code tend to be shared between these two components, but there is no -complete overlap, so it is possible for a vulnerability to affect only one component but not the other. +revisioned independently. Most of the code tends to be shared between these two components, but the +overlap is not complete, so a future vulnerability may affect only one of the components. ## Known Vulnerabilities There is currently one known (and fixed) security vulnerability affecting `systemd-boot` on arm64 and diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index a3d5607..79de121 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -741,20 +741,25 @@ static bool menu_run( lines = xnew(char16_t *, config->n_entries + 1); for (size_t i = 0; i < config->n_entries; i++) { - size_t j, padding; + size_t width = line_width - MIN(strlen16(config->entries[i]->title_show), line_width); + size_t padding = width / 2; + bool odd = width % 2; - lines[i] = xnew(char16_t, line_width + 1); - padding = (line_width - MIN(strlen16(config->entries[i]->title_show), line_width)) / 2; + /* Make sure there is space for => */ + padding = MAX((size_t) 2, padding); - for (j = 0; j < padding; j++) - lines[i][j] = ' '; + size_t print_width = MIN( + strlen16(config->entries[i]->title_show), + line_width - padding * 2); - for (size_t k = 0; config->entries[i]->title_show[k] != '\0' && j < line_width; j++, k++) - lines[i][j] = config->entries[i]->title_show[k]; + assert((padding + 1) <= INT_MAX); + assert(print_width <= INT_MAX); - for (; j < line_width; j++) - lines[i][j] = ' '; - lines[i][line_width] = '\0'; + lines[i] = xasprintf( + "%*ls%.*ls%*ls", + (int) padding, u"", + (int) print_width, config->entries[i]->title_show, + odd ? (int) (padding + 1) : (int) padding, u""); } lines[config->n_entries] = NULL; @@ -2288,7 +2293,7 @@ static EFI_STATUS initrd_prepare( continue; size_t new_size, read_size = info->FileSize; - if (__builtin_add_overflow(size, read_size, &new_size)) + if (!ADD_SAFE(&new_size, size, read_size)) return EFI_OUT_OF_RESOURCES; initrd = xrealloc(initrd, size, new_size); @@ -2369,7 +2374,16 @@ static EFI_STATUS image_start( /* If we had to append an initrd= entry to the command line, we have to pass it, and measure it. * Otherwise, only pass/measure it if it is not implicit anyway (i.e. embedded into the UKI or * so). */ - char16_t *options = options_initrd ?: entry->options_implied ? NULL : entry->options; + _cleanup_free_ char16_t *options = xstrdup16(options_initrd ?: entry->options_implied ? NULL : entry->options); + + if (entry->type == LOADER_LINUX && !is_confidential_vm()) { + const char *extra = smbios_find_oem_string("io.systemd.boot.kernel-cmdline-extra"); + if (extra) { + _cleanup_free_ char16_t *tmp = TAKE_PTR(options), *extra16 = xstr8_to_16(extra); + options = xasprintf("%ls %ls", tmp, extra16); + } + } + if (options) { loaded_image->LoadOptions = options; loaded_image->LoadOptionsSize = strsize16(options); @@ -2466,7 +2480,7 @@ static EFI_STATUS secure_boot_discover_keys(Config *config, EFI_FILE *root_dir) EFI_STATUS err; _cleanup_(file_closep) EFI_FILE *keys_basedir = NULL; - if (secure_boot_mode() != SECURE_BOOT_SETUP) + if (!IN_SET(secure_boot_mode(), SECURE_BOOT_SETUP, SECURE_BOOT_AUDIT)) return EFI_SUCCESS; /* the lack of a 'keys' directory is not fatal and is silently ignored */ diff --git a/src/boot/efi/cpio.c b/src/boot/efi/cpio.c index c4f803c..bd1118a 100644 --- a/src/boot/efi/cpio.c +++ b/src/boot/efi/cpio.c @@ -305,6 +305,7 @@ EFI_STATUS pack_cpio( EFI_LOADED_IMAGE_PROTOCOL *loaded_image, const char16_t *dropin_dir, const char16_t *match_suffix, + const char16_t *exclude_suffix, const char *target_dir_prefix, uint32_t dir_mode, uint32_t access_mode, @@ -367,6 +368,8 @@ EFI_STATUS pack_cpio( continue; if (match_suffix && !endswith_no_case(dirent->FileName, match_suffix)) continue; + if (exclude_suffix && endswith_no_case(dirent->FileName, exclude_suffix)) + continue; if (!is_ascii(dirent->FileName)) continue; if (strlen16(dirent->FileName) > 255) /* Max filename size on Linux */ diff --git a/src/boot/efi/cpio.h b/src/boot/efi/cpio.h index 26851e3..9d14fa1 100644 --- a/src/boot/efi/cpio.h +++ b/src/boot/efi/cpio.h @@ -8,6 +8,7 @@ EFI_STATUS pack_cpio( EFI_LOADED_IMAGE_PROTOCOL *loaded_image, const char16_t *dropin_dir, const char16_t *match_suffix, + const char16_t *exclude_suffix, const char *target_dir_prefix, uint32_t dir_mode, uint32_t access_mode, diff --git a/src/boot/efi/efi-string.c b/src/boot/efi/efi-string.c index 4144c0d..3bdb802 100644 --- a/src/boot/efi/efi-string.c +++ b/src/boot/efi/efi-string.c @@ -372,9 +372,9 @@ bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack) { \ uint64_t u = 0; \ while (*s >= '0' && *s <= '9') { \ - if (__builtin_mul_overflow(u, 10, &u)) \ + if (!MUL_ASSIGN_SAFE(&u, 10)) \ return false; \ - if (__builtin_add_overflow(u, *s - '0', &u)) \ + if (!INC_SAFE(&u, *s - '0')) \ return false; \ s++; \ } \ @@ -593,13 +593,13 @@ typedef struct { static void grow_buf(FormatContext *ctx, size_t need) { assert(ctx); - assert_se(!__builtin_add_overflow(ctx->n, need, &need)); + assert_se(INC_SAFE(&need, ctx->n)); if (need < ctx->n_buf) return; /* Greedily allocate if we can. */ - if (__builtin_mul_overflow(need, 2, &ctx->n_buf)) + if (!MUL_SAFE(&ctx->n_buf, need, 2)) ctx->n_buf = need; /* We cannot use realloc here as ctx->buf may be ctx->stack_buf, which we cannot free. */ diff --git a/src/boot/efi/efi.h b/src/boot/efi/efi.h index fbc5d10..e8217c1 100644 --- a/src/boot/efi/efi.h +++ b/src/boot/efi/efi.h @@ -140,6 +140,8 @@ typedef struct { GUID_DEF(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c) #define EFI_IMAGE_SECURITY_DATABASE_GUID \ GUID_DEF(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f) +#define EFI_CUSTOM_MODE_ENABLE_GUID \ + GUID_DEF(0xc076ec0c, 0x7028, 0x4399, 0xa0, 0x72, 0x71, 0xee, 0x5c, 0x44, 0x8b, 0x9f) #define EVT_TIMER 0x80000000U #define EVT_RUNTIME 0x40000000U diff --git a/src/boot/efi/measure.c b/src/boot/efi/measure.c index 01c97c8..08a2ecd 100644 --- a/src/boot/efi/measure.c +++ b/src/boot/efi/measure.c @@ -5,43 +5,11 @@ #include "macro-fundamental.h" #include "measure.h" #include "memory-util-fundamental.h" +#include "proto/cc-measurement.h" #include "proto/tcg.h" #include "tpm2-pcr.h" #include "util.h" -static EFI_STATUS tpm1_measure_to_pcr_and_event_log( - const EFI_TCG_PROTOCOL *tcg, - uint32_t pcrindex, - EFI_PHYSICAL_ADDRESS buffer, - size_t buffer_size, - const char16_t *description) { - - _cleanup_free_ TCG_PCR_EVENT *tcg_event = NULL; - EFI_PHYSICAL_ADDRESS event_log_last; - uint32_t event_number = 1; - size_t desc_len; - - assert(tcg); - assert(description); - - desc_len = strsize16(description); - tcg_event = xmalloc(offsetof(TCG_PCR_EVENT, Event) + desc_len); - *tcg_event = (TCG_PCR_EVENT) { - .EventSize = desc_len, - .PCRIndex = pcrindex, - .EventType = EV_IPL, - }; - memcpy(tcg_event->Event, description, desc_len); - - return tcg->HashLogExtendEvent( - (EFI_TCG_PROTOCOL *) tcg, - buffer, buffer_size, - TCG_ALG_SHA, - tcg_event, - &event_number, - &event_log_last); -} - static EFI_STATUS tpm2_measure_to_pcr_and_tagged_event_log( EFI_TCG2_PROTOCOL *tcg, uint32_t pcrindex, @@ -123,35 +91,67 @@ static EFI_STATUS tpm2_measure_to_pcr_and_event_log( tcg_event); } -static EFI_TCG_PROTOCOL *tcg1_interface_check(void) { - EFI_PHYSICAL_ADDRESS event_log_location, event_log_last_entry; - EFI_TCG_BOOT_SERVICE_CAPABILITY capability = { +static EFI_STATUS cc_measure_to_mr_and_event_log( + EFI_CC_MEASUREMENT_PROTOCOL *cc, + uint32_t pcrindex, + EFI_PHYSICAL_ADDRESS buffer, + uint64_t buffer_size, + const char16_t *description) { + + _cleanup_free_ EFI_CC_EVENT *event = NULL; + uint32_t mr; + EFI_STATUS err; + size_t desc_len; + + assert(cc); + assert(description); + + /* MapPcrToMrIndex service provides callers information on + * how the TPM PCR registers are mapped to the CC measurement + * registers (MR) in the vendor implementation. */ + err = cc->MapPcrToMrIndex(cc, pcrindex, &mr); + if (err != EFI_SUCCESS) + return EFI_NOT_FOUND; + + desc_len = strsize16(description); + event = xmalloc(offsetof(EFI_CC_EVENT, Event) + desc_len); + *event = (EFI_CC_EVENT) { + .Size = offsetof(EFI_CC_EVENT, Event) + desc_len, + .Header.HeaderSize = sizeof(EFI_CC_EVENT_HEADER), + .Header.HeaderVersion = EFI_CC_EVENT_HEADER_VERSION, + .Header.MrIndex = mr, + .Header.EventType = EV_IPL, + }; + + memcpy(event->Event, description, desc_len); + + return cc->HashLogExtendEvent( + cc, + 0, + buffer, + buffer_size, + event); +} + +static EFI_CC_MEASUREMENT_PROTOCOL *cc_interface_check(void) { + EFI_CC_BOOT_SERVICE_CAPABILITY capability = { .Size = sizeof(capability), }; EFI_STATUS err; - uint32_t features; - EFI_TCG_PROTOCOL *tcg; + EFI_CC_MEASUREMENT_PROTOCOL *cc; - err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_TCG_PROTOCOL), NULL, (void **) &tcg); + err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_CC_MEASUREMENT_PROTOCOL), NULL, (void **) &cc); if (err != EFI_SUCCESS) return NULL; - err = tcg->StatusCheck( - tcg, - &capability, - &features, - &event_log_location, - &event_log_last_entry); + err = cc->GetCapability(cc, &capability); if (err != EFI_SUCCESS) return NULL; - if (capability.TPMDeactivatedFlag) + if (!(capability.SupportedEventLogs & EFI_CC_EVENT_LOG_FORMAT_TCG_2)) return NULL; - if (!capability.TPMPresentFlag) - return NULL; - - return tcg; + return cc; } static EFI_TCG2_PROTOCOL *tcg2_interface_check(void) { @@ -184,12 +184,42 @@ static EFI_TCG2_PROTOCOL *tcg2_interface_check(void) { } bool tpm_present(void) { - return tcg2_interface_check() || tcg1_interface_check(); + return tcg2_interface_check(); } -EFI_STATUS tpm_log_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char16_t *description, bool *ret_measured) { +static EFI_STATUS tcg2_log_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char16_t *description, bool *ret_measured) { EFI_TCG2_PROTOCOL *tpm2; + EFI_STATUS err = EFI_SUCCESS; + + assert(ret_measured); + + tpm2 = tcg2_interface_check(); + if (tpm2) + err = tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description); + + *ret_measured = tpm2 && (err == EFI_SUCCESS); + + return err; +} + +static EFI_STATUS cc_log_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char16_t *description, bool *ret_measured) { + EFI_CC_MEASUREMENT_PROTOCOL *cc; + EFI_STATUS err = EFI_SUCCESS; + + assert(ret_measured); + + cc = cc_interface_check(); + if (cc) + err = cc_measure_to_mr_and_event_log(cc, pcrindex, buffer, buffer_size, description); + + *ret_measured = cc && (err == EFI_SUCCESS); + + return err; +} + +EFI_STATUS tpm_log_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char16_t *description, bool *ret_measured) { EFI_STATUS err; + bool tpm_ret_measured, cc_ret_measured; assert(description || pcrindex == UINT32_MAX); @@ -203,27 +233,15 @@ EFI_STATUS tpm_log_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t return EFI_SUCCESS; } - tpm2 = tcg2_interface_check(); - if (tpm2) - err = tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description); - else { - EFI_TCG_PROTOCOL *tpm1; - - tpm1 = tcg1_interface_check(); - if (tpm1) - err = tpm1_measure_to_pcr_and_event_log(tpm1, pcrindex, buffer, buffer_size, description); - else { - /* No active TPM found, so don't return an error */ - - if (ret_measured) - *ret_measured = false; + /* Measure into both CC and TPM if both are available to avoid a problem like CVE-2021-42299 */ + err = cc_log_event(pcrindex, buffer, buffer_size, description, &cc_ret_measured); + if (err != EFI_SUCCESS) + return err; - return EFI_SUCCESS; - } - } + err = tcg2_log_event(pcrindex, buffer, buffer_size, description, &tpm_ret_measured); if (err == EFI_SUCCESS && ret_measured) - *ret_measured = true; + *ret_measured = tpm_ret_measured || cc_ret_measured; return err; } diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build index 43727ef..7a60b0e 100644 --- a/src/boot/efi/meson.build +++ b/src/boot/efi/meson.build @@ -28,7 +28,7 @@ efi_fuzz_template = fuzz_template + efitest_base executables += [ efi_test_template + { 'sources' : files('test-bcd.c'), - 'dependencies' : libzstd, + 'dependencies' : libzstd_cflags, 'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_ZSTD'], }, efi_test_template + { @@ -67,7 +67,8 @@ if meson.is_cross_build() and get_option('sbat-distro') == 'auto' warning('Auto detection of SBAT information not supported when cross-building, disabling SBAT.') elif get_option('sbat-distro') != '' efi_conf.set_quoted('SBAT_PROJECT', meson.project_name()) - efi_conf.set_quoted('PROJECT_VERSION', meson.project_version()) + efi_conf.set_quoted('PROJECT_VERSION', meson.project_version().split('~')[0]) + efi_conf.set_quoted('VERSION_TAG', version_tag) efi_conf.set('PROJECT_URL', conf.get('PROJECT_URL')) if get_option('sbat-distro-generation') < 1 error('SBAT Distro Generation must be a positive integer') @@ -209,11 +210,13 @@ if cc.get_id() == 'clang' endif efi_arch_c_args = { - 'aarch64' : ['-mgeneral-regs-only'], - 'arm' : ['-mgeneral-regs-only'], + 'aarch64' : ['-mgeneral-regs-only'], + 'arm' : ['-mgeneral-regs-only'], + # Until -mgeneral-regs-only is supported in LoongArch, use the following option instead: + 'loongarch64' : ['-mno-lsx', '-mno-lasx'], # Pass -m64/32 explicitly to make building on x32 work. - 'x86_64' : ['-m64', '-march=x86-64', '-mno-red-zone', '-mgeneral-regs-only'], - 'x86' : ['-m32', '-march=i686', '-mgeneral-regs-only', '-malign-double'], + 'x86_64' : ['-m64', '-march=x86-64', '-mno-red-zone', '-mgeneral-regs-only'], + 'x86' : ['-m32', '-march=i686', '-mgeneral-regs-only', '-malign-double'], } efi_arch_c_ld_args = { # libgcc is not compiled with -fshort-wchar, but it does not use it anyways, @@ -385,7 +388,7 @@ foreach efi_elf_binary : efi_elf_binaries install_tag : 'systemd-boot', command : [ elf2efi_py, - '--version-major=' + meson.project_version(), + '--version-major=' + meson.project_version().split('~')[0], '--version-minor=0', '--efi-major=1', '--efi-minor=1', diff --git a/src/boot/efi/part-discovery.c b/src/boot/efi/part-discovery.c index f5b1573..e66e2da 100644 --- a/src/boot/efi/part-discovery.c +++ b/src/boot/efi/part-discovery.c @@ -232,7 +232,7 @@ static EFI_STATUS find_device(const EFI_GUID *type, EFI_HANDLE *device, EFI_DEVI } /* Patch in the data we found */ - *ret_device_path = device_path_replace_node(partition_path, part_node, (EFI_DEVICE_PATH *) &hd); + *ret_device_path = device_path_replace_node(partition_path, part_node, &hd.Header); return EFI_SUCCESS; } diff --git a/src/boot/efi/proto/cc-measurement.h b/src/boot/efi/proto/cc-measurement.h new file mode 100644 index 0000000..9335ecf --- /dev/null +++ b/src/boot/efi/proto/cc-measurement.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "efi.h" + +/* The UEFI specification defines the interface between the confidential virtual guest OS and + * virtual firmware as EFI_CC_MEASUREMENT_PROTOCOL. The measurements are captured in the CC eventlog + * that follows the TCG2 format. TPM PCR registers are mapped to vendor specific measurement registers + * and the mapping can be queried using MapPcrToMrIndex service as part of the protocol. + * + * The "Confidential Computing" section in the UEFI specification covers the details. */ + +#define EFI_CC_MEASUREMENT_PROTOCOL_GUID \ + GUID_DEF(0x96751a3d, 0x72f4, 0x41a6, 0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b) + +#define EFI_CC_EVENT_HEADER_VERSION 1 +#define EFI_CC_EVENT_LOG_FORMAT_TCG_2 0x00000002 + +typedef struct { + uint8_t Type; + uint8_t SubType; +} EFI_CC_TYPE; + +typedef struct { + uint8_t Major; + uint8_t Minor; +} EFI_CC_VERSION; + +typedef struct { + uint8_t Size; + EFI_CC_VERSION StructureVersion; + EFI_CC_VERSION ProtocolVersion; + uint32_t HashAlgorithmBitmap; + uint32_t SupportedEventLogs; + EFI_CC_TYPE CcType; +} EFI_CC_BOOT_SERVICE_CAPABILITY; + +typedef struct { + uint32_t HeaderSize; + uint16_t HeaderVersion; + uint32_t MrIndex; + uint32_t EventType; +} _packed_ EFI_CC_EVENT_HEADER; + +typedef struct { + uint32_t Size; + EFI_CC_EVENT_HEADER Header; + uint8_t Event[]; +} _packed_ EFI_CC_EVENT; + +typedef struct EFI_CC_MEASUREMENT_PROTOCOL EFI_CC_MEASUREMENT_PROTOCOL; +struct EFI_CC_MEASUREMENT_PROTOCOL { + EFI_STATUS (EFIAPI *GetCapability)( + EFI_CC_MEASUREMENT_PROTOCOL *This, + EFI_CC_BOOT_SERVICE_CAPABILITY *ProtocolCapability); + void *GetEventLog; + EFI_STATUS (EFIAPI *HashLogExtendEvent)( + EFI_CC_MEASUREMENT_PROTOCOL *This, + uint64_t Flags, + EFI_PHYSICAL_ADDRESS DataToHash, + uint64_t DataToHashLen, + EFI_CC_EVENT *EfiCcEvent); + EFI_STATUS (EFIAPI *MapPcrToMrIndex)( + EFI_CC_MEASUREMENT_PROTOCOL *This, + uint32_t PcrIndex, + uint32_t *MrIndex); +}; diff --git a/src/boot/efi/proto/tcg.h b/src/boot/efi/proto/tcg.h index b4b8296..e243bf8 100644 --- a/src/boot/efi/proto/tcg.h +++ b/src/boot/efi/proto/tcg.h @@ -3,12 +3,9 @@ #include "efi.h" -#define EFI_TCG_PROTOCOL_GUID \ - GUID_DEF(0xf541796d, 0xa62e, 0x4954, 0xa7, 0x75, 0x95, 0x84, 0xf6, 0x1b, 0x9c, 0xdd) #define EFI_TCG2_PROTOCOL_GUID \ GUID_DEF(0x607f766c, 0x7455, 0x42be, 0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f) -#define TCG_ALG_SHA 0x4 #define EFI_TCG2_EVENT_HEADER_VERSION 1 #define EV_IPL 13 #define EV_EVENT_TAG UINT32_C(6) @@ -49,16 +46,6 @@ typedef struct { } EFI_TCG2_BOOT_SERVICE_CAPABILITY; typedef struct { - uint32_t PCRIndex; - uint32_t EventType; - struct { - uint8_t Digest[20]; - } Digest; - uint32_t EventSize; - uint8_t Event[]; -} _packed_ TCG_PCR_EVENT; - -typedef struct { uint32_t HeaderSize; uint16_t HeaderVersion; uint32_t PCRIndex; @@ -77,27 +64,6 @@ typedef struct { uint8_t Event[]; } _packed_ EFI_TCG2_TAGGED_EVENT; -typedef struct EFI_TCG_PROTOCOL EFI_TCG_PROTOCOL; -struct EFI_TCG_PROTOCOL { - EFI_STATUS (EFIAPI *StatusCheck)( - EFI_TCG_PROTOCOL *This, - EFI_TCG_BOOT_SERVICE_CAPABILITY *ProtocolCapability, - uint32_t *TCGFeatureFlags, - EFI_PHYSICAL_ADDRESS *EventLogLocation, - EFI_PHYSICAL_ADDRESS *EventLogLastEntry); - void *HashAll; - void *LogEvent; - void *PassThroughToTpm; - EFI_STATUS (EFIAPI *HashLogExtendEvent)( - EFI_TCG_PROTOCOL *This, - EFI_PHYSICAL_ADDRESS HashData, - uint64_t HashDataLen, - uint32_t AlgorithmId, - TCG_PCR_EVENT *TCGLogData, - uint32_t *EventNumber, - EFI_PHYSICAL_ADDRESS *EventLogLastEntry); -}; - typedef struct EFI_TCG2_PROTOCOL EFI_TCG2_PROTOCOL; struct EFI_TCG2_PROTOCOL { EFI_STATUS (EFIAPI *GetCapability)( diff --git a/src/boot/efi/random-seed.c b/src/boot/efi/random-seed.c index 8147e54..03f3ebd 100644 --- a/src/boot/efi/random-seed.c +++ b/src/boot/efi/random-seed.c @@ -4,7 +4,7 @@ #include "proto/rng.h" #include "random-seed.h" #include "secure-boot.h" -#include "sha256.h" +#include "sha256-fundamental.h" #include "util.h" #define RANDOM_MAX_SIZE_MIN (32U) diff --git a/src/boot/efi/secure-boot.c b/src/boot/efi/secure-boot.c index f76d2f4..2400324 100644 --- a/src/boot/efi/secure-boot.c +++ b/src/boot/efi/secure-boot.c @@ -32,10 +32,46 @@ SecureBootMode secure_boot_mode(void) { return decode_secure_boot_mode(secure, audit, deployed, setup); } +/* + * Custom mode allows the secure boot certificate databases db, dbx, KEK, and PK to be changed without the variable + * updates being signed. When enrolling certificates to an unconfigured system (no PK present yet) writing + * db, dbx and KEK updates without signature works fine even in standard mode. Writing PK updates without + * signature requires custom mode in any case. + * + * Enabling custom mode works only if a user is physically present. Note that OVMF has a dummy + * implementation for the user presence check (there is no useful way to implement a presence check for a + * virtual machine). + * + * FYI: Your firmware setup utility might offers the option to enroll certificates from *.crt files + * (DER-encoded x509 certificates) on the ESP; that uses custom mode too. Your firmware setup might also + * offer the option to switch the system into custom mode for the next boot. + */ +static bool custom_mode_enabled(void) { + bool enabled = false; + + (void) efivar_get_boolean_u8(MAKE_GUID_PTR(EFI_CUSTOM_MODE_ENABLE), + u"CustomMode", &enabled); + return enabled; +} + +static EFI_STATUS set_custom_mode(bool enable) { + static char16_t name[] = u"CustomMode"; + static uint32_t attr = + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS; + uint8_t mode = enable + ? 1 /* CUSTOM_SECURE_BOOT_MODE */ + : 0; /* STANDARD_SECURE_BOOT_MODE */ + + return RT->SetVariable(name, MAKE_GUID_PTR(EFI_CUSTOM_MODE_ENABLE), + attr, sizeof(mode), &mode); +} + EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool force) { assert(root_dir); assert(path); + bool need_custom_mode = false; EFI_STATUS err; clear_screen(COLOR_NORMAL); @@ -88,21 +124,47 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool const char16_t *name; const char16_t *filename; const EFI_GUID vendor; + bool required; char *buffer; size_t size; } sb_vars[] = { - { u"db", u"db.auth", EFI_IMAGE_SECURITY_DATABASE_GUID, NULL, 0 }, - { u"KEK", u"KEK.auth", EFI_GLOBAL_VARIABLE, NULL, 0 }, - { u"PK", u"PK.auth", EFI_GLOBAL_VARIABLE, NULL, 0 }, + { u"db", u"db.auth", EFI_IMAGE_SECURITY_DATABASE_GUID, true }, + { u"dbx", u"dbx.auth", EFI_IMAGE_SECURITY_DATABASE_GUID, false }, + { u"KEK", u"KEK.auth", EFI_GLOBAL_VARIABLE, true }, + { u"PK", u"PK.auth", EFI_GLOBAL_VARIABLE, true }, }; /* Make sure all keys files exist before we start enrolling them by loading them from the disk first. */ for (size_t i = 0; i < ELEMENTSOF(sb_vars); i++) { err = file_read(dir, sb_vars[i].filename, 0, 0, &sb_vars[i].buffer, &sb_vars[i].size); - if (err != EFI_SUCCESS) { + if (err != EFI_SUCCESS && sb_vars[i].required) { log_error_status(err, "Failed reading file %ls\\%ls: %m", path, sb_vars[i].filename); goto out_deallocate; } + if (streq16(sb_vars[i].name, u"PK") && sb_vars[i].size > 20) { + assert(sb_vars[i].buffer); + /* + * The buffer should be EFI_TIME (16 bytes), followed by + * EFI_VARIABLE_AUTHENTICATION_2 header. First header field is the size. If the + * size covers only the header itself (8 bytes) plus the signature type guid (16 + * bytes), leaving no space for an actual signature, we can conclude that no + * signature is present. + */ + uint32_t *sigsize = (uint32_t*)(sb_vars[i].buffer + 16); + if (*sigsize <= 24) { + printf("PK is not signed (need custom mode).\n"); + need_custom_mode = true; + } + } + } + + if (need_custom_mode && !custom_mode_enabled()) { + err = set_custom_mode(/* enable */ true); + if (err != EFI_SUCCESS) { + log_error_status(err, "Failed to enable custom mode: %m"); + goto out_deallocate; + } + printf("Custom mode enabled.\n"); } for (size_t i = 0; i < ELEMENTSOF(sb_vars); i++) { @@ -112,6 +174,9 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + if (!sb_vars[i].buffer) + continue; + err = efivar_set_raw(&sb_vars[i].vendor, sb_vars[i].name, sb_vars[i].buffer, sb_vars[i].size, sb_vars_opts); if (err != EFI_SUCCESS) { log_error_status(err, "Failed to write %ls secure boot variable: %m", sb_vars[i].name); 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); } diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c index e56ccfd..b5c8c63 100644 --- a/src/boot/efi/util.c +++ b/src/boot/efi/util.c @@ -303,7 +303,7 @@ EFI_STATUS chunked_read(EFI_FILE *file, size_t *size, void *buf) { * Some broken firmwares cannot handle large file reads and will instead return * an error. As a workaround, read such files in small chunks. * Note that we cannot just try reading the whole file first on such firmware as - * that will permanently break the handle even if it is re-opened. + * that will permanently break the handle even if it is reopened. * * https://github.com/systemd/systemd/issues/25911 */ diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h index 0306e32..ceac07c 100644 --- a/src/boot/efi/util.h +++ b/src/boot/efi/util.h @@ -33,7 +33,7 @@ void *xmalloc(size_t size); _malloc_ _alloc_(1, 2) _returns_nonnull_ _warn_unused_result_ static inline void *xmalloc_multiply(size_t n, size_t size) { - assert_se(!__builtin_mul_overflow(size, n, &size)); + assert_se(MUL_ASSIGN_SAFE(&size, n)); return xmalloc(size); } @@ -84,7 +84,7 @@ static inline Pages xmalloc_pages( EFI_STATUS efivar_set(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags); EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const char16_t *name, const void *buf, size_t size, uint32_t flags); EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, const char16_t *name, size_t i, uint32_t flags); -EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *NAME, uint32_t value, uint32_t flags); +EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t value, uint32_t flags); EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t value, uint32_t flags); void efivar_set_time_usec(const EFI_GUID *vendor, const char16_t *name, uint64_t usec); diff --git a/src/boot/efi/vmm.h b/src/boot/efi/vmm.h index df48af3..1d1037b 100644 --- a/src/boot/efi/vmm.h +++ b/src/boot/efi/vmm.h @@ -4,7 +4,7 @@ #include "efi.h" bool is_direct_boot(EFI_HANDLE device); -EFI_STATUS vmm_open(EFI_HANDLE *ret_qemu_dev, EFI_FILE **ret_qemu_dir); +EFI_STATUS vmm_open(EFI_HANDLE *ret_vmm_dev, EFI_FILE **ret_vmm_dir); bool in_hypervisor(void); |