dc0bc06
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
dc0bc06
From: Michael Chang <mchang@suse.com>
dc0bc06
Date: Wed, 22 Mar 2023 12:25:43 +0800
dc0bc06
Subject: [PATCH] tpm: Disable the tpm verifier if the TPM device is not
dc0bc06
 present
dc0bc06
dc0bc06
When the tpm module is loaded, the verifier reads entire file into
dc0bc06
memory, measures it and uses verified content as a backing buffer for
dc0bc06
file accesses. However, this process may result in high memory
dc0bc06
utilization for file operations, sometimes causing a system to run out
dc0bc06
of memory which may finally lead to boot failure. To address this issue,
dc0bc06
among others, the commit 887f98f0d (mm: Allow dynamically requesting
dc0bc06
additional memory regions) have optimized memory management by
dc0bc06
dynamically allocating heap space to maximize memory usage and reduce
dc0bc06
threat of memory exhaustion. But in some cases problems may still arise,
dc0bc06
e.g., when large ISO images are mounted using loopback or when dealing
dc0bc06
with embedded systems with limited memory resources.
dc0bc06
dc0bc06
Unfortunately current implementation of the tpm module doesn't allow
dc0bc06
elimination of the back buffer once it is loaded. Even if the TPM device
dc0bc06
is not present or it has been explicitly disabled. This may unnecessary
dc0bc06
allocate a lot memory. To solve this issue, a patch has been developed
dc0bc06
to detect the TPM status at module load and skip verifier registration
dc0bc06
if the device is missing or deactivated. This prevents allocation of
dc0bc06
memory for the back buffer, avoiding wasting memory when no real measure
dc0bc06
boot functionality is performed. Disabling the TPM device in the system
dc0bc06
can reduce memory usage in the GRUB. It is useful in scenarios where
dc0bc06
high memory utilization is a concern and measurements of loaded
dc0bc06
artifacts are not necessary.
dc0bc06
dc0bc06
Signed-off-by: Michael Chang <mchang@suse.com>
dc0bc06
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
dc0bc06
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
dc0bc06
(cherry picked from commit 30708dfe3bebd62a5487437554da8a24253f519f)
dc0bc06
---
dc0bc06
 grub-core/commands/efi/tpm.c          | 37 +++++++++++++++++++++++++++++++++++
dc0bc06
 grub-core/commands/ieee1275/ibmvtpm.c | 20 +++++++++----------
dc0bc06
 grub-core/commands/tpm.c              | 10 ++++++++++
dc0bc06
 include/grub/tpm.h                    |  1 +
dc0bc06
 4 files changed, 58 insertions(+), 10 deletions(-)
dc0bc06
dc0bc06
diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c
dc0bc06
index ae09c1bf8b..e1f343fea3 100644
dc0bc06
--- a/grub-core/commands/efi/tpm.c
dc0bc06
+++ b/grub-core/commands/efi/tpm.c
dc0bc06
@@ -287,3 +287,40 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
dc0bc06
   else
dc0bc06
     return grub_tpm2_log_event (tpm_handle, buf, size, pcr, description);
dc0bc06
 }
dc0bc06
+
dc0bc06
+int
dc0bc06
+grub_tpm_present (void)
dc0bc06
+{
dc0bc06
+  grub_efi_handle_t tpm_handle;
dc0bc06
+  grub_efi_uint8_t protocol_version;
dc0bc06
+
dc0bc06
+  if (!grub_tpm_handle_find (&tpm_handle, &protocol_version))
dc0bc06
+    return 0;
dc0bc06
+
dc0bc06
+  if (protocol_version == 1)
dc0bc06
+    {
dc0bc06
+      grub_efi_tpm_protocol_t *tpm;
dc0bc06
+
dc0bc06
+      tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid,
dc0bc06
+				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
dc0bc06
+      if (!tpm)
dc0bc06
+	{
dc0bc06
+	  grub_dprintf ("tpm", "Cannot open TPM protocol\n");
dc0bc06
+	  return 0;
dc0bc06
+	}
dc0bc06
+      return grub_tpm1_present (tpm);
dc0bc06
+    }
dc0bc06
+  else
dc0bc06
+    {
dc0bc06
+      grub_efi_tpm2_protocol_t *tpm;
dc0bc06
+
dc0bc06
+      tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid,
dc0bc06
+				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
dc0bc06
+      if (!tpm)
dc0bc06
+	{
dc0bc06
+	  grub_dprintf ("tpm", "Cannot open TPM protocol\n");
dc0bc06
+	  return 0;
dc0bc06
+	}
dc0bc06
+      return grub_tpm2_present (tpm);
dc0bc06
+    }
dc0bc06
+}
dc0bc06
diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c
dc0bc06
index 239942d27e..a6fee5c516 100644
dc0bc06
--- a/grub-core/commands/ieee1275/ibmvtpm.c
dc0bc06
+++ b/grub-core/commands/ieee1275/ibmvtpm.c
dc0bc06
@@ -135,16 +135,6 @@ grub_err_t
dc0bc06
 grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
