From 9b2c8ae5d22463974916fa476f419a5809bc3f6b Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 10 Dec 2025 23:47:53 +0000 Subject: [PATCH] commands/bli: Set UINT32_MAX in LoaderTpm2ActivePcrBanks if TPM2 present but no banks protocol The implementation in sd-boot was changed to return UINT32_MAX when the EFI environment detects a working TPM2, but with an older firmware that doesn't implement the protocol to get the list of active banks. This allows distinguishing with the case where there is no working TPM2, in which case userspace just gives up, and instead lets userspace try to figure it out later. Fixes: f326c5c47 (commands/bli: Set LoaderTpm2ActivePcrBanks runtime variable) Signed-off-by: Luca Boccassi Reviewed-by: Daniel Kiper --- grub-core/commands/efi/tpm.c | 65 ++++++++++++++---------------------- 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c index 7b493c890..96b509031 100644 --- a/grub-core/commands/efi/tpm.c +++ b/grub-core/commands/efi/tpm.c @@ -39,7 +39,7 @@ static grub_uint8_t grub_tpm_version; static grub_int8_t tpm1_present = -1; static grub_int8_t tpm2_present = -1; -static grub_int8_t tpm2_pcr_banks_reporting_present = -1; +static grub_efi_int64_t tpm2_active_pcr_banks = -1; static grub_efi_boolean_t grub_tpm1_present (grub_efi_tpm_protocol_t *tpm) @@ -90,34 +90,6 @@ grub_tpm2_present (grub_efi_tpm2_protocol_t *tpm) return (grub_efi_boolean_t) tpm2_present; } -static grub_efi_boolean_t -grub_tpm2_pcr_banks_reporting_present (grub_efi_tpm2_protocol_t *tpm) -{ - grub_efi_status_t status; - EFI_TCG2_BOOT_SERVICE_CAPABILITY caps; - - caps.Size = (grub_uint8_t) sizeof (caps); - - if (tpm2_pcr_banks_reporting_present != -1) - return (grub_efi_boolean_t) tpm2_pcr_banks_reporting_present; - - if (!grub_tpm2_present (tpm)) - return (grub_efi_boolean_t) (tpm2_pcr_banks_reporting_present = 0); - - status = tpm->get_capability (tpm, &caps); - - if (status != GRUB_EFI_SUCCESS || caps.StructureVersion.Major < 1 - || (caps.StructureVersion.Major == 1 && caps.StructureVersion.Minor < 1)) - tpm2_pcr_banks_reporting_present = 0; - else - tpm2_pcr_banks_reporting_present = 1; - - grub_dprintf ("tpm", "tpm2 PCR banks reporting%s present\n", - tpm2_pcr_banks_reporting_present ? "" : " NOT"); - - return (grub_efi_boolean_t) tpm2_pcr_banks_reporting_present; -} - static grub_efi_boolean_t grub_tpm_handle_find (grub_efi_handle_t *tpm_handle, grub_efi_uint8_t *protocol_version) @@ -365,32 +337,45 @@ grub_tpm_present (void) grub_uint32_t grub_tpm2_active_pcr_banks (void) { + EFI_TCG2_BOOT_SERVICE_CAPABILITY caps; grub_efi_handle_t tpm_handle; grub_efi_uint8_t protocol_version; grub_efi_tpm2_protocol_t *tpm; - grub_efi_uint32_t active_pcr_banks = 0; + grub_efi_uint32_t active_pcr_banks; + grub_efi_status_t status; + + if (tpm2_active_pcr_banks >= 0) + return (grub_uint32_t) tpm2_active_pcr_banks; if (!grub_tpm_handle_find (&tpm_handle, &protocol_version)) - return 0; + return (grub_uint32_t) (tpm2_active_pcr_banks = 0); if (protocol_version == 1) - return 0; /* We report TPM2 status */ + return (grub_uint32_t) (tpm2_active_pcr_banks = 0); /* We report TPM2 status. */ tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (tpm == NULL) { grub_dprintf ("tpm", "Cannot open TPM2 protocol\n"); - return 0; + return (grub_uint32_t) (tpm2_active_pcr_banks = 0); } - if (grub_tpm2_pcr_banks_reporting_present (tpm)) - { - grub_efi_status_t status = tpm->get_active_pcr_banks (tpm, &active_pcr_banks); + if (!grub_tpm2_present (tpm)) + return (grub_uint32_t) (tpm2_active_pcr_banks = 0); - if (status != GRUB_EFI_SUCCESS) - return 0; /* Assume none available if the call fails. */ - } + caps.Size = (grub_uint8_t) sizeof (caps); + status = tpm->get_capability (tpm, &caps); + if (status != GRUB_EFI_SUCCESS) + return (grub_uint32_t) (tpm2_active_pcr_banks = 0); + if (caps.StructureVersion.Major < 1 || + (caps.StructureVersion.Major == 1 && caps.StructureVersion.Minor < 1)) + /* There's a working TPM2 but without querying protocol, let userspace figure it out. */ + return (grub_uint32_t) (tpm2_active_pcr_banks = GRUB_UINT_MAX); - return active_pcr_banks; + status = tpm->get_active_pcr_banks (tpm, &active_pcr_banks); + if (status != GRUB_EFI_SUCCESS) + return (grub_uint32_t) (tpm2_active_pcr_banks = 0); /* Assume none available if the call fails. */ + + return (grub_uint32_t) (tpm2_active_pcr_banks = active_pcr_banks); }