diff --git a/board-qemu/slof/vtpm-sml.fs b/board-qemu/slof/vtpm-sml.fs index fd888fb..865db06 100644 --- a/board-qemu/slof/vtpm-sml.fs +++ b/board-qemu/slof/vtpm-sml.fs @@ -42,6 +42,14 @@ s" ibm,vtpm" 2dup device-name device-type THEN ; +: measure-gpt ( ) + 0 7 separator-event + tpm-measure-gpt + ?dup IF + ." VTPM: Error code from tpm-measure-gpt: " . cr + THEN +; + : leave-firmware ( -- ) tpm-leave-firmware ( errcode ) ?dup IF diff --git a/lib/libtpm/tcgbios.c b/lib/libtpm/tcgbios.c index c5f8ccf..be6c3d1 100644 --- a/lib/libtpm/tcgbios.c +++ b/lib/libtpm/tcgbios.c @@ -69,6 +69,11 @@ static struct { #define TPM2_ALG_SHA512_FLAG (1 << 3) #define TPM2_ALG_SM3_256_FLAG (1 << 4) +static const uint8_t ZeroGuid[16] = { 0 }; + +static UEFI_GPT_DATA *uefi_gpt_data; +static size_t uefi_gpt_data_size; + /* * TPM 2 logs are written in little endian format. */ @@ -925,6 +930,89 @@ uint32_t tpm_measure_bcv_mbr(uint32_t bootdrv, const uint8_t *addr, addr + 0x1b8, 0x48); } +/* + * This is the first function to call when measuring a GPT table. + * It allocates memory for the data to log which are 'measured' later on. + */ +void tpm_gpt_set_lba1(const uint8_t *addr, uint32_t length) +{ + if (!tpm_is_working()) + return; + + SLOF_free_mem(uefi_gpt_data, uefi_gpt_data_size); + + uefi_gpt_data_size = sizeof(UEFI_GPT_DATA); + uefi_gpt_data = SLOF_alloc_mem(uefi_gpt_data_size); + if (!uefi_gpt_data) + return; + + memcpy(&uefi_gpt_data->EfiPartitionHeader, + addr, sizeof(uefi_gpt_data->EfiPartitionHeader)); + uefi_gpt_data->NumberOfPartitions = 0; +} + +/* + * This function adds a GPT entry to the data to measure. It must + * be called after tpm_gpt_set_lba1. + */ +void tpm_gpt_add_entry(const uint8_t *addr, uint32_t length) +{ + size_t sz; + UEFI_PARTITION_ENTRY *upe = (void *)addr; + void *tmp; + + if (!tpm_is_working() || + !uefi_gpt_data || + length < sizeof(*upe) || + !memcmp(upe->partTypeGuid, ZeroGuid, sizeof(ZeroGuid))) + return; + + sz = offset_of(UEFI_GPT_DATA, Partitions) + + (uefi_gpt_data->NumberOfPartitions + 1) + * sizeof(UEFI_PARTITION_ENTRY); + if (sz > uefi_gpt_data_size) { + tmp = SLOF_alloc_mem(sz); + if (!tmp) + goto err_no_mem; + + memcpy(tmp, uefi_gpt_data, uefi_gpt_data_size); + SLOF_free_mem(uefi_gpt_data, uefi_gpt_data_size); + uefi_gpt_data = tmp; + uefi_gpt_data_size = sz; + } + + memcpy(&uefi_gpt_data->Partitions[uefi_gpt_data->NumberOfPartitions], + addr, + sizeof(UEFI_PARTITION_ENTRY)); + uefi_gpt_data->NumberOfPartitions++; + + return; + +err_no_mem: + SLOF_free_mem(uefi_gpt_data, uefi_gpt_data_size); + uefi_gpt_data_size = 0; + uefi_gpt_data = NULL; +} + +/* + * tpm_measure_gpt finally measures the GPT table and adds an entry + * to the log. + */ +uint32_t tpm_measure_gpt(void) +{ + size_t sz; + + if (!tpm_is_working()) + return TCGBIOS_GENERAL_ERROR; + + sz = offset_of(UEFI_GPT_DATA, Partitions) + + uefi_gpt_data->NumberOfPartitions * sizeof(UEFI_PARTITION_ENTRY); + + return tpm_add_measurement_to_log(5, EV_EFI_GPT_EVENT, + (const char *)uefi_gpt_data, sz, + (const uint8_t *)uefi_gpt_data, sz); +} + uint32_t tpm_measure_scrtm(void) { uint32_t rc; diff --git a/lib/libtpm/tcgbios.h b/lib/libtpm/tcgbios.h index c4a2e71..8174d86 100644 --- a/lib/libtpm/tcgbios.h +++ b/lib/libtpm/tcgbios.h @@ -29,5 +29,8 @@ uint32_t tpm_driver_get_failure_reason(void); void tpm_driver_set_failure_reason(uint32_t errcode); bool tpm_is_working(void); void tpm20_menu(void); +void tpm_gpt_set_lba1(const uint8_t *addr, uint32_t length); +void tpm_gpt_add_entry(const uint8_t *addr, uint32_t length); +uint32_t tpm_measure_gpt(void); #endif /* TCGBIOS_H */ diff --git a/lib/libtpm/tcgbios_int.h b/lib/libtpm/tcgbios_int.h index 6892e6f..1a88402 100644 --- a/lib/libtpm/tcgbios_int.h +++ b/lib/libtpm/tcgbios_int.h @@ -39,6 +39,8 @@ #define EV_S_CRTM_VERSION 8 #define EV_IPL 13 #define EV_IPL_PARTITION_DATA 14 +#define EV_EFI_EVENT_BASE 0x80000000 +#define EV_EFI_GPT_EVENT (EV_EFI_EVENT_BASE + 0x6) #define BCV_DEVICE_HDD 0x80 @@ -91,6 +93,44 @@ struct TCG_EfiSpecIdEventStruct { */ } __attribute__((packed)); +/* EFI related data structures for logging */ +typedef struct { + uint64_t signature; + uint32_t revision; + uint32_t size; + uint32_t crc32; + uint8_t reserved[4]; +} __attribute__((packed)) UEFI_TABLE_HEADER; + +typedef struct { + UEFI_TABLE_HEADER header; + uint64_t currentLba; + uint64_t backupLba; + uint64_t firstLba; + uint64_t lastLba; + uint8_t diskGuid[16]; + uint64_t partEntryLba; + uint32_t numPartEntry; + uint32_t partEntrySize; + uint32_t partArrayCrc32; + uint8_t reserved[420]; +} __attribute__((packed)) UEFI_PARTITION_TABLE_HEADER; + +typedef struct { + uint8_t partTypeGuid[16]; + uint8_t partGuid[16]; + uint64_t firstLba; + uint64_t lastLba; + uint64_t attribute; + uint8_t partName[72]; +} __attribute__((packed)) UEFI_PARTITION_ENTRY; + +typedef struct { + UEFI_PARTITION_TABLE_HEADER EfiPartitionHeader; + uint64_t NumberOfPartitions; + UEFI_PARTITION_ENTRY Partitions[0]; +} __attribute__((packed)) UEFI_GPT_DATA; + /* Input and Output headers for all TPM commands */ struct tpm_req_header { uint16_t tag; diff --git a/lib/libtpm/tpm.code b/lib/libtpm/tpm.code index b8f5669..205c608 100644 --- a/lib/libtpm/tpm.code +++ b/lib/libtpm/tpm.code @@ -137,3 +137,35 @@ MIRP PRIM(tpm20_X2d_menu) tpm20_menu(); MIRP + +/*************************************************************************/ +/* Set the LBA1 of the GPT */ +/* SLOF: tpm-gpt-set-lba1 ( addr length -- ) */ +/* LIBTPM: tpm_gpt_set_lba1(addr, length) */ +/*************************************************************************/ +PRIM(tpm_X2d_gpt_X2d_set_X2d_lba1) + int length = TOS.u; POP; + void *addr = TOS.a; POP; + tpm_gpt_set_lba1(addr, length); +MIRP + +/*************************************************************************/ +/* Add a GPT table entry */ +/* SLOF: tpm-gpt-add-entry ( addr length -- ) */ +/* LIBTPM: tpm_gpt_add_entry(addr, length) */ +/*************************************************************************/ +PRIM(tpm_X2d_gpt_X2d_add_X2d_entry) + int length = TOS.u; POP; + void *addr = TOS.a; POP; + tpm_gpt_add_entry(addr, length); +MIRP + +/*************************************************************************/ +/* Measure and log GPT EVENT */ +/* SLOF: tpm-measure-gpt ( -- errcode ) */ +/* LIBTPM: errcode = tpm_measure_gpt() */ +/*************************************************************************/ +PRIM(tpm_X2d_measure_X2d_gpt) + PUSH; + TOS.n = tpm_measure_gpt(); +MIRP diff --git a/lib/libtpm/tpm.in b/lib/libtpm/tpm.in index 590fee1..bdbc47d 100644 --- a/lib/libtpm/tpm.in +++ b/lib/libtpm/tpm.in @@ -25,3 +25,6 @@ cod(tpm-measure-scrtm) cod(tpm-driver-get-failure-reason) cod(tpm-driver-set-failure-reason) cod(tpm20-menu) +cod(tpm-gpt-set-lba1) +cod(tpm-gpt-add-entry) +cod(tpm-measure-gpt) diff --git a/slof/fs/packages/disk-label.fs b/slof/fs/packages/disk-label.fs index 969eb00..bb64022 100644 --- a/slof/fs/packages/disk-label.fs +++ b/slof/fs/packages/disk-label.fs @@ -431,6 +431,27 @@ CREATE GPT-LINUX-PARTITION 10 allot block gpt>signature x@ GPT-SIGNATURE = ; +\ Measure the GPT partition table by collecting its LBA1 +\ and GPT Entries and then measuring them. +\ This function modifies 'block' and 'seek-pos' + +: measure-gpt-partition ( -- ) + s" /ibm,vtpm" find-node ?dup IF + get-gpt-partition 0= if drop EXIT THEN + + block block-size tpm-gpt-set-lba1 + + block gpt>num-part-entry l@-le + 1+ 1 ?DO + seek-pos 0 seek drop + block gpt-part-size read drop + block gpt-part-size tpm-gpt-add-entry + seek-pos gpt-part-size + to seek-pos + LOOP + s" measure-gpt" rot $call-static + THEN +; + : load-from-gpt-prep-partition ( addr -- size ) get-gpt-partition 0= IF false EXIT THEN block gpt>num-part-entry l@-le dup 0= IF false exit THEN @@ -465,6 +486,7 @@ CREATE GPT-LINUX-PARTITION 10 allot ; : try-gpt-dos-partition ( -- true|false ) + measure-gpt-partition get-gpt-partition 0= IF false EXIT THEN block gpt>num-part-entry l@-le dup 0= IF false EXIT THEN 1+ 1 ?DO