efi_loader: add UEFI GPT measurement
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>
This commit is contained in:
		
							parent
							
								
									3d49ee8510
								
							
						
					
					
						commit
						ce3dbc5d08
					
				|  | @ -45,6 +45,9 @@ enum if_type { | ||||||
| #define BLK_PRD_SIZE		20 | #define BLK_PRD_SIZE		20 | ||||||
| #define BLK_REV_SIZE		8 | #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 |  * Identifies the partition table type (ie. MBR vs GPT GUID) signature | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | @ -503,7 +503,7 @@ efi_status_t efi_init_variables(void); | ||||||
| void efi_variables_boot_exit_notify(void); | void efi_variables_boot_exit_notify(void); | ||||||
| efi_status_t efi_tcg2_notify_exit_boot_services_failed(void); | efi_status_t efi_tcg2_notify_exit_boot_services_failed(void); | ||||||
| /* Measure efi application invocation */ | /* 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 */ | /* Measure efi application exit */ | ||||||
| efi_status_t efi_tcg2_measure_efi_app_exit(void); | efi_status_t efi_tcg2_measure_efi_app_exit(void); | ||||||
| /* Called by bootefi to initialize root node */ | /* 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); | 				       const efi_guid_t *guid); | ||||||
| struct efi_device_path *efi_dp_concat(const struct efi_device_path *dp1, | struct efi_device_path *efi_dp_concat(const struct efi_device_path *dp1, | ||||||
| 				      const struct efi_device_path *dp2); | 				      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_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data, | ||||||
| 					 efi_uintn_t *size); | 					 efi_uintn_t *size); | ||||||
| unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data); | unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data); | ||||||
|  |  | ||||||
|  | @ -225,6 +225,18 @@ struct smbios_handoff_table_pointers2 { | ||||||
| 	struct efi_configuration_table table_entry[]; | 	struct efi_configuration_table table_entry[]; | ||||||
| } __packed; | } __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 { | struct efi_tcg2_protocol { | ||||||
| 	efi_status_t (EFIAPI * get_capability)(struct efi_tcg2_protocol *this, | 	efi_status_t (EFIAPI * get_capability)(struct efi_tcg2_protocol *this, | ||||||
| 					       struct efi_tcg2_boot_service_capability *capability); | 					       struct efi_tcg2_boot_service_capability *capability); | ||||||
|  |  | ||||||
|  | @ -3004,7 +3004,7 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, | ||||||
| 
 | 
 | ||||||
| 	if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) { | 	if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) { | ||||||
| 		if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) { | 		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) { | 			if (ret != EFI_SUCCESS) { | ||||||
| 				log_warning("tcg2 measurement fails(0x%lx)\n", | 				log_warning("tcg2 measurement fails(0x%lx)\n", | ||||||
| 					    ret); | 					    ret); | ||||||
|  |  | ||||||
|  | @ -1239,3 +1239,30 @@ efi_device_path *efi_dp_from_lo(struct efi_load_option *lo, | ||||||
| 
 | 
 | ||||||
| 	return NULL; | 	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; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -1528,12 +1528,152 @@ static void *find_smbios_table(void) | ||||||
| 	return NULL; | 	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 *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 |  * efi_tcg2_measure_efi_app_invocation() - measure efi app invocation | ||||||
|  * |  * | ||||||
|  * Return:	status code |  * 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; | 	efi_status_t ret; | ||||||
| 	u32 pcr_index; | 	u32 pcr_index; | ||||||
|  | @ -1565,6 +1705,10 @@ efi_status_t efi_tcg2_measure_efi_app_invocation(void) | ||||||
| 			goto out; | 			goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	ret = tcg2_measure_gpt_data(dev, handle); | ||||||
|  | 	if (ret != EFI_SUCCESS) | ||||||
|  | 		goto out; | ||||||
|  | 
 | ||||||
| 	for (pcr_index = 0; pcr_index <= 7; pcr_index++) { | 	for (pcr_index = 0; pcr_index <= 7; pcr_index++) { | ||||||
| 		ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR, | 		ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR, | ||||||
| 					 sizeof(event), (u8 *)&event); | 					 sizeof(event), (u8 *)&event); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue