Merge pull request #22761 from poettering/pcr-fix

sd-boot: change kernel cmdline PCR from 8 to 12
This commit is contained in:
Lennart Poettering 2022-03-16 22:32:43 +01:00 committed by GitHub
commit e127ac90ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 76 additions and 34 deletions

13
NEWS
View file

@ -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.

View file

@ -214,6 +214,8 @@
<!-- See: https://github.com/rhboot/shim/blob/main/README.tpm -->
<!-- See: https://www.gnu.org/software/grub/manual/grub/html_node/Measured-Boot.html -->
<!-- See: https://sourceforge.net/p/linux-ima/wiki/Home/ -->
<!-- See: https://github.com/tianocore-docs/edk2-TrustedBootChain/blob/main/4_Other_Trusted_Boot_Chains.md -->
<!-- See: https://wiki.archlinux.org/title/Trusted_Platform_Module#Accessing_PCR_registers -->
<tgroup cols='2' align='left' colsep='1' rowsep='1'>
<colspec colname="pcr" />
@ -267,14 +269,14 @@
<entry>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.</entry>
</row>
<row>
<entry>8</entry>
<entry><citerefentry><refentrytitle>sd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> measures the kernel command line into this PCR.</entry>
<!-- Grub measures all its commands and the kernel command line into PCR 8 too… -->
</row>
<!-- Grub measures all its commands and the kernel command line into PCR 8… -->
<!-- Grub measures all files it reads (including kernel image, initrd, …) into PCR 9… -->
<row>
<entry>12</entry>
<entry><citerefentry><refentrytitle>sd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> measures the kernel command line into this PCR.</entry>
</row>
<row>
<entry>10</entry>
<entry>The IMA project measures its runtime state into this PCR.</entry>

View file

@ -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,

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -3,10 +3,24 @@
#include <efi.h>
/* 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;
}

View file

@ -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(',')

View file

@ -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);

View file

@ -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)