[SLOF] [PATCH v7 8/8] tcgbios: Measure the GPT table

Stefan Berger stefanb at linux.ibm.com
Wed Jan 22 07:01:47 AEDT 2020


From: Stefan Berger <stefanb at linux.vnet.ibm.com>

Measure and log the GPT table including LBA1 and all GPT table entries
with a non-zero Type GUID.

We follow the specification "TCG PC Client Platform Firmware Profile
Specification" for the format of what needs to be logged and measured.
See section "Event Logging" subsection "Measuring UEFI Variables" for
the UEFI_GPT_DATA structure.

Signed-off-by: Stefan Berger <stefanb at linux.ibm.com>
---
 board-qemu/slof/vtpm-sml.fs    |  8 ++++
 lib/libtpm/tcgbios.c           | 88 ++++++++++++++++++++++++++++++++++
 lib/libtpm/tcgbios.h           |  3 ++
 lib/libtpm/tcgbios_int.h       | 40 ++++++++++++++++
 lib/libtpm/tpm.code            | 32 +++++++++++++
 lib/libtpm/tpm.in              |  3 ++
 slof/fs/packages/disk-label.fs | 22 +++++++++
 7 files changed, 196 insertions(+)

diff --git a/board-qemu/slof/vtpm-sml.fs b/board-qemu/slof/vtpm-sml.fs
index a51c907..fd0e6ee 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 252a44e..1ea3dfa 100644
--- a/slof/fs/packages/disk-label.fs
+++ b/slof/fs/packages/disk-label.fs
@@ -433,6 +433,27 @@ B9E5                CONSTANT GPT-BASIC-DATA-PARTITION-2
    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 at -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 at -le dup 0= IF false exit THEN
@@ -455,6 +476,7 @@ B9E5                CONSTANT GPT-BASIC-DATA-PARTITION-2
 ;
 
 : try-gpt-dos-partition ( -- true|false )
+   measure-gpt-partition
    get-gpt-partition 0= IF false EXIT THEN
    block gpt>num-part-entry l at -le dup 0= IF false EXIT THEN
    1+ 1 ?DO
-- 
2.24.1



More information about the SLOF mailing list