On 9/15/21 7:15 AM, Masahisa Kojima wrote:
This commit adds the UEFI GPT disk partition topology
measurement required in TCG PC Client PFP Spec.

Thanks for looking into the missing parts of TCG measurement in U-Boot.

The requirements in the TCG PC Client PFP Spec are strange. It does not
explicitly say how to handle multiple block devices. Did the authors
never enjoy the pleasure of a second disk drive?

With your implementation you would measure the GPT table of the SD-card
from which you load Shim or GRUB but would not care about the GPT of the
NVMe drive with your OS.

A clarification by the TCG standards committee would be helpful.

After this series "10.2.7 DEVICE_SECURITY_EVENT_DATA Structure" still
needs to be covered.

Best regards

Heinrich


Signed-off-by: Masahisa Kojima <[email protected]>
---
  include/blk.h                 |   3 +
  include/efi_loader.h          |   2 +-
  include/efi_tcg2.h            |  12 +++
  lib/efi_loader/efi_boottime.c |   2 +-
  lib/efi_loader/efi_tcg2.c     | 175 +++++++++++++++++++++++++++++++++-
  5 files changed, 191 insertions(+), 3 deletions(-)

diff --git a/include/blk.h b/include/blk.h
index 19bab081c2..f0cc7ca1a2 100644
--- a/include/blk.h
+++ b/include/blk.h
@@ -45,6 +45,9 @@ enum if_type {
  #define BLK_PRD_SIZE          20
  #define BLK_REV_SIZE          8

+#define PART_FORMAT_PCAT       0x1
+#define PART_FORMAT_GPT                0x2
+
  /*
   * Identifies the partition table type (ie. MBR vs GPT GUID) signature
   */
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 13f0c24058..dbcc296e01 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -503,7 +503,7 @@ efi_status_t efi_init_variables(void);
  void efi_variables_boot_exit_notify(void);
  efi_status_t efi_tcg2_notify_exit_boot_services_failed(void);
  /* Measure efi application invocation */
-efi_status_t efi_tcg2_measure_efi_app_invocation(void);
+efi_status_t efi_tcg2_measure_efi_app_invocation(struct efi_loaded_image_obj 
*handle);
  /* Measure efi application exit */
  efi_status_t efi_tcg2_measure_efi_app_exit(void);
  /* Called by bootefi to initialize root node */
diff --git a/include/efi_tcg2.h b/include/efi_tcg2.h
index da33f8a1d0..33257fa96b 100644
--- a/include/efi_tcg2.h
+++ b/include/efi_tcg2.h
@@ -230,6 +230,18 @@ struct smbios_handoff_table_pointers2 {
        struct efi_configuration_table table_entry[1];
  } __packed;

+/**
+ * struct tdUEFI_GPT_DATA - event log structure of industry standard tables
+ * @uefi_partition_header:     gpt partition header
+ * @number_of_partitions:      the number of partition
+ * @partitions:                        partition entries
+ */
+struct efi_gpt_data {
+       gpt_header uefi_partition_header;
+       u64 number_of_partitions;
+       gpt_entry partitions[];
+} __packed;
+
  struct efi_tcg2_protocol {
        efi_status_t (EFIAPI * get_capability)(struct efi_tcg2_protocol *this,
                                               struct 
efi_tcg2_boot_service_capability *capability);
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 701e2212c8..bf5661e1ee 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -3003,7 +3003,7 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t 
image_handle,

        if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {
                if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {
-                       ret = efi_tcg2_measure_efi_app_invocation();
+                       ret = efi_tcg2_measure_efi_app_invocation(image_obj);
                        if (ret != EFI_SUCCESS) {
                                log_warning("tcg2 measurement fails(0x%lx)\n",
                                            ret);
diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
index 7f47998a55..35810615ed 100644
--- a/lib/efi_loader/efi_tcg2.c
+++ b/lib/efi_loader/efi_tcg2.c
@@ -1525,12 +1525,181 @@ static void *search_smbios_table(void)
        return NULL;
  }

+/**
+ * search_gpt_dp_node() - search gpt device path node
+ *
+ * @device_path:       device path
+ *
+ * Return:     pointer to the gpt device path node
+ */
+static struct
+efi_device_path *search_gpt_dp_node(struct efi_device_path *device_path)
+{
+       struct efi_device_path *dp = device_path;
+
+       while (dp) {
+               if (dp->type == DEVICE_PATH_TYPE_MEDIA_DEVICE &&
+                   dp->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) {
+                       struct efi_device_path_hard_drive_path *hd_dp =
+                               (struct efi_device_path_hard_drive_path *)dp;
+
+                       if (hd_dp->partmap_type == PART_FORMAT_GPT &&
+                           hd_dp->signature_type == SIG_TYPE_GUID)
+                               return dp;
+               }
+               dp = efi_dp_next(dp);
+       }
+
+       return NULL;
+}
+
+/**
+ * tcg2_measure_gpt_table() - measure gpt table
+ *
+ * @dev:               TPM device
+ * @loaded_image:      handle to the loaded image
+ *
+ * Return:     status code
+ */
+static efi_status_t
+tcg2_measure_gpt_data(struct udevice *dev,
+                     struct efi_loaded_image_obj *loaded_image)
+{
+       efi_status_t ret;
+       efi_handle_t handle;
+       struct efi_handler *dp_handler;
+       struct efi_device_path *orig_device_path;
+       struct efi_device_path *device_path;
+       struct efi_device_path *dp;
+       struct efi_block_io *block_io;
+       struct efi_gpt_data *event = NULL;
+       efi_guid_t null_guid = NULL_GUID;
+       gpt_header *orig_gpt_h = NULL;
+       gpt_entry *orig_gpt_e = NULL;
+       gpt_header *gpt_h = NULL;
+       gpt_entry *entry = NULL;
+       gpt_entry *gpt_e;
+       u32 num_of_valid_entry = 0;
+       u32 event_size;
+       u32 i;
+       u32 total_gpt_entry_size;
+
+       ret = efi_search_protocol(&loaded_image->header,
+                                 &efi_guid_loaded_image_device_path,
+                                 &dp_handler);
+       if (ret != EFI_SUCCESS)
+               return ret;
+
+       orig_device_path = dp_handler->protocol_interface;
+       device_path = efi_dp_dup(orig_device_path);
+       if (!device_path)
+               return EFI_OUT_OF_RESOURCES;
+
+       dp = search_gpt_dp_node(device_path);
+       if (!dp) {
+               /* no GPT device path node found, skip GPT measurement */
+               ret = EFI_SUCCESS;
+               goto out1;
+       }
+
+       /* read GPT header */
+       dp->type = DEVICE_PATH_TYPE_END;
+       dp->sub_type = DEVICE_PATH_SUB_TYPE_END;
+       dp = device_path;
+       ret = EFI_CALL(systab.boottime->locate_device_path(&efi_block_io_guid,
+                                                          &dp, &handle));
+       if (ret != EFI_SUCCESS)
+               goto out1;
+
+       ret = EFI_CALL(efi_handle_protocol(handle,
+                                          &efi_block_io_guid, (void 
**)&block_io));
+       if (ret != EFI_SUCCESS)
+               goto out1;
+
+       orig_gpt_h = calloc(1, (block_io->media->block_size + 
block_io->media->io_align));
+       if (!orig_gpt_h) {
+               ret = EFI_OUT_OF_RESOURCES;
+               goto out2;
+       }
+
+       gpt_h = (gpt_header *)ALIGN((uintptr_t)orig_gpt_h, 
block_io->media->io_align);
+       ret = block_io->read_blocks(block_io, block_io->media->media_id, 1,
+                                   block_io->media->block_size, gpt_h);
+       if (ret != EFI_SUCCESS)
+               goto out2;
+
+       /* read GPT entry */
+       total_gpt_entry_size = gpt_h->num_partition_entries *
+                              gpt_h->sizeof_partition_entry;
+       orig_gpt_e = calloc(1, total_gpt_entry_size + 
block_io->media->io_align);
+       entry = (void *)ALIGN((uintptr_t)orig_gpt_e, block_io->media->io_align);
+       if (!entry) {
+               ret = EFI_OUT_OF_RESOURCES;
+               goto out2;
+       }
+
+       ret = block_io->read_blocks(block_io, block_io->media->media_id,
+                                   gpt_h->partition_entry_lba,
+                                   total_gpt_entry_size, entry);
+       if (ret != EFI_SUCCESS)
+               goto out2;
+
+       /* count valid GPT entry */
+       gpt_e = entry;
+       for (i = 0; i < gpt_h->num_partition_entries; i++) {
+               if (guidcmp(&null_guid, &gpt_e->partition_type_guid))
+                       num_of_valid_entry++;
+
+               gpt_e = (gpt_entry *)((u8 *)gpt_e + 
gpt_h->sizeof_partition_entry);
+       }
+
+       /* prepare event data for measurement */
+       event_size = sizeof(struct efi_gpt_data) +
+               (num_of_valid_entry * gpt_h->sizeof_partition_entry);
+       event = calloc(1, event_size);
+       if (!event) {
+               ret = EFI_OUT_OF_RESOURCES;
+               goto out2;
+       }
+       memcpy(event, gpt_h, sizeof(gpt_header));
+       put_unaligned_le64(num_of_valid_entry, &event->number_of_partitions);
+
+       /* copy valid GPT entry */
+       gpt_e = entry;
+       num_of_valid_entry = 0;
+       for (i = 0; i < gpt_h->num_partition_entries; i++) {
+               if (guidcmp(&null_guid, &gpt_e->partition_type_guid)) {
+                       memcpy((u8 *)event->partitions +
+                              (num_of_valid_entry * 
gpt_h->sizeof_partition_entry),
+                              gpt_e, gpt_h->sizeof_partition_entry);
+                       num_of_valid_entry++;
+               }
+
+               gpt_e = (gpt_entry *)((u8 *)gpt_e + 
gpt_h->sizeof_partition_entry);
+       }
+
+       ret = tcg2_measure_event(dev, 5, EV_EFI_GPT_EVENT, event_size, (u8 
*)event);
+       if (ret != EFI_SUCCESS)
+               goto out2;
+
+out2:
+       EFI_CALL(efi_close_protocol((efi_handle_t)block_io, &efi_block_io_guid,
+                                   NULL, NULL));
+       free(orig_gpt_h);
+       free(orig_gpt_e);
+       free(event);
+out1:
+       efi_free_pool(device_path);
+
+       return ret;
+}
+
  /**
   * efi_tcg2_measure_efi_app_invocation() - measure efi app invocation
   *
   * Return:    status code
   */
-efi_status_t efi_tcg2_measure_efi_app_invocation(void)
+efi_status_t efi_tcg2_measure_efi_app_invocation(struct efi_loaded_image_obj 
*handle)
  {
        efi_status_t ret;
        u32 pcr_index;
@@ -1569,6 +1738,10 @@ efi_status_t efi_tcg2_measure_efi_app_invocation(void)
                        goto out;
        }

+       ret = tcg2_measure_gpt_data(dev, handle);
+       if (ret != EFI_SUCCESS)
+               goto out;
+
        tcg2_efi_app_invoked = true;
  out:
        return ret;

Reply via email to