From 4d32507f5186a89e98093659fbbe386787a97b9f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 16 Mar 2022 10:51:03 +0100 Subject: [PATCH] sd-boot: measure kernel cmdline into PCR 12 rather than 8 Apparently Grub is measuring all kinds of garbage into PCR 8. Since people apparently chainload sd-boot from grub, let's thus stay away from PCR 8, and use PCR 12 instead for the kernel command line. As discussed here: #22635 Fixes: #22635 --- meson_options.txt | 2 ++ src/boot/efi/cpio.c | 20 ++++++++++++-------- src/boot/efi/cpio.h | 3 ++- src/boot/efi/measure.c | 18 +++++++++++++----- src/boot/efi/measure.h | 14 ++++++++++++++ src/boot/efi/meson.build | 1 + src/boot/efi/stub.c | 9 ++++++--- src/boot/efi/util.h | 7 ------- 8 files changed, 50 insertions(+), 24 deletions(-) diff --git a/meson_options.txt b/meson_options.txt index 5d635748d58..284109cadf4 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -426,6 +426,8 @@ option('efi-libdir', type : 'string', description : 'path to the EFI lib directory') option('efi-includedir', type : 'string', value : '/usr/include/efi', description : 'path to the EFI header directory') +option('efi-tpm-pcr-compat', type : 'boolean', value : 'false', + description : 'Measure kernel command line also into TPM PCR 8 (in addition to 12)') option('sbat-distro', type : 'string', value : 'auto', description : 'SBAT distribution ID, e.g. fedora, or auto for autodetection') option('sbat-distro-generation', type : 'integer', value : 1, diff --git a/src/boot/efi/cpio.c b/src/boot/efi/cpio.c index a4da4a97fec..14957130be0 100644 --- a/src/boot/efi/cpio.c +++ b/src/boot/efi/cpio.c @@ -311,7 +311,8 @@ EFI_STATUS pack_cpio( const CHAR8 *target_dir_prefix, UINT32 dir_mode, UINT32 access_mode, - UINT32 tpm_pcr, + const UINT32 tpm_pcr[], + UINTN n_tpm_pcr, const CHAR16 *tpm_description, void **ret_buffer, UINTN *ret_buffer_size) { @@ -328,6 +329,7 @@ EFI_STATUS pack_cpio( assert(loaded_image); assert(target_dir_prefix); + assert(tpm_pcr || n_tpm_pcr == 0); assert(ret_buffer); assert(ret_buffer_size); @@ -449,13 +451,15 @@ EFI_STATUS pack_cpio( if (EFI_ERROR(err)) return log_error_status_stall(err, L"Failed to pack cpio trailer: %r"); - err = tpm_log_event( - tpm_pcr, - POINTER_TO_PHYSICAL_ADDRESS(buffer), - buffer_size, - tpm_description); - if (EFI_ERROR(err)) - log_error_stall(L"Unable to add initrd TPM measurement for PCR %u (%s), ignoring: %r", tpm_pcr, tpm_description, err); + for (UINTN i = 0; i < n_tpm_pcr; i++) { + err = tpm_log_event( + tpm_pcr[i], + POINTER_TO_PHYSICAL_ADDRESS(buffer), + buffer_size, + tpm_description); + if (EFI_ERROR(err)) + log_error_stall(L"Unable to add initrd TPM measurement for PCR %u (%s), ignoring: %r", tpm_pcr[i], tpm_description, err); + } *ret_buffer = TAKE_PTR(buffer); *ret_buffer_size = buffer_size; diff --git a/src/boot/efi/cpio.h b/src/boot/efi/cpio.h index 93ee4c43106..5f6698fd128 100644 --- a/src/boot/efi/cpio.h +++ b/src/boot/efi/cpio.h @@ -10,7 +10,8 @@ EFI_STATUS pack_cpio( const CHAR8 *target_dir_prefix, UINT32 dir_mode, UINT32 access_mode, - UINT32 tpm_pcr, + const UINT32 tpm_pcr[], + UINTN n_tpm_pcr, const CHAR16 *tpm_description, void **ret_buffer, UINTN *ret_buffer_size); diff --git a/src/boot/efi/measure.c b/src/boot/efi/measure.c index 5c082b537c7..da4fd18ea8c 100644 --- a/src/boot/efi/measure.c +++ b/src/boot/efi/measure.c @@ -145,6 +145,10 @@ EFI_STATUS tpm_log_event(UINT32 pcrindex, EFI_PHYSICAL_ADDRESS buffer, UINTN buf assert(description); + /* PCR disabled */ + if (pcrindex == UINT32_MAX) + return EFI_SUCCESS; + tpm2 = tcg2_interface_check(); if (tpm2) return tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description); @@ -162,11 +166,15 @@ EFI_STATUS tpm_log_load_options(const CHAR16 *load_options) { /* Measures a load options string into the TPM2, i.e. the kernel command line */ - err = tpm_log_event(TPM_PCR_INDEX_KERNEL_PARAMETERS, - POINTER_TO_PHYSICAL_ADDRESS(load_options), - StrSize(load_options), load_options); - if (EFI_ERROR(err)) - return log_error_status_stall(err, L"Unable to add load options (i.e. kernel command) line measurement: %r", err); + for (UINTN i = 0; i < 2; i++) { + UINT32 pcr = i == 0 ? TPM_PCR_INDEX_KERNEL_PARAMETERS : TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT; + + err = tpm_log_event(pcr, + POINTER_TO_PHYSICAL_ADDRESS(load_options), + StrSize(load_options), load_options); + if (EFI_ERROR(err)) + return log_error_status_stall(err, L"Unable to add load options (i.e. kernel command) line measurement to PCR %u: %r", pcr, err); + } return EFI_SUCCESS; } diff --git a/src/boot/efi/measure.h b/src/boot/efi/measure.h index 33c98aaf733..7a817b22d8d 100644 --- a/src/boot/efi/measure.h +++ b/src/boot/efi/measure.h @@ -3,6 +3,20 @@ #include +/* This TPM PCR is where we extend the kernel command line and any passed credentials here. */ +#define TPM_PCR_INDEX_KERNEL_PARAMETERS 12U + +/* We used to write the the kernel command line/credentials into PCR 8, in systemd <= 250. Let's provide for + * some compatibility. (Remove in 2023!) */ +#if EFI_TPM_PCR_COMPAT +#define TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT 8U +#else +#define TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT UINT32_MAX +#endif + +/* This TPM PCR is where most Linux infrastructure extends the initrd binary images into, and so do we. */ +#define TPM_PCR_INDEX_INITRD 4U + #if ENABLE_TPM BOOLEAN tpm_present(void); diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build index f6004e47ecc..ffee98bbb83 100644 --- a/src/boot/efi/meson.build +++ b/src/boot/efi/meson.build @@ -104,6 +104,7 @@ conf.set_quoted('EFI_MACHINE_TYPE_NAME', efi_arch[0]) efi_conf = configuration_data() efi_conf.set_quoted('EFI_MACHINE_TYPE_NAME', efi_arch[0]) efi_conf.set10('ENABLE_TPM', get_option('tpm')) +efi_conf.set10('EFI_TPM_PCR_COMPAT', get_option('efi-tpm-pcr-compat')) foreach ctype : ['color-normal', 'color-entry', 'color-highlight', 'color-edit'] c = get_option('efi-' + ctype).split(',') diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index 22554a48604..73d06de7f11 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -234,7 +234,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { (const CHAR8*) ".extra/credentials", /* dir_mode= */ 0500, /* access_mode= */ 0400, - /* tpm_pcr= */ TPM_PCR_INDEX_KERNEL_PARAMETERS, + /* tpm_pcr= */ (UINT32[]) { TPM_PCR_INDEX_KERNEL_PARAMETERS, TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT }, + /* n_tpm_pcr= */ 2, L"Credentials initrd", &credential_initrd, &credential_initrd_size); @@ -245,7 +246,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { (const CHAR8*) ".extra/global_credentials", /* dir_mode= */ 0500, /* access_mode= */ 0400, - /* tpm_pcr= */ TPM_PCR_INDEX_KERNEL_PARAMETERS, + /* tpm_pcr= */ (UINT32[]) { TPM_PCR_INDEX_KERNEL_PARAMETERS, TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT }, + /* n_tpm_pcr= */ 2, L"Global credentials initrd", &global_credential_initrd, &global_credential_initrd_size); @@ -256,7 +258,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { (const CHAR8*) ".extra/sysext", /* dir_mode= */ 0555, /* access_mode= */ 0444, - /* tpm_pcr= */ TPM_PCR_INDEX_INITRD, + /* tpm_pcr= */ (UINT32[]) { TPM_PCR_INDEX_INITRD }, + /* n_tpm_pcr= */ 1, L"System extension initrd", &sysext_initrd, &sysext_initrd_size); diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h index 33b17d04fbb..93dd2da566f 100644 --- a/src/boot/efi/util.h +++ b/src/boot/efi/util.h @@ -6,13 +6,6 @@ #include "string-util-fundamental.h" -/* This TPM PCR is where most Linux infrastructure extends the kernel command line into, and so do we. We also extend - * any passed credentials here. */ -#define TPM_PCR_INDEX_KERNEL_PARAMETERS 8 - -/* This TPM PCR is where most Linux infrastructure extends the initrd binary images into, and so do we. */ -#define TPM_PCR_INDEX_INITRD 4 - #define offsetof(type, member) __builtin_offsetof(type, member) #define UINTN_MAX (~(UINTN)0)