dc0bc06
 		  const char *description)
dc0bc06
 {
dc0bc06
-  /*
dc0bc06
-   * Call tpm_init() 'late' rather than from GRUB_MOD_INIT() so that device nodes
dc0bc06
-   * can be found.
dc0bc06
-   */
dc0bc06
-  grub_err_t err = tpm_init ();
dc0bc06
-
dc0bc06
-  /* Absence of a TPM isn't a failure. */
dc0bc06
-  if (err != GRUB_ERR_NONE)
dc0bc06
-    return GRUB_ERR_NONE;
dc0bc06
-
dc0bc06
   grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n",
dc0bc06
 		pcr, size, description);
dc0bc06
 
dc0bc06
@@ -153,3 +143,13 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
dc0bc06
 
dc0bc06
   return GRUB_ERR_NONE;
dc0bc06
 }
dc0bc06
+
dc0bc06
+int
dc0bc06
+grub_tpm_present (void)
dc0bc06
+{
dc0bc06
+  /*
dc0bc06
+   * Call tpm_init() "late" rather than from GRUB_MOD_INIT() so that device nodes
dc0bc06
+   * can be found.
dc0bc06
+   */
dc0bc06
+  return tpm_init() == GRUB_ERR_NONE;
dc0bc06
+}
dc0bc06
diff --git a/grub-core/commands/tpm.c b/grub-core/commands/tpm.c
dc0bc06
index e287d042e6..5839053d3d 100644
dc0bc06
--- a/grub-core/commands/tpm.c
dc0bc06
+++ b/grub-core/commands/tpm.c
dc0bc06
@@ -86,10 +86,20 @@ struct grub_file_verifier grub_tpm_verifier = {
dc0bc06
 
dc0bc06
 GRUB_MOD_INIT (tpm)
dc0bc06
 {
dc0bc06
+  /*
dc0bc06
+   * Even though this now calls ibmvtpm's grub_tpm_present() from GRUB_MOD_INIT(),
dc0bc06
+   * it does seem to call it late enough in the initialization sequence so
dc0bc06
+   * that whatever discovered "device nodes" before this GRUB_MOD_INIT() is
dc0bc06
+   * called, enables the ibmvtpm driver to see the device nodes.
dc0bc06
+   */
dc0bc06
+  if (!grub_tpm_present())
dc0bc06
+    return;
dc0bc06
   grub_verifier_register (&grub_tpm_verifier);
dc0bc06
 }
dc0bc06
 
dc0bc06
 GRUB_MOD_FINI (tpm)
dc0bc06
 {
dc0bc06
+  if (!grub_tpm_present())
dc0bc06
+    return;
dc0bc06
   grub_verifier_unregister (&grub_tpm_verifier);
dc0bc06
 }
dc0bc06
diff --git a/include/grub/tpm.h b/include/grub/tpm.h
dc0bc06
index 5c285cbc52..c19fcbd0a6 100644
dc0bc06
--- a/include/grub/tpm.h
dc0bc06
+++ b/include/grub/tpm.h
dc0bc06
@@ -36,4 +36,5 @@
dc0bc06
 
dc0bc06
 grub_err_t grub_tpm_measure (unsigned char *buf, grub_size_t size,
dc0bc06
 			     grub_uint8_t pcr, const char *description);
dc0bc06
+int grub_tpm_present (void);
dc0bc06
 #endif