diff --git a/NEWS b/NEWS index df729dc7696..a1d9447bad9 100644 --- a/NEWS +++ b/NEWS @@ -120,6 +120,19 @@ CHANGES WITH 251: 250. For newer kernels, non-x86 systems, or older x86 systems, there should be no visible changes. + * sd-boot will now measure the kernel command line into TPM PCR 12 + rather than PCR 8. This improves usefulness of the measurements on + sytems where sd-boot is chainloaded from Grub. Grub measures all + commands its executes into PCR 8, which makes it very hard to use + reasonably, hence separate ourselves from that and use PCR 12 + instead, which is already what certain Ubuntu editions use it for. To + retain compatibility with systems running older systemd systems a new + Meson option 'efi-tpm-pcr-compat' has been added (which defaults to + false). If enabled, the measurement is done twice: into the new-style + PCR 12 *and* the old-style PCR 8. It's strongly advised to migrate + all users to PCR 12 for this purpose in the long run, as we intend to + remove this compatibility feature again in two year's time. + CHANGES WITH 250: * Support for encrypted and authenticated credentials has been added. diff --git a/man/systemd-cryptenroll.xml b/man/systemd-cryptenroll.xml index 58a46267680..02f932edfba 100644 --- a/man/systemd-cryptenroll.xml +++ b/man/systemd-cryptenroll.xml @@ -214,6 +214,8 @@ + + @@ -267,14 +269,14 @@ Secure boot state; changes when UEFI SecureBoot mode is enabled/disabled, or firmware certificates (PK, KEK, db, dbx, …) changes. The shim project will measure most of its (non-MOK) certificates and SBAT data into this PCR. - - 8 - sd-boot7 measures the kernel command line into this PCR. - - - + + + 12 + sd-boot7 measures the kernel command line into this PCR. + + 10 The IMA project measures its runtime state into this PCR. 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 2855c4119be..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, - UINTN 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 a272d289298..5f6698fd128 100644 --- a/src/boot/efi/cpio.h +++ b/src/boot/efi/cpio.h @@ -10,8 +10,8 @@ EFI_STATUS pack_cpio( const CHAR8 *target_dir_prefix, UINT32 dir_mode, UINT32 access_mode, - UINTN 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 992acde527c..da4fd18ea8c 100644 --- a/src/boot/efi/measure.c +++ b/src/boot/efi/measure.c @@ -139,12 +139,16 @@ BOOLEAN tpm_present(void) { return tcg2_interface_check() || tcg1_interface_check(); } -EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) { +EFI_STATUS tpm_log_event(UINT32 pcrindex, EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) { EFI_TCG *tpm1; EFI_TCG2 *tpm2; 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 ffa49245626..7a817b22d8d 100644 --- a/src/boot/efi/measure.h +++ b/src/boot/efi/measure.h @@ -3,10 +3,24 @@ #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); -EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description); +EFI_STATUS tpm_log_event(UINT32 pcrindex, EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description); EFI_STATUS tpm_log_load_options(const CHAR16 *cmdline); #else @@ -14,9 +28,11 @@ EFI_STATUS tpm_log_load_options(const CHAR16 *cmdline); static inline BOOLEAN tpm_present(void) { return FALSE; } -static inline EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) { + +static inline EFI_STATUS tpm_log_event(UINT32 pcrindex, EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) { return EFI_SUCCESS; } + static inline EFI_STATUS tpm_log_load_options(const CHAR16 *cmdline) { return EFI_SUCCESS; } 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)