diff options
author | Tom Rini <trini@konsulko.com> | 2025-01-29 08:12:21 -0600 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2025-01-29 08:12:21 -0600 |
commit | 021baf7b08cceb58bb850859dba1614424e16a83 (patch) | |
tree | 9f53a40366eea064bcafbe5b82a3f1245b2671bc /lib/tpm_tcg2.c | |
parent | 75125f392de4e672127fe0b092d481e78ff8bdd0 (diff) | |
parent | 8895ff8ae2186b53b4a073966ef16b09c12a69b8 (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.c | 111 |
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; } |