This commit adds the UEFI GPT disk partition topology
measurement required in TCG PC Client Platform Firmware
Profile Specification

Signed-off-by: Masahisa Kojima <masahisa.koj...@linaro.org>
---
Changes in v4:
- update commit message
- return EFI_SUCCESS if device path is NULL
- use memalign()

Changes in v3:
- EV_EFI_GPT_EVENT is measured before EV_SEPARATOR, same as
  other PCRs
- use PTR_ARRAY instead of ARRAY
- create sub-function of allocating io_aligned buffer
- move search_gpt_dp_node() into efi_device_path.c

 include/blk.h                    |   3 +
 include/efi_loader.h             |   3 +-
 include/efi_tcg2.h               |  12 +++
 lib/efi_loader/efi_boottime.c    |   2 +-
 lib/efi_loader/efi_device_path.c |  27 ++++++
 lib/efi_loader/efi_tcg2.c        | 146 ++++++++++++++++++++++++++++++-
 6 files changed, 190 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 d0433ea52e..d52e399841 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 */
@@ -847,6 +847,7 @@ struct efi_device_path *efi_dp_from_lo(struct 
efi_load_option *lo,
                                       const efi_guid_t *guid);
 struct efi_device_path *efi_dp_concat(const struct efi_device_path *dp1,
                                      const struct efi_device_path *dp2);
+struct efi_device_path *search_gpt_dp_node(struct efi_device_path 
*device_path);
 efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data,
                                         efi_uintn_t *size);
 unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data);
diff --git a/include/efi_tcg2.h b/include/efi_tcg2.h
index ca66695b39..50a59f9263 100644
--- a/include/efi_tcg2.h
+++ b/include/efi_tcg2.h
@@ -225,6 +225,18 @@ struct smbios_handoff_table_pointers2 {
        struct efi_configuration_table table_entry[];
 } __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 973134b12d..1823990d9b 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -3004,7 +3004,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_device_path.c b/lib/efi_loader/efi_device_path.c
index c04439d16d..735ed0bd0f 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -1239,3 +1239,30 @@ efi_device_path *efi_dp_from_lo(struct efi_load_option 
*lo,
 
        return NULL;
 }
+
+/**
+ * search_gpt_dp_node() - search gpt device path node
+ *
+ * @device_path:       device path
+ *
+ * Return:     pointer to the gpt device path node
+ */
+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;
+}
diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
index da589d0197..377b138855 100644
--- a/lib/efi_loader/efi_tcg2.c
+++ b/lib/efi_loader/efi_tcg2.c
@@ -1528,12 +1528,152 @@ static void *find_smbios_table(void)
        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;
+       efi_guid_t null_guid = NULL_GUID;
+       gpt_header *gpt_h;
+       gpt_entry *entry;
+       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;
+       if (!orig_device_path) /* no device path, skip GPT measurement */
+               return EFI_SUCCESS;
+
+       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;
+
+       gpt_h = memalign(block_io->media->io_align, 
block_io->media->block_size);
+       if (!gpt_h) {
+               ret = EFI_OUT_OF_RESOURCES;
+               goto out2;
+       }
+
+       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;
+       entry = memalign(block_io->media->io_align, total_gpt_entry_size);
+       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(gpt_h);
+       free(entry);
+       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;
@@ -1565,6 +1705,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;
+
        for (pcr_index = 0; pcr_index <= 7; pcr_index++) {
                ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR,
                                         sizeof(event), (u8 *)&event);
-- 
2.17.1

Reply via email to