|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v4 14/23] x86/slaunch: update TPM event log (TPM1.2 or TPM2.0)
Instead of storing hashing result to stack variables, a TPM event log is
discovered in an Slaunch-specific way, extended with an additional entry and
that entry is filled with digests.
Signed-off-by: Krystian Hebel <krystian.hebel@xxxxxxxxx>
Signed-off-by: Szymon Acedański <accek@xxxxxxxxxxxxxxxxxxxxxx>
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Sergii Dmytruk <sergii.dmytruk@xxxxxxxxx>
---
Notes:
v4: was "x86/tpm.c: implement event log for TPM2.0"
v4: part of it as in "x86/tpm.c: code for early hashing and extending PCRs
(for TPM1.2)"
v4: TPM event log code was part of tpm.c changes, now in slaunch-tpm.c
v4: fixed comment on txt_ext_data_element::size and finding log element
(worked because it was first)
v4: provide list of hashes even in the absence of event log to extend PCRs
xen/arch/x86/include/asm/intel-txt.h | 69 ++++++++++
xen/arch/x86/slaunch-tpm.c | 188 +++++++++++++++++++++++----
2 files changed, 232 insertions(+), 25 deletions(-)
diff --git a/xen/arch/x86/include/asm/intel-txt.h
b/xen/arch/x86/include/asm/intel-txt.h
index 406929fac2..8bcca20d6e 100644
--- a/xen/arch/x86/include/asm/intel-txt.h
+++ b/xen/arch/x86/include/asm/intel-txt.h
@@ -71,6 +71,8 @@
#include <xen/multiboot2.h>
#include <xen/slr-table.h>
+#include <asm/tpm1.h>
+
/* Need to differentiate between pre- and post paging enabled. */
#ifdef __EARLY_SLAUNCH__
#include <xen/macros.h>
@@ -200,6 +202,52 @@ struct txt_sinit_mle_data {
/* Ext Data Elements */
} __packed;
+struct txt_ev_log_container_12 {
+ char Signature[20]; /* "TXT Event Container", null-terminated
*/
+ uint8_t Reserved[12];
+ uint8_t ContainerVerMajor;
+ uint8_t ContainerVerMinor;
+ uint8_t PCREventVerMajor;
+ uint8_t PCREventVerMinor;
+ uint32_t ContainerSize; /* Allocated size */
+ uint32_t PCREventsOffset;
+ uint32_t NextEventOffset;
+ struct TPM12_PCREvent PCREvents[];
+};
+
+/* Types of extended data. */
+#define TXT_HEAP_EXTDATA_TYPE_END 0
+#define TXT_HEAP_EXTDATA_TYPE_BIOS_SPEC_VER 1
+#define TXT_HEAP_EXTDATA_TYPE_ACM 2
+#define TXT_HEAP_EXTDATA_TYPE_STM 3
+#define TXT_HEAP_EXTDATA_TYPE_CUSTOM 4
+#define TXT_HEAP_EXTDATA_TYPE_MADT 6
+#define TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1 8
+#define TXT_HEAP_EXTDATA_TYPE_MCFG 9
+#define TXT_HEAP_EXTDATA_TYPE_TPR_REQ 13
+#define TXT_HEAP_EXTDATA_TYPE_DTPR 14
+#define TXT_HEAP_EXTDATA_TYPE_CEDT 15
+
+/*
+ * Self-describing data structure that is used for extensions to TXT heap
+ * tables.
+ */
+struct txt_ext_data_element {
+ uint32_t type; /* One of TXT_HEAP_EXTDATA_TYPE_*. */
+ uint32_t size; /* Size of the whole element (header + data), in bytes. */
+ uint8_t data[0];
+} __packed;
+
+/*
+ * Extended data describing TPM 2.0 log.
+ */
+struct heap_event_log_pointer_element2_1 {
+ uint64_t physical_address;
+ uint32_t allocated_event_container_size;
+ uint32_t first_record_offset;
+ uint32_t next_record_offset;
+} __packed;
+
/*
* Functions to extract data from the Intel TXT Heap Memory.
*
@@ -268,6 +316,27 @@ static inline void *txt_init(void)
return txt_heap;
}
+/*
+ * Find the given element in the TXT heap extended data.
+ */
+static inline struct txt_ext_data_element *
+txt_find_ext_data_element(struct txt_os_sinit_data *os_sinit, uint32_t type)
+{
+ struct txt_ext_data_element *ext_elem;
+
+ ext_elem = (void *)os_sinit + sizeof(struct txt_os_sinit_data);
+
+ while ( ext_elem->type != TXT_HEAP_EXTDATA_TYPE_END )
+ {
+ if ( ext_elem->type == type )
+ return ext_elem;
+
+ ext_elem = (void *)ext_elem + ext_elem->size;
+ }
+
+ return NULL;
+}
+
static inline bool is_in_pmr(const struct txt_os_sinit_data *os_sinit,
uint64_t base, uint32_t size, bool check_high)
{
diff --git a/xen/arch/x86/slaunch-tpm.c b/xen/arch/x86/slaunch-tpm.c
index 21dec67dca..e3b7341cc5 100644
--- a/xen/arch/x86/slaunch-tpm.c
+++ b/xen/arch/x86/slaunch-tpm.c
@@ -67,6 +67,136 @@ void asmlinkage slaunch_measure_mbi(const
multiboot2_fixed_t *mbi,
#endif /* __EARLY_SLAUNCH__ */
+static struct tpm_log_hashes
+create_log_event12(struct txt_ev_log_container_12 *evt_log,
+ uint32_t evt_log_size, uint32_t pcr, uint32_t type,
+ const uint8_t *data, unsigned data_size)
+{
+ struct tpm_log_hashes log_hashes = {0};
+
+ struct TPM12_PCREvent *new_entry;
+
+ if (evt_log == NULL)
+ return log_hashes;
+
+ new_entry = (void *)evt_log + evt_log->NextEventOffset;
+
+ /*
+ * Check if there is enough space left for new entry.
+ * Note: it is possible to introduce a gap in event log if entry with big
+ * data_size is followed by another entry with smaller data. Maybe we
should
+ * cap the event log size in such case?
+ */
+ if ( evt_log->NextEventOffset + sizeof(struct TPM12_PCREvent) + data_size >
+ evt_log_size )
+ return log_hashes;
+
+ evt_log->NextEventOffset += sizeof(struct TPM12_PCREvent) + data_size;
+
+ new_entry->PCRIndex = pcr;
+ new_entry->Type = type;
+ new_entry->Size = data_size;
+
+ if ( data != NULL && data_size > 0 )
+ memcpy(new_entry->Data, data, data_size);
+
+ log_hashes.count = 1;
+ log_hashes.hashes[0].alg = TPM_ALG_SHA1;
+ log_hashes.hashes[0].size = SHA1_DIGEST_SIZE;
+ log_hashes.hashes[0].data = new_entry->Digest;
+
+ return log_hashes;
+}
+
+static struct heap_event_log_pointer_element2_1 *
+find_evt_log_ext_data(struct tpm2_spec_id_event *evt_log)
+{
+ struct txt_os_sinit_data *os_sinit;
+ struct txt_ext_data_element *ext_data;
+
+ os_sinit = txt_start(__va(txt_read(TXTCR_HEAP_BASE)), TXT_OS2SINIT);
+ ext_data = txt_find_ext_data_element(os_sinit,
+
TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1);
+ if ( ext_data == NULL )
+ return NULL;
+
+ return (struct heap_event_log_pointer_element2_1 *)ext_data->data;
+}
+
+static struct tpm_log_hashes
+create_log_event20(struct tpm2_spec_id_event *evt_log, uint32_t evt_log_size,
+ uint32_t pcr, uint32_t type, const uint8_t *data,
+ unsigned data_size)
+{
+ struct tpm_log_hashes log_hashes = {0};
+
+ struct heap_event_log_pointer_element2_1 *log_ext_data;
+ struct tpm2_pcr_event_header *new_entry;
+ uint32_t entry_size;
+ unsigned i;
+ uint8_t *p;
+
+ if (evt_log == NULL)
+ return log_hashes;
+
+ log_ext_data = find_evt_log_ext_data(evt_log);
+ if ( log_ext_data == NULL )
+ return log_hashes;
+
+ entry_size = sizeof(*new_entry);
+ for ( i = 0; i < evt_log->digestCount; ++i )
+ {
+ entry_size += sizeof(uint16_t); /* hash type */
+ entry_size += evt_log->digestSizes[i].digestSize;
+ }
+ entry_size += sizeof(uint32_t); /* data size field */
+ entry_size += data_size;
+
+ /*
+ * Check if there is enough space left for new entry.
+ * Note: it is possible to introduce a gap in event log if entry with big
+ * data_size is followed by another entry with smaller data. Maybe we
should
+ * cap the event log size in such case?
+ */
+ if ( log_ext_data->next_record_offset + entry_size > evt_log_size )
+ return log_hashes;
+
+ new_entry = (void *)evt_log + log_ext_data->next_record_offset;
+ log_ext_data->next_record_offset += entry_size;
+
+ new_entry->pcrIndex = pcr;
+ new_entry->eventType = type;
+ new_entry->digestCount = evt_log->digestCount;
+
+ p = &new_entry->digests[0];
+ for ( i = 0; i < evt_log->digestCount; ++i )
+ {
+ uint16_t alg = evt_log->digestSizes[i].algId;
+ uint16_t size = evt_log->digestSizes[i].digestSize;
+
+ *(uint16_t *)p = alg;
+ p += sizeof(uint16_t);
+
+ log_hashes.hashes[i].alg = alg;
+ log_hashes.hashes[i].size = size;
+ log_hashes.hashes[i].data = p;
+ p += size;
+
+ /* This is called "OneDigest" in TXT Software Development Guide. */
+ memset(log_hashes.hashes[i].data, 0, size);
+ log_hashes.hashes[i].data[0] = 1;
+ }
+ log_hashes.count = evt_log->digestCount;
+
+ *(uint32_t *)p = data_size;
+ p += sizeof(uint32_t);
+
+ if ( data != NULL && data_size > 0 )
+ memcpy(p, data, data_size);
+
+ return log_hashes;
+}
+
void slaunch_find_log(const struct slr_table *slrt, paddr_t *evt_log,
uint32_t *evt_log_size)
{
@@ -99,42 +229,50 @@ void slaunch_hash_extend(unsigned int loc, unsigned int
pcr, const uint8_t *buf,
{
paddr_t evt_log_paddr;
uint32_t evt_log_size;
- struct tpm_log_hashes log_hashes;
uint8_t discarded_digests[SHA2_256_DIGEST_SIZE];
+ struct tpm_log_hashes log_hashes;
uint32_t rc;
slaunch_find_log(slaunch_get_slrt(), &evt_log_paddr, &evt_log_size);
if ( tpm_is_tpm1() )
{
- log_hashes = (struct tpm_log_hashes) {
- .count = 1,
- .hashes = {
- {
- .alg = TPM_ALG_SHA1,
- .size = SHA1_DIGEST_SIZE,
- .data = discarded_digests,
- },
- },
- };
+ struct txt_ev_log_container_12 *evt_log = __va(evt_log_paddr);
+
+ log_hashes = create_log_event12(evt_log, evt_log_size, pcr, type,
+ log_data, log_data_size);
}
else
{
- log_hashes = (struct tpm_log_hashes) {
- .count = 2,
- .hashes = {
- {
- .alg = TPM_ALG_SHA1,
- .size = SHA1_DIGEST_SIZE,
- .data = discarded_digests,
- },
- {
- .alg = TPM_ALG_SHA256,
- .size = SHA2_256_DIGEST_SIZE,
- .data = discarded_digests,
+ struct tpm2_spec_id_event *evt_log = __va(evt_log_paddr);
+
+ log_hashes = create_log_event20(evt_log, evt_log_size, pcr, type,
+ log_data, log_data_size);
+
+ if ( log_hashes.count == 0 )
+ {
+ /*
+ * Because TPM2 supports multiple PCR banks, the list of digests is
+ * also used to indicate which banks to extend. Thus avoid passing
+ * an empty list of digests to have a chance of something being
+ * extended even without event log.
+ */
+ log_hashes = (struct tpm_log_hashes) {
+ .count = 2,
+ .hashes = {
+ {
+ .alg = TPM_ALG_SHA1,
+ .size = SHA1_DIGEST_SIZE,
+ .data = discarded_digests,
+ },
+ {
+ .alg = TPM_ALG_SHA256,
+ .size = SHA2_256_DIGEST_SIZE,
+ .data = discarded_digests,
+ },
},
- },
- };
+ };
+ }
}
rc = tpm_hash_extend(loc, pcr, buf, size, &log_hashes);
--
2.55.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |