Skip to content

Commit

Permalink
x86/tpm.c: implement event log for TPM2.0
Browse files Browse the repository at this point in the history
Signed-off-by: Sergii Dmytruk <[email protected]>
  • Loading branch information
SergiiDmytruk committed Jan 7, 2024
1 parent 51833de commit 62863e0
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 24 deletions.
33 changes: 33 additions & 0 deletions xen/arch/x86/include/asm/intel_txt.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,39 @@ struct txt_sinit_mle_data {
/* Ext Data Elements */
} __packed;

/* 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;
uint8_t data[0]; /* size bytes. */
} __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. The layout
* of the heap is as follows:
Expand Down
163 changes: 139 additions & 24 deletions xen/arch/x86/tpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,44 @@ struct tpm2_log_hashes {
struct tpm2_log_hash hashes[MAX_HASH_COUNT];
};

struct tpm2_pcr_event_header {
uint32_t pcrIndex;
uint32_t eventType;
uint32_t digestCount;
uint8_t digests[0];
/*
* Each hash is represented as:
* struct {
* uint16_t hashAlg;
* uint8_t hash[size of hashAlg];
* };
*/
/* uint32_t eventSize; */
/* uint8_t event[0]; */
} __packed;

struct tpm2_digest_sizes {
uint16_t algId;
uint16_t digestSize;
} __packed;

struct tpm2_spec_id_event {
uint32_t pcrIndex;
uint32_t eventType;
uint8_t digest[20];
uint32_t eventSize;
uint8_t signature[16];
uint32_t platformClass;
uint8_t specVersionMinor;
uint8_t specVersionMajor;
uint8_t specErrata;
uint8_t uintnSize;
uint32_t digestCount;
struct tpm2_digest_sizes digestSizes[0]; /* variable number of members */
/* uint8_t vendorInfoSize; */
/* uint8_t vendorInfo[vendorInfoSize]; */
} __packed;

#ifdef __EARLY_TPM__

union tpm2_cmd_rsp {
Expand Down Expand Up @@ -759,15 +797,12 @@ static uint32_t tpm2_hash_extend(unsigned loc, uint8_t *buf, unsigned size,
continue;
}

if ( hash->alg == TPM_ALG_SHA1 ) {
if ( hash->alg == TPM_ALG_SHA1 )
sha1_hash(buf, size, hash->data);
} else if ( hash->alg == TPM_ALG_SHA256 ) {
else if ( hash->alg == TPM_ALG_SHA256 )
sha256_hash(buf, size, hash->data);
} else {
/* This is called "OneDigest" in TXT Software Development Guide. */
memset(hash->data, 0, size);
hash->data[0] = 1;
}
else
/* create_log_event20() took care of initializing the digest. */;

if ( supported_hashes.count == MAX_HASH_COUNT ) {
printk(XENLOG_ERR "Hit hash count implementation limit: %d\n",
Expand All @@ -787,6 +822,99 @@ static uint32_t tpm2_hash_extend(unsigned loc, uint8_t *buf, unsigned size,

#endif /* __EARLY_TPM__ */

static struct heap_event_log_pointer_element2_1 *find_evt_log_ext_data(void)
{
struct txt_os_sinit_data *os_sinit;
struct txt_ext_data_element *ext_data;

os_sinit = txt_os_sinit_data_start(__va(read_txt_reg(TXTCR_HEAP_BASE)));
ext_data = (void *)((uint8_t *)os_sinit + sizeof(*os_sinit));

/*
* Find TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1 which is necessary to
* know where to put the next entry.
*/
while ( ext_data->type != TXT_HEAP_EXTDATA_TYPE_END ) {
if ( ext_data->type == TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1 )
break;
ext_data = (void *)&ext_data->data[ext_data->size];
}

if ( ext_data->type == TXT_HEAP_EXTDATA_TYPE_END )
return NULL;

return (void *)&ext_data->data[0];
}

static struct tpm2_log_hashes
create_log_event20(struct tpm2_spec_id_event *evt_log, uint32_t evt_log_size,
uint32_t pcr, uint32_t type, uint8_t *data,
unsigned data_size)
{
struct tpm2_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;

log_ext_data = find_evt_log_ext_data();
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 *)((uint8_t *)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 && data_size > 0 )
memcpy(p, data, data_size);

return log_hashes;
}

/************************** end of TPM2.0 specific ****************************/

void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size,
Expand All @@ -811,25 +939,12 @@ void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size,

tpm12_hash_extend(loc, buf, size, pcr, entry_digest);
} else {
uint8_t sha1_digest[SHA1_DIGEST_SIZE];
uint8_t sha256_digest[SHA256_DIGEST_SIZE];
uint32_t rc;

struct tpm2_log_hashes log_hashes = {
.count = 2,
.hashes = {
{
.alg = TPM_ALG_SHA1,
.size = SHA1_DIGEST_SIZE,
.data = sha1_digest,
},
{
.alg = TPM_ALG_SHA256,
.size = SHA256_DIGEST_SIZE,
.data = sha256_digest,
},
},
};
struct tpm2_spec_id_event *evt_log = evt_log_addr;
struct tpm2_log_hashes log_hashes =
create_log_event20(evt_log, evt_log_size, pcr, type, log_data,
log_data_size);

rc = tpm2_hash_extend(loc, buf, size, pcr, &log_hashes);
if ( rc != 0 ) {
Expand Down

0 comments on commit 62863e0

Please sign in to comment.