efi_loader: add UEFI GPT measurement
authorMasahisa Kojima <masahisa.kojima@linaro.org>
Tue, 26 Oct 2021 08:27:25 +0000 (17:27 +0900)
committerHeinrich Schuchardt <heinrich.schuchardt@canonical.com>
Tue, 26 Oct 2021 19:32:46 +0000 (21:32 +0200)
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.kojima@linaro.org>
include/blk.h
include/efi_loader.h
include/efi_tcg2.h
lib/efi_loader/efi_boottime.c
lib/efi_loader/efi_device_path.c
lib/efi_loader/efi_tcg2.c

index 19bab08..f0cc7ca 100644 (file)
@@ -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
  */
index d0433ea..d52e399 100644 (file)
@@ -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);
index ca66695..50a59f9 100644 (file)
@@ -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);
index 973134b..1823990 100644 (file)
@@ -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);
index c04439d..735ed0b 100644 (file)
@@ -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;
+}
index da589d0..dc45eaf 100644 (file)
@@ -1529,11 +1529,151 @@ static void *find_smbios_table(void)
 }
 
 /**
+ * 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 *gpt_h;
+       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;
+       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);