summaryrefslogtreecommitdiff
path: root/lib/tpm_tcg2.c
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2025-01-29 08:12:21 -0600
committerTom Rini <trini@konsulko.com>2025-01-29 08:12:21 -0600
commit021baf7b08cceb58bb850859dba1614424e16a83 (patch)
tree9f53a40366eea064bcafbe5b82a3f1245b2671bc /lib/tpm_tcg2.c
parent75125f392de4e672127fe0b092d481e78ff8bdd0 (diff)
parent8895ff8ae2186b53b4a073966ef16b09c12a69b8 (diff)
Merge tag 'tpm-master-28012025' of https://source.denx.de/u-boot/custodians/u-boot-tpm
CI: https://source.denx.de/u-boot/custodians/u-boot-tpm/-/pipelines/24375 We have use cases where a previous stage boot loader doesn't have any TPM drivers. Instead of extending the hardware PCRs it produces an EventLog that U-Boot later replays on the hardware. The only real example we have is TF-A, which produces the EventLog using hashing algorithms created at compile time. This creates a problem to the TPM since measurements need to extend all active PCR banks. Up to now we were exiting refusing the extend measurements. TPMs can be instructed to change their active PCR banks, as long as the device resets immediately after a reconfiguration. This PR is adding that functionality. U-Boot can now scan the currently active TPM PCR banks, the ones it was compiled to support and the ones present in an EventLog. It the reconfigures the TPM on the fly with the correct algorithms.
Diffstat (limited to 'lib/tpm_tcg2.c')
-rw-r--r--lib/tpm_tcg2.c111
1 files changed, 56 insertions, 55 deletions
diff --git a/lib/tpm_tcg2.c b/lib/tpm_tcg2.c
index 4134d93a358..c314b401d0b 100644
--- a/lib/tpm_tcg2.c
+++ b/lib/tpm_tcg2.c
@@ -19,6 +19,7 @@
#include <linux/unaligned/generic.h>
#include <linux/unaligned/le_byteshift.h>
#include "tpm-utils.h"
+#include <bloblist.h>
int tcg2_get_pcr_info(struct udevice *dev, u32 *supported_bank, u32 *active_bank,
u32 *bank_num)
@@ -358,12 +359,12 @@ static int tcg2_replay_eventlog(struct tcg2_event_log *elog,
return 0;
}
-static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog)
+static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog,
+ u32 *log_active)
{
struct tpml_digest_values digest_list;
struct tcg_efi_spec_id_event *event;
struct tcg_pcr_event *log;
- u32 log_active;
u32 calc_size;
u32 active;
u32 count;
@@ -374,6 +375,8 @@ static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog)
int rc;
u32 i;
+ *log_active = 0;
+
if (elog->log_size <= offsetof(struct tcg_pcr_event, event))
return 0;
@@ -419,7 +422,6 @@ static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog)
* algorithms, so just check the EvenLog against the TPM active ones.
*/
digest_list.count = 0;
- log_active = 0;
for (i = 0; i < count; ++i) {
algo = get_unaligned_le16(&event->digest_sizes[i].algorithm_id);
mask = tcg2_algorithm_to_mask(algo);
@@ -445,17 +447,15 @@ static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog)
algo);
return -1;
}
- log_active |= mask;
+ *log_active |= mask;
}
rc = tcg2_get_active_pcr_banks(dev, &active);
if (rc)
return rc;
/* If the EventLog and active algorithms don't match exit */
- if (log_active != active) {
- log_err("EventLog doesn't contain all active PCR banks\n");
- return -1;
- }
+ if (*log_active != active)
+ return -ERESTARTSYS;
/* Read PCR0 to check if previous firmware extended the PCRs or not. */
rc = tcg2_pcr_read(dev, 0, &digest_list);
@@ -552,43 +552,21 @@ int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog,
bool ignore_existing_log)
{
struct tcg2_event_log log;
- int rc, i;
+ int rc;
+ u32 log_active = 0;
elog->log_position = 0;
elog->found = false;
- /*
- * Make sure U-Boot is compiled with all the active PCRs
- * since we are about to create an EventLog and we won't
- * measure anything if the PCR banks don't match
- */
- if (!tpm2_check_active_banks(dev)) {
- log_err("Cannot create EventLog\n");
- log_err("Mismatch between U-Boot and TPM hash algos\n");
- log_info("TPM:\n");
- tpm2_print_active_banks(dev);
- log_info("U-Boot:\n");
- for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) {
- const struct digest_info *algo = &hash_algo_list[i];
- const char *str;
-
- if (!algo->supported)
- continue;
-
- str = tpm2_algorithm_name(algo->hash_alg);
- if (str)
- log_info("%s\n", str);
- }
- return -EINVAL;
- }
-
rc = tcg2_platform_get_log(dev, (void **)&log.log, &log.log_size);
if (!rc) {
log.log_position = 0;
log.found = false;
if (!ignore_existing_log) {
- rc = tcg2_log_parse(dev, &log);
+ rc = tcg2_log_parse(dev, &log, &log_active);
+ if (rc == -ERESTARTSYS && log_active)
+ goto pcr_allocate;
if (rc)
return rc;
}
@@ -615,6 +593,11 @@ int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog,
elog->found = log.found;
}
+pcr_allocate:
+ rc = tpm2_activate_banks(dev, log_active);
+ if (rc)
+ return rc;
+
/*
* Initialize the log buffer if no log was discovered and the buffer is
* valid. User's can pass in their own buffer as a fallback if no
@@ -672,21 +655,42 @@ void tcg2_measurement_term(struct udevice *dev, struct tcg2_event_log *elog,
__weak int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size)
{
- const __be32 *addr_prop;
- const __be32 *size_prop;
+ const __be32 *addr_prop = NULL;
+ const __be32 *size_prop = NULL;
int asize;
int ssize;
+ struct ofnode_phandle_args args;
+ phys_addr_t a;
+ fdt_size_t s;
*addr = NULL;
*size = 0;
- addr_prop = dev_read_prop(dev, "tpm_event_log_addr", &asize);
- if (!addr_prop)
- addr_prop = dev_read_prop(dev, "linux,sml-base", &asize);
+ *addr = bloblist_get_blob(BLOBLISTT_TPM_EVLOG, size);
+ if (*addr && *size) {
+ *addr = map_physmem((uintptr_t)(*addr), *size, MAP_NOCACHE);
+ return 0;
+ }
- size_prop = dev_read_prop(dev, "tpm_event_log_size", &ssize);
- if (!size_prop)
+ /*
+ * TODO:
+ * Replace BLOBLIST with a new kconfig for handoff all components
+ * (fdt, tpm event log, etc...) from previous boot stage via bloblist
+ * mandatorily following Firmware Handoff spec.
+ */
+ if (!CONFIG_IS_ENABLED(BLOBLIST)) {
+ addr_prop = dev_read_prop(dev, "tpm_event_log_addr", &asize);
+ size_prop = dev_read_prop(dev, "tpm_event_log_size", &ssize);
+ }
+
+ /*
+ * If no eventlog was observed, a sml buffer is required for the kernel
+ * to discover the eventlog.
+ */
+ if (!addr_prop || !size_prop) {
+ addr_prop = dev_read_prop(dev, "linux,sml-base", &asize);
size_prop = dev_read_prop(dev, "linux,sml-size", &ssize);
+ }
if (addr_prop && size_prop) {
u64 a = of_read_number(addr_prop, asize / sizeof(__be32));
@@ -694,22 +698,19 @@ __weak int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size)
*addr = map_physmem(a, s, MAP_NOCACHE);
*size = (u32)s;
- } else {
- struct ofnode_phandle_args args;
- phys_addr_t a;
- fdt_size_t s;
- if (dev_read_phandle_with_args(dev, "memory-region", NULL, 0,
- 0, &args))
- return -ENODEV;
+ return 0;
+ }
- a = ofnode_get_addr_size(args.node, "reg", &s);
- if (a == FDT_ADDR_T_NONE)
- return -ENOMEM;
+ if (dev_read_phandle_with_args(dev, "memory-region", NULL, 0, 0, &args))
+ return -ENODEV;
- *addr = map_physmem(a, s, MAP_NOCACHE);
- *size = (u32)s;
- }
+ a = ofnode_get_addr_size(args.node, "reg", &s);
+ if (a == FDT_ADDR_T_NONE)
+ return -ENOMEM;
+
+ *addr = map_physmem(a, s, MAP_NOCACHE);
+ *size = (u32)s;
return 0;
}