]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
boot: check protocol version before assuming GetActiveBanks() exists
authorLennart Poettering <lennart@poettering.net>
Tue, 23 Sep 2025 11:42:02 +0000 (13:42 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 10 Oct 2025 08:36:47 +0000 (10:36 +0200)
Alternative to: #39034
Fixes: #38932
Follow-up to: 6eab4cd44c3c43698dcfc2c3bc8cd31ed610a812

(cherry picked from commit b388fa20c735add38080a746fd831273820c93ac)

src/boot/measure.c

index e097e6676e69aade5b61deb522d989cc36f4f40f..b1433ff1b50694bd9dbedaf40e0591708f14e9b6 100644 (file)
@@ -150,7 +150,7 @@ static EFI_CC_MEASUREMENT_PROTOCOL *cc_interface_check(void) {
         return cc;
 }
 
-static EFI_TCG2_PROTOCOL *tcg2_interface_check(void) {
+static EFI_TCG2_PROTOCOL* tcg2_interface_check(EFI_TCG2_VERSION *ret_version) {
         EFI_STATUS err;
 
         EFI_TCG2_PROTOCOL *tcg;
@@ -167,28 +167,42 @@ static EFI_TCG2_PROTOCOL *tcg2_interface_check(void) {
 
         assert(capability.Size >= endoffsetof_field(EFI_TCG2_BOOT_SERVICE_CAPABILITY, Size));
 
-        if (capability.Size < endoffsetof_field(EFI_TCG2_BOOT_SERVICE_CAPABILITY, TPMPresentFlag))
+        /* This is a paranoia check, given these fields existed from day one of the spec. But the spec also
+         * suggests checking the structure size before accessing any fields, hence let's do so, for extra
+         * paranoia. */
+        if (capability.Size < CONST_MAX(endoffsetof_field(EFI_TCG2_BOOT_SERVICE_CAPABILITY, TPMPresentFlag),
+                                        endoffsetof_field(EFI_TCG2_BOOT_SERVICE_CAPABILITY, ProtocolVersion)))
                 return NULL;
 
         if (!capability.TPMPresentFlag)
                 return NULL;
 
+        if (ret_version)
+                *ret_version = capability.ProtocolVersion;
+
         return tcg;
 }
 
 bool tpm_present(void) {
-        return tcg2_interface_check();
+        return tcg2_interface_check(/* ret_version= */ NULL);
 }
 
 uint32_t tpm_get_active_pcr_banks(void) {
-        uint32_t active_pcr_banks = 0;
-        EFI_TCG2_PROTOCOL *tpm2;
         EFI_STATUS err;
 
-        tpm2 = tcg2_interface_check();
+        EFI_TCG2_PROTOCOL *tpm2;
+        EFI_TCG2_VERSION version;
+        tpm2 = tcg2_interface_check(&version);
         if (!tpm2)
                 return 0;
 
+        /* 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;
+        }
+
+        uint32_t active_pcr_banks = 0;
         err = tpm2->GetActivePcrBanks(tpm2, &active_pcr_banks);
         if (err != EFI_SUCCESS) {
                 log_warning_status(err, "Failed to get TPM2 active PCR banks, assuming none: %m");
@@ -204,7 +218,7 @@ static EFI_STATUS tcg2_log_ipl_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buf
 
         assert(ret_measured);
 
-        tpm2 = tcg2_interface_check();
+        tpm2 = tcg2_interface_check(/* ret_version= */ NULL);
         if (!tpm2) {
                 *ret_measured = false;
                 return EFI_SUCCESS;
@@ -286,7 +300,7 @@ EFI_STATUS tpm_log_tagged_event(
         /* If EFI_SUCCESS is returned, will initialize ret_measured to true if we actually measured
          * something, or false if measurement was turned off. */
 
-        tpm2 = tcg2_interface_check();
+        tpm2 = tcg2_interface_check(/* ret_version= */ NULL);
         if (!tpm2 || pcrindex == UINT32_MAX) { /* PCR disabled? */
                 if (ret_measured)
                         *ret_measured = false;