Blob Blame History Raw
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Wed, 22 Mar 2023 12:25:43 +0800
Subject: [PATCH] tpm: Disable the tpm verifier if the TPM device is not
 present

When the tpm module is loaded, the verifier reads entire file into
memory, measures it and uses verified content as a backing buffer for
file accesses. However, this process may result in high memory
utilization for file operations, sometimes causing a system to run out
of memory which may finally lead to boot failure. To address this issue,
among others, the commit 887f98f0d (mm: Allow dynamically requesting
additional memory regions) have optimized memory management by
dynamically allocating heap space to maximize memory usage and reduce
threat of memory exhaustion. But in some cases problems may still arise,
e.g., when large ISO images are mounted using loopback or when dealing
with embedded systems with limited memory resources.

Unfortunately current implementation of the tpm module doesn't allow
elimination of the back buffer once it is loaded. Even if the TPM device
is not present or it has been explicitly disabled. This may unnecessary
allocate a lot memory. To solve this issue, a patch has been developed
to detect the TPM status at module load and skip verifier registration
if the device is missing or deactivated. This prevents allocation of
memory for the back buffer, avoiding wasting memory when no real measure
boot functionality is performed. Disabling the TPM device in the system
can reduce memory usage in the GRUB. It is useful in scenarios where
high memory utilization is a concern and measurements of loaded
artifacts are not necessary.

Signed-off-by: Michael Chang <mchang@suse.com>
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 30708dfe3bebd62a5487437554da8a24253f519f)
---
 grub-core/commands/efi/tpm.c          | 37 +++++++++++++++++++++++++++++++++++
 grub-core/commands/ieee1275/ibmvtpm.c | 20 +++++++++----------
 grub-core/commands/tpm.c              | 10 ++++++++++
 include/grub/tpm.h                    |  1 +
 4 files changed, 58 insertions(+), 10 deletions(-)

diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c
index ae09c1bf8b..e1f343fea3 100644
--- a/grub-core/commands/efi/tpm.c
+++ b/grub-core/commands/efi/tpm.c
@@ -287,3 +287,40 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
   else
     return grub_tpm2_log_event (tpm_handle, buf, size, pcr, description);
 }
+
+int
+grub_tpm_present (void)
+{
+  grub_efi_handle_t tpm_handle;
+  grub_efi_uint8_t protocol_version;
+
+  if (!grub_tpm_handle_find (&tpm_handle, &protocol_version))
+    return 0;
+
+  if (protocol_version == 1)
+    {
+      grub_efi_tpm_protocol_t *tpm;
+
+      tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid,
+				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+      if (!tpm)
+	{
+	  grub_dprintf ("tpm", "Cannot open TPM protocol\n");
+	  return 0;
+	}
+      return grub_tpm1_present (tpm);
+    }
+  else
+    {
+      grub_efi_tpm2_protocol_t *tpm;
+
+      tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid,
+				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+      if (!tpm)
+	{
+	  grub_dprintf ("tpm", "Cannot open TPM protocol\n");
+	  return 0;
+	}
+      return grub_tpm2_present (tpm);
+    }
+}
diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c
index 239942d27e..a6fee5c516 100644
--- a/grub-core/commands/ieee1275/ibmvtpm.c
+++ b/grub-core/commands/ieee1275/ibmvtpm.c
@@ -135,16 +135,6 @@ grub_err_t
 grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
 		  const char *description)
 {
-  /*
-   * Call tpm_init() 'late' rather than from GRUB_MOD_INIT() so that device nodes
-   * can be found.
-   */
-  grub_err_t err = tpm_init ();
-
-  /* Absence of a TPM isn't a failure. */
-  if (err != GRUB_ERR_NONE)
-    return GRUB_ERR_NONE;
-
   grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n",
 		pcr, size, description);
 
@@ -153,3 +143,13 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
 
   return GRUB_ERR_NONE;
 }
+
+int
+grub_tpm_present (void)
+{
+  /*
+   * Call tpm_init() "late" rather than from GRUB_MOD_INIT() so that device nodes
+   * can be found.
+   */
+  return tpm_init() == GRUB_ERR_NONE;
+}
diff --git a/grub-core/commands/tpm.c b/grub-core/commands/tpm.c
index e287d042e6..5839053d3d 100644
--- a/grub-core/commands/tpm.c
+++ b/grub-core/commands/tpm.c
@@ -86,10 +86,20 @@ struct grub_file_verifier grub_tpm_verifier = {
 
 GRUB_MOD_INIT (tpm)
 {
+  /*
+   * Even though this now calls ibmvtpm's grub_tpm_present() from GRUB_MOD_INIT(),
+   * it does seem to call it late enough in the initialization sequence so
+   * that whatever discovered "device nodes" before this GRUB_MOD_INIT() is
+   * called, enables the ibmvtpm driver to see the device nodes.
+   */
+  if (!grub_tpm_present())
+    return;
   grub_verifier_register (&grub_tpm_verifier);
 }
 
 GRUB_MOD_FINI (tpm)
 {
+  if (!grub_tpm_present())
+    return;
   grub_verifier_unregister (&grub_tpm_verifier);
 }
diff --git a/include/grub/tpm.h b/include/grub/tpm.h
index 5c285cbc52..c19fcbd0a6 100644
--- a/include/grub/tpm.h
+++ b/include/grub/tpm.h
@@ -36,4 +36,5 @@
 
 grub_err_t grub_tpm_measure (unsigned char *buf, grub_size_t size,
 			     grub_uint8_t pcr, const char *description);
+int grub_tpm_present (void);
 #endif