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>
This commit is contained in:
Michael Chang 2023-03-22 12:25:43 +08:00 committed by Daniel Kiper
parent 0f5d860637
commit 30708dfe3b
4 changed files with 58 additions and 10 deletions

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -103,10 +103,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);
}

View File

@ -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