]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
boot: report missing GetActivePcrBanks() call in formware as UINT32_MAX PCR bank...
authorLennart Poettering <lennart@poettering.net>
Thu, 13 Nov 2025 08:30:43 +0000 (09:30 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 14 Nov 2025 21:22:39 +0000 (22:22 +0100)
Fixes: #39150
src/boot/measure.c
src/shared/efi-api.c
src/shared/tpm2-util.c

index b1433ff1b50694bd9dbedaf40e0591708f14e9b6..22129cb87d61d207d9626ee50d2c3bc7b82941c9 100644 (file)
@@ -198,8 +198,8 @@ uint32_t tpm_get_active_pcr_banks(void) {
 
         /* GetActivePcrBanks() was added only in version 1.1 of the spec */
         if (version.Major < 1 || (version.Major == 1 && version.Minor < 1)) {
-                log_debug("TCG protocol too old for GetActivePcrBanks(), claiming no active banks.");
-                return 0;
+                log_debug("TCG protocol too old for GetActivePcrBanks(), returning wildcard bank information.");
+                return UINT32_MAX;
         }
 
         uint32_t active_pcr_banks = 0;
index 608001b6e2d158e415829f15d6f9453c3433de0c..ad9cbab74e132ad394f38ee3468aa2ceb2b5bbce 100644 (file)
@@ -525,10 +525,15 @@ int efi_get_boot_options(uint16_t **ret_options) {
 
 int efi_get_active_pcr_banks(uint32_t *ret) {
 #if ENABLE_EFI
-        static uint32_t cache = UINT32_MAX;
+        static uint32_t cache = 0;
+        static bool cache_valid = false;
         int r;
 
-        if (cache == UINT32_MAX) {
+        /* Returns the enabled PCR banks as bitmask, as reported by firmware. If the bitmask is returned as
+         * UINT32_MAX, the firmware supports the TCG protocol, but in a version too old to report this
+         * information. */
+
+        if (!cache_valid) {
                 _cleanup_free_ char *active_pcr_banks = NULL;
                 r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderTpm2ActivePcrBanks"), &active_pcr_banks);
                 if (r < 0)
@@ -539,22 +544,29 @@ int efi_get_active_pcr_banks(uint32_t *ret) {
                 if (r < 0)
                         return log_debug_errno(r, "Failed to parse LoaderTpm2ActivePcrBanks variable: %m");
 
-                /* EFI TPM protocol uses different bit values for the hash algorithms, let's convert */
-                static const struct {
-                        uint32_t efi;
-                        uint32_t tcg;
-                } table[] = {
-                        { EFI_TCG2_BOOT_HASH_ALG_SHA1,   1U << TPM2_ALG_SHA1   },
-                        { EFI_TCG2_BOOT_HASH_ALG_SHA256, 1U << TPM2_ALG_SHA256 },
-                        { EFI_TCG2_BOOT_HASH_ALG_SHA384, 1U << TPM2_ALG_SHA384 },
-                        { EFI_TCG2_BOOT_HASH_ALG_SHA512, 1U << TPM2_ALG_SHA512 },
-                };
-
-                uint32_t tcg_bits = 0;
-                FOREACH_ELEMENT(t, table)
-                        SET_FLAG(tcg_bits, t->tcg, efi_bits & t->efi);
-
-                cache = tcg_bits;
+                if (efi_bits == UINT32_MAX)
+                        /* UINT32_MAX means that the firmware API doesn't implement GetActivePcrBanks() and caller must guess */
+                        cache = UINT32_MAX;
+                else {
+                        /* EFI TPM protocol uses different bit values for the hash algorithms, let's convert */
+                        static const struct {
+                                uint32_t efi;
+                                uint32_t tcg;
+                        } table[] = {
+                                { EFI_TCG2_BOOT_HASH_ALG_SHA1,   1U << TPM2_ALG_SHA1   },
+                                { EFI_TCG2_BOOT_HASH_ALG_SHA256, 1U << TPM2_ALG_SHA256 },
+                                { EFI_TCG2_BOOT_HASH_ALG_SHA384, 1U << TPM2_ALG_SHA384 },
+                                { EFI_TCG2_BOOT_HASH_ALG_SHA512, 1U << TPM2_ALG_SHA512 },
+                        };
+
+                        uint32_t tcg_bits = 0;
+                        FOREACH_ELEMENT(t, table)
+                                SET_FLAG(tcg_bits, t->tcg, efi_bits & t->efi);
+
+                        cache = tcg_bits;
+                }
+
+                cache_valid = true;
         }
 
         if (ret)
index de7e3d9728c01557d559bb5cff6ac9aa3d51eb6d..c74162302caeb9ae7bfca349b87eaf1c00202945 100644 (file)
@@ -2705,7 +2705,9 @@ int tpm2_get_best_pcr_bank(
 
                 /* If variable is not set use guesswork below */
                 log_debug("Boot loader didn't set the LoaderTpm2ActivePcrBanks EFI variable, we have to guess the used PCR banks.");
-        } else {
+        } else if (efi_banks == UINT32_MAX)
+                log_debug("Boot loader set the LoaderTpm2ActivePcrBanks EFI variable to indicate that the GetActivePcrBanks() API is not available in the firmware. We have to guess the used PCR banks.");
+        else {
                 if (BIT_SET(efi_banks, TPM2_ALG_SHA256))
                         *ret = TPM2_ALG_SHA256;
                 else if (BIT_SET(efi_banks, TPM2_ALG_SHA1))
@@ -2812,7 +2814,9 @@ int tpm2_get_good_pcr_banks(
 
                 /* If the variable is not set we have to guess via the code below */
                 log_debug("Boot loader didn't set the LoaderTpm2ActivePcrBanks EFI variable, we have to guess the used PCR banks.");
-        } else {
+        } else if (efi_banks == UINT32_MAX)
+                log_debug("Boot loader set the LoaderTpm2ActivePcrBanks EFI variable to indicate that the GetActivePcrBanks() API is not available in the firmware. We have to guess the used PCR banks.");
+        else {
                 FOREACH_ARRAY(hash, tpm2_hash_algorithms, TPM2_N_HASH_ALGORITHMS) {
                         if (!BIT_SET(efi_banks, *hash))
                                 continue;