Skip to content

Commit 62863e0

Browse files
committed
x86/tpm.c: implement event log for TPM2.0
Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
1 parent 51833de commit 62863e0

File tree

2 files changed

+172
-24
lines changed

2 files changed

+172
-24
lines changed

xen/arch/x86/include/asm/intel_txt.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,39 @@ struct txt_sinit_mle_data {
200200
/* Ext Data Elements */
201201
} __packed;
202202

203+
/* Types of extended data. */
204+
#define TXT_HEAP_EXTDATA_TYPE_END 0
205+
#define TXT_HEAP_EXTDATA_TYPE_BIOS_SPEC_VER 1
206+
#define TXT_HEAP_EXTDATA_TYPE_ACM 2
207+
#define TXT_HEAP_EXTDATA_TYPE_STM 3
208+
#define TXT_HEAP_EXTDATA_TYPE_CUSTOM 4
209+
#define TXT_HEAP_EXTDATA_TYPE_MADT 6
210+
#define TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1 8
211+
#define TXT_HEAP_EXTDATA_TYPE_MCFG 9
212+
#define TXT_HEAP_EXTDATA_TYPE_TPR_REQ 13
213+
#define TXT_HEAP_EXTDATA_TYPE_DTPR 14
214+
#define TXT_HEAP_EXTDATA_TYPE_CEDT 15
215+
216+
/*
217+
* Self-describing data structure that is used for extensions to TXT heap
218+
* tables.
219+
*/
220+
struct txt_ext_data_element {
221+
uint32_t type; /* One of TXT_HEAP_EXTDATA_TYPE_*. */
222+
uint32_t size;
223+
uint8_t data[0]; /* size bytes. */
224+
} __packed;
225+
226+
/*
227+
* Extended data describing TPM 2.0 log.
228+
*/
229+
struct heap_event_log_pointer_element2_1 {
230+
uint64_t physical_address;
231+
uint32_t allocated_event_container_size;
232+
uint32_t first_record_offset;
233+
uint32_t next_record_offset;
234+
} __packed;
235+
203236
/*
204237
* Functions to extract data from the Intel TXT Heap Memory. The layout
205238
* of the heap is as follows:

xen/arch/x86/tpm.c

Lines changed: 139 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,44 @@ struct tpm2_log_hashes {
539539
struct tpm2_log_hash hashes[MAX_HASH_COUNT];
540540
};
541541

542+
struct tpm2_pcr_event_header {
543+
uint32_t pcrIndex;
544+
uint32_t eventType;
545+
uint32_t digestCount;
546+
uint8_t digests[0];
547+
/*
548+
* Each hash is represented as:
549+
* struct {
550+
* uint16_t hashAlg;
551+
* uint8_t hash[size of hashAlg];
552+
* };
553+
*/
554+
/* uint32_t eventSize; */
555+
/* uint8_t event[0]; */
556+
} __packed;
557+
558+
struct tpm2_digest_sizes {
559+
uint16_t algId;
560+
uint16_t digestSize;
561+
} __packed;
562+
563+
struct tpm2_spec_id_event {
564+
uint32_t pcrIndex;
565+
uint32_t eventType;
566+
uint8_t digest[20];
567+
uint32_t eventSize;
568+
uint8_t signature[16];
569+
uint32_t platformClass;
570+
uint8_t specVersionMinor;
571+
uint8_t specVersionMajor;
572+
uint8_t specErrata;
573+
uint8_t uintnSize;
574+
uint32_t digestCount;
575+
struct tpm2_digest_sizes digestSizes[0]; /* variable number of members */
576+
/* uint8_t vendorInfoSize; */
577+
/* uint8_t vendorInfo[vendorInfoSize]; */
578+
} __packed;
579+
542580
#ifdef __EARLY_TPM__
543581

544582
union tpm2_cmd_rsp {
@@ -759,15 +797,12 @@ static uint32_t tpm2_hash_extend(unsigned loc, uint8_t *buf, unsigned size,
759797
continue;
760798
}
761799

762-
if ( hash->alg == TPM_ALG_SHA1 ) {
800+
if ( hash->alg == TPM_ALG_SHA1 )
763801
sha1_hash(buf, size, hash->data);
764-
} else if ( hash->alg == TPM_ALG_SHA256 ) {
802+
else if ( hash->alg == TPM_ALG_SHA256 )
765803
sha256_hash(buf, size, hash->data);
766-
} else {
767-
/* This is called "OneDigest" in TXT Software Development Guide. */
768-
memset(hash->data, 0, size);
769-
hash->data[0] = 1;
770-
}
804+
else
805+
/* create_log_event20() took care of initializing the digest. */;
771806

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

788823
#endif /* __EARLY_TPM__ */
789824

825+
static struct heap_event_log_pointer_element2_1 *find_evt_log_ext_data(void)
826+
{
827+
struct txt_os_sinit_data *os_sinit;
828+
struct txt_ext_data_element *ext_data;
829+
830+
os_sinit = txt_os_sinit_data_start(__va(read_txt_reg(TXTCR_HEAP_BASE)));
831+
ext_data = (void *)((uint8_t *)os_sinit + sizeof(*os_sinit));
832+
833+
/*
834+
* Find TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1 which is necessary to
835+
* know where to put the next entry.
836+
*/
837+
while ( ext_data->type != TXT_HEAP_EXTDATA_TYPE_END ) {
838+
if ( ext_data->type == TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1 )
839+
break;
840+
ext_data = (void *)&ext_data->data[ext_data->size];
841+
}
842+
843+
if ( ext_data->type == TXT_HEAP_EXTDATA_TYPE_END )
844+
return NULL;
845+
846+
return (void *)&ext_data->data[0];
847+
}
848+
849+
static struct tpm2_log_hashes
850+
create_log_event20(struct tpm2_spec_id_event *evt_log, uint32_t evt_log_size,
851+
uint32_t pcr, uint32_t type, uint8_t *data,
852+
unsigned data_size)
853+
{
854+
struct tpm2_log_hashes log_hashes = {0};
855+
856+
struct heap_event_log_pointer_element2_1 *log_ext_data;
857+
struct tpm2_pcr_event_header *new_entry;
858+
uint32_t entry_size;
859+
unsigned i;
860+
uint8_t *p;
861+
862+
log_ext_data = find_evt_log_ext_data();
863+
if ( log_ext_data == NULL )
864+
return log_hashes;
865+
866+
entry_size = sizeof(*new_entry);
867+
for ( i = 0; i < evt_log->digestCount; ++i ) {
868+
entry_size += sizeof(uint16_t); /* hash type */
869+
entry_size += evt_log->digestSizes[i].digestSize;
870+
}
871+
entry_size += sizeof(uint32_t); /* data size field */
872+
entry_size += data_size;
873+
874+
/*
875+
* Check if there is enough space left for new entry.
876+
* Note: it is possible to introduce a gap in event log if entry with big
877+
* data_size is followed by another entry with smaller data. Maybe we should
878+
* cap the event log size in such case?
879+
*/
880+
if ( log_ext_data->next_record_offset + entry_size > evt_log_size )
881+
return log_hashes;
882+
883+
new_entry = (void *)((uint8_t *)evt_log + log_ext_data->next_record_offset);
884+
log_ext_data->next_record_offset += entry_size;
885+
886+
new_entry->pcrIndex = pcr;
887+
new_entry->eventType = type;
888+
new_entry->digestCount = evt_log->digestCount;
889+
890+
p = &new_entry->digests[0];
891+
for ( i = 0; i < evt_log->digestCount; ++i ) {
892+
uint16_t alg = evt_log->digestSizes[i].algId;
893+
uint16_t size = evt_log->digestSizes[i].digestSize;
894+
895+
*(uint16_t *)p = alg;
896+
p += sizeof(uint16_t);
897+
898+
log_hashes.hashes[i].alg = alg;
899+
log_hashes.hashes[i].size = size;
900+
log_hashes.hashes[i].data = p;
901+
p += size;
902+
903+
/* This is called "OneDigest" in TXT Software Development Guide. */
904+
memset(log_hashes.hashes[i].data, 0, size);
905+
log_hashes.hashes[i].data[0] = 1;
906+
}
907+
log_hashes.count = evt_log->digestCount;
908+
909+
*(uint32_t *)p = data_size;
910+
p += sizeof(uint32_t);
911+
912+
if ( data && data_size > 0 )
913+
memcpy(p, data, data_size);
914+
915+
return log_hashes;
916+
}
917+
790918
/************************** end of TPM2.0 specific ****************************/
791919

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

812940
tpm12_hash_extend(loc, buf, size, pcr, entry_digest);
813941
} else {
814-
uint8_t sha1_digest[SHA1_DIGEST_SIZE];
815-
uint8_t sha256_digest[SHA256_DIGEST_SIZE];
816942
uint32_t rc;
817943

818-
struct tpm2_log_hashes log_hashes = {
819-
.count = 2,
820-
.hashes = {
821-
{
822-
.alg = TPM_ALG_SHA1,
823-
.size = SHA1_DIGEST_SIZE,
824-
.data = sha1_digest,
825-
},
826-
{
827-
.alg = TPM_ALG_SHA256,
828-
.size = SHA256_DIGEST_SIZE,
829-
.data = sha256_digest,
830-
},
831-
},
832-
};
944+
struct tpm2_spec_id_event *evt_log = evt_log_addr;
945+
struct tpm2_log_hashes log_hashes =
946+
create_log_event20(evt_log, evt_log_size, pcr, type, log_data,
947+
log_data_size);
833948

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

0 commit comments

Comments
 (0)