--- /dev/null
+/** @file\r
+ The library instance provides security service of TPM2 measure boot.\r
+\r
+ Caution: This file requires additional review when modified.\r
+ This library will have external input - PE/COFF image and GPT partition.\r
+ This external input must be validated carefully to avoid security issue like\r
+ buffer overflow, integer overflow.\r
+\r
+ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content\r
+ read is within the image buffer.\r
+\r
+ TrEEMeasurePeImage() function will accept untrusted PE/COFF image and validate its\r
+ data structure within this image buffer before use.\r
+\r
+ TrEEMeasureGptTable() function will receive untrusted GPT partition table, and parse\r
+ partition data carefully.\r
+\r
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution. The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/TrEEProtocol.h>\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/DiskIo.h>\r
+#include <Protocol/DevicePathToText.h>\r
+#include <Protocol/FirmwareVolumeBlock.h>\r
+\r
+#include <Guid/MeasuredFvHob.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseCryptLib.h>\r
+#include <Library/PeCoffLib.h>\r
+#include <Library/SecurityManagementLib.h>\r
+#include <Library/HobLib.h>\r
+\r
+//\r
+// Flag to check GPT partition. It only need be measured once.\r
+//\r
+BOOLEAN mTrEEMeasureGptTableFlag = FALSE;\r
+EFI_GUID mTrEEZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};\r
+UINTN mTrEEMeasureGptCount = 0;\r
+VOID *mTrEEFileBuffer;\r
+UINTN mTrEEImageSize;\r
+//\r
+// Measured FV handle cache\r
+//\r
+EFI_HANDLE mTrEECacheMeasuredHandle = NULL;\r
+MEASURED_HOB_DATA *mTrEEMeasuredHobData = NULL;\r
+\r
+/**\r
+ Reads contents of a PE/COFF image in memory buffer.\r
+\r
+ Caution: This function may receive untrusted input.\r
+ PE/COFF image is external input, so this function will make sure the PE/COFF image content\r
+ read is within the image buffer.\r
+\r
+ @param FileHandle Pointer to the file handle to read the PE/COFF image.\r
+ @param FileOffset Offset into the PE/COFF image to begin the read operation.\r
+ @param ReadSize On input, the size in bytes of the requested read operation. \r
+ On output, the number of bytes actually read.\r
+ @param Buffer Output buffer that contains the data read from the PE/COFF image.\r
+ \r
+ @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeTpm2MeasureBootLibImageRead (\r
+ IN VOID *FileHandle,\r
+ IN UINTN FileOffset,\r
+ IN OUT UINTN *ReadSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ UINTN EndPosition;\r
+\r
+ if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (MAX_ADDRESS - FileOffset < *ReadSize) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ EndPosition = FileOffset + *ReadSize;\r
+ if (EndPosition > mTrEEImageSize) {\r
+ *ReadSize = (UINT32)(mTrEEImageSize - FileOffset);\r
+ }\r
+\r
+ if (FileOffset >= mTrEEImageSize) {\r
+ *ReadSize = 0;\r
+ }\r
+\r
+ CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Measure GPT table data into TPM log.\r
+\r
+ Caution: This function may receive untrusted input.\r
+ The GPT partition table is external input, so this function should parse partition data carefully.\r
+\r
+ @param TreeProtocol Pointer to the located TREE protocol instance.\r
+ @param GptHandle Handle that GPT partition was installed.\r
+\r
+ @retval EFI_SUCCESS Successfully measure GPT table.\r
+ @retval EFI_UNSUPPORTED Not support GPT table on the given handle.\r
+ @retval EFI_DEVICE_ERROR Can't get GPT table because device error.\r
+ @retval EFI_OUT_OF_RESOURCES No enough resource to measure GPT table.\r
+ @retval other error value\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TrEEMeasureGptTable (\r
+ IN EFI_TREE_PROTOCOL *TreeProtocol,\r
+ IN EFI_HANDLE GptHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ EFI_DISK_IO_PROTOCOL *DiskIo;\r
+ EFI_PARTITION_TABLE_HEADER *PrimaryHeader;\r
+ EFI_PARTITION_ENTRY *PartitionEntry;\r
+ UINT8 *EntryPtr;\r
+ UINTN NumberOfPartition;\r
+ UINT32 Index;\r
+ TrEE_EVENT *TreeEvent;\r
+ EFI_GPT_DATA *GptData;\r
+ UINT32 EventSize;\r
+\r
+ if (mTrEEMeasureGptCount > 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (GptHandle, &gEfiBlockIoProtocolGuid, (VOID**)&BlockIo);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ Status = gBS->HandleProtocol (GptHandle, &gEfiDiskIoProtocolGuid, (VOID**)&DiskIo);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Read the EFI Partition Table Header\r
+ // \r
+ PrimaryHeader = (EFI_PARTITION_TABLE_HEADER *) AllocatePool (BlockIo->Media->BlockSize);\r
+ if (PrimaryHeader == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ } \r
+ Status = DiskIo->ReadDisk (\r
+ DiskIo,\r
+ BlockIo->Media->MediaId,\r
+ 1 * BlockIo->Media->BlockSize,\r
+ BlockIo->Media->BlockSize,\r
+ (UINT8 *)PrimaryHeader\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Failed to Read Partition Table Header!\n"));\r
+ FreePool (PrimaryHeader);\r
+ return EFI_DEVICE_ERROR;\r
+ } \r
+ //\r
+ // Read the partition entry.\r
+ //\r
+ EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);\r
+ if (EntryPtr == NULL) {\r
+ FreePool (PrimaryHeader);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ Status = DiskIo->ReadDisk (\r
+ DiskIo,\r
+ BlockIo->Media->MediaId,\r
+ MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),\r
+ PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry,\r
+ EntryPtr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (PrimaryHeader);\r
+ FreePool (EntryPtr);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ \r
+ //\r
+ // Count the valid partition\r
+ //\r
+ PartitionEntry = (EFI_PARTITION_ENTRY *)EntryPtr;\r
+ NumberOfPartition = 0;\r
+ for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {\r
+ if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mTrEEZeroGuid)) {\r
+ NumberOfPartition++; \r
+ }\r
+ PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);\r
+ }\r
+\r
+ //\r
+ // Prepare Data for Measurement\r
+ // \r
+ EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) \r
+ + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);\r
+ TreeEvent = (TrEE_EVENT *) AllocateZeroPool (EventSize + sizeof (TrEE_EVENT) - sizeof(TreeEvent->Event));\r
+ if (TreeEvent == NULL) {\r
+ FreePool (PrimaryHeader);\r
+ FreePool (EntryPtr);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ TreeEvent->Size = EventSize + sizeof (TrEE_EVENT) - sizeof(TreeEvent->Event);\r
+ TreeEvent->Header.HeaderSize = sizeof(TrEE_EVENT_HEADER);\r
+ TreeEvent->Header.HeaderVersion = TREE_EVENT_HEADER_VERSION;\r
+ TreeEvent->Header.PCRIndex = 5;\r
+ TreeEvent->Header.EventType = EV_EFI_GPT_EVENT;\r
+ GptData = (EFI_GPT_DATA *) TreeEvent->Event; \r
+\r
+ //\r
+ // Copy the EFI_PARTITION_TABLE_HEADER and NumberOfPartition\r
+ // \r
+ CopyMem ((UINT8 *)GptData, (UINT8*)PrimaryHeader, sizeof (EFI_PARTITION_TABLE_HEADER));\r
+ GptData->NumberOfPartitions = NumberOfPartition;\r
+ //\r
+ // Copy the valid partition entry\r
+ //\r
+ PartitionEntry = (EFI_PARTITION_ENTRY*)EntryPtr;\r
+ NumberOfPartition = 0;\r
+ for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {\r
+ if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mTrEEZeroGuid)) {\r
+ CopyMem (\r
+ (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry,\r
+ (UINT8 *)PartitionEntry,\r
+ PrimaryHeader->SizeOfPartitionEntry\r
+ );\r
+ NumberOfPartition++;\r
+ }\r
+ PartitionEntry =(EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);\r
+ }\r
+\r
+ //\r
+ // Measure the GPT data\r
+ //\r
+ Status = TreeProtocol->HashLogExtendEvent (\r
+ TreeProtocol,\r
+ 0,\r
+ (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) GptData,\r
+ (UINT64) EventSize,\r
+ TreeEvent\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ mTrEEMeasureGptCount++;\r
+ }\r
+\r
+ FreePool (PrimaryHeader);\r
+ FreePool (EntryPtr);\r
+ FreePool (TreeEvent);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Measure PE image into TPM log based on the authenticode image hashing in\r
+ PE/COFF Specification 8.0 Appendix A.\r
+\r
+ Caution: This function may receive untrusted input.\r
+ PE/COFF image is external input, so this function will validate its data structure\r
+ within this image buffer before use.\r
+\r
+ @param[in] TreeProtocol Pointer to the located TREE protocol instance.\r
+ @param[in] ImageAddress Start address of image buffer.\r
+ @param[in] ImageSize Image size\r
+ @param[in] LinkTimeBase Address that the image is loaded into memory.\r
+ @param[in] ImageType Image subsystem type.\r
+ @param[in] FilePath File path is corresponding to the input image.\r
+\r
+ @retval EFI_SUCCESS Successfully measure image.\r
+ @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.\r
+ @retval EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format. \r
+ @retval other error value\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TrEEMeasurePeImage (\r
+ IN EFI_TREE_PROTOCOL *TreeProtocol,\r
+ IN EFI_PHYSICAL_ADDRESS ImageAddress,\r
+ IN UINTN ImageSize,\r
+ IN UINTN LinkTimeBase,\r
+ IN UINT16 ImageType,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ TrEE_EVENT *TreeEvent;\r
+ EFI_IMAGE_LOAD_EVENT *ImageLoad;\r
+ UINT32 FilePathSize;\r
+ UINT32 EventSize;\r
+\r
+ Status = EFI_UNSUPPORTED;\r
+ ImageLoad = NULL;\r
+ FilePathSize = (UINT32) GetDevicePathSize (FilePath);\r
+\r
+ //\r
+ // Determine destination PCR by BootPolicy\r
+ //\r
+ EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize;\r
+ TreeEvent = AllocateZeroPool (EventSize + sizeof (TrEE_EVENT) - sizeof(TreeEvent->Event));\r
+ if (TreeEvent == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ TreeEvent->Size = EventSize + sizeof (TrEE_EVENT) - sizeof(TreeEvent->Event);\r
+ TreeEvent->Header.HeaderSize = sizeof(TrEE_EVENT_HEADER);\r
+ TreeEvent->Header.HeaderVersion = TREE_EVENT_HEADER_VERSION;\r
+ ImageLoad = (EFI_IMAGE_LOAD_EVENT *) TreeEvent->Event;\r
+\r
+ switch (ImageType) {\r
+ case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:\r
+ TreeEvent->Header.EventType = EV_EFI_BOOT_SERVICES_APPLICATION;\r
+ TreeEvent->Header.PCRIndex = 4;\r
+ break;\r
+ case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:\r
+ TreeEvent->Header.EventType = EV_EFI_BOOT_SERVICES_DRIVER;\r
+ TreeEvent->Header.PCRIndex = 2;\r
+ break;\r
+ case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
+ TreeEvent->Header.EventType = EV_EFI_RUNTIME_SERVICES_DRIVER;\r
+ TreeEvent->Header.PCRIndex = 2;\r
+ break;\r
+ default:\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "TrEEMeasurePeImage: Unknown subsystem type %d",\r
+ ImageType\r
+ ));\r
+ goto Finish;\r
+ }\r
+\r
+ ImageLoad->ImageLocationInMemory = ImageAddress;\r
+ ImageLoad->ImageLengthInMemory = ImageSize;\r
+ ImageLoad->ImageLinkTimeAddress = LinkTimeBase;\r
+ ImageLoad->LengthOfDevicePath = FilePathSize;\r
+ CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize);\r
+\r
+ //\r
+ // Log the PE data\r
+ //\r
+ Status = TreeProtocol->HashLogExtendEvent (\r
+ TreeProtocol,\r
+ PE_COFF_IMAGE,\r
+ ImageAddress,\r
+ ImageSize,\r
+ TreeEvent\r
+ );\r
+ if (Status == EFI_VOLUME_FULL) {\r
+ //\r
+ // Volume full here means the image is hashed and its result is extended to PCR.\r
+ // But the event log cann't be saved since log area is full.\r
+ // Just return EFI_SUCCESS in order not to block the image load.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+Finish:\r
+ FreePool (TreeEvent);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ The security handler is used to abstract platform-specific policy \r
+ from the DXE core response to an attempt to use a file that returns a \r
+ given status for the authentication check from the section extraction protocol. \r
+\r
+ The possible responses in a given SAP implementation may include locking \r
+ flash upon failure to authenticate, attestation logging for all signed drivers, \r
+ and other exception operations. The File parameter allows for possible logging \r
+ within the SAP of the driver.\r
+\r
+ If File is NULL, then EFI_INVALID_PARAMETER is returned.\r
+\r
+ If the file specified by File with an authentication status specified by \r
+ AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned.\r
+\r
+ If the file specified by File with an authentication status specified by \r
+ AuthenticationStatus is not safe for the DXE Core to use under any circumstances, \r
+ then EFI_ACCESS_DENIED is returned.\r
+\r
+ If the file specified by File with an authentication status specified by \r
+ AuthenticationStatus is not safe for the DXE Core to use right now, but it \r
+ might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is \r
+ returned.\r
+\r
+ @param[in] AuthenticationStatus This is the authentication status returned\r
+ from the securitymeasurement services for the\r
+ input file.\r
+ @param[in] File This is a pointer to the device path of the file that is\r
+ being dispatched. This will optionally be used for logging.\r
+ @param[in] FileBuffer File buffer matches the input file device path.\r
+ @param[in] FileSize Size of File buffer matches the input file device path.\r
+ @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.\r
+\r
+ @retval EFI_SUCCESS The file specified by DevicePath and non-NULL\r
+ FileBuffer did authenticate, and the platform policy dictates\r
+ that the DXE Foundation may use the file.\r
+ @retval other error value\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeTpm2MeasureBootHandler (\r
+ IN UINT32 AuthenticationStatus,\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
+ IN VOID *FileBuffer,\r
+ IN UINTN FileSize,\r
+ IN BOOLEAN BootPolicy\r
+ )\r
+{\r
+ EFI_TREE_PROTOCOL *TreeProtocol;\r
+ EFI_STATUS Status;\r
+ TREE_BOOT_SERVICE_CAPABILITY ProtocolCapability;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
+ EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode;\r
+ EFI_HANDLE Handle;\r
+ EFI_HANDLE TempHandle;\r
+ BOOLEAN ApplicationRequired;\r
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;\r
+ EFI_PHYSICAL_ADDRESS FvAddress;\r
+ UINT32 Index;\r
+\r
+ Status = gBS->LocateProtocol (&gEfiTrEEProtocolGuid, NULL, (VOID **) &TreeProtocol);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // TrEE protocol is not installed. So, TPM2 is not present.\r
+ // Don't do any measurement, and directly return EFI_SUCCESS.\r
+ //\r
+ DEBUG ((EFI_D_ERROR, "DxeTpm2MeasureBootHandler - TrEE - %r\n", Status));\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ ProtocolCapability.Size = (UINT8) sizeof (ProtocolCapability);\r
+ Status = TreeProtocol->GetCapability (\r
+ TreeProtocol, \r
+ &ProtocolCapability\r
+ );\r
+ if (EFI_ERROR (Status) || !ProtocolCapability.TrEEPresentFlag) {\r
+ //\r
+ // TPM device doesn't work or activate.\r
+ //\r
+ DEBUG ((EFI_D_ERROR, "DxeTpm2MeasureBootHandler (%r) - TrEEPresentFlag - %x\n", Status, ProtocolCapability.TrEEPresentFlag));\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Copy File Device Path\r
+ //\r
+ OrigDevicePathNode = DuplicateDevicePath (File);\r
+ \r
+ //\r
+ // 1. Check whether this device path support BlockIo protocol.\r
+ // Is so, this device path may be a GPT device path.\r
+ //\r
+ DevicePathNode = OrigDevicePathNode;\r
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle);\r
+ if (!EFI_ERROR (Status) && !mTrEEMeasureGptTableFlag) {\r
+ //\r
+ // Find the gpt partion on the given devicepath\r
+ //\r
+ DevicePathNode = OrigDevicePathNode;\r
+ ASSERT (DevicePathNode != NULL);\r
+ while (!IsDevicePathEnd (DevicePathNode)) {\r
+ //\r
+ // Find the Gpt partition\r
+ //\r
+ if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH &&\r
+ DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP) {\r
+ //\r
+ // Check whether it is a gpt partition or not\r
+ // \r
+ if (((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER && \r
+ ((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->SignatureType == SIGNATURE_TYPE_GUID) {\r
+\r
+ //\r
+ // Change the partition device path to its parent device path (disk) and get the handle.\r
+ //\r
+ DevicePathNode->Type = END_DEVICE_PATH_TYPE;\r
+ DevicePathNode->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;\r
+ DevicePathNode = OrigDevicePathNode;\r
+ Status = gBS->LocateDevicePath (\r
+ &gEfiDiskIoProtocolGuid,\r
+ &DevicePathNode,\r
+ &Handle\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Measure GPT disk.\r
+ //\r
+ Status = TrEEMeasureGptTable (TreeProtocol, Handle);\r
+ DEBUG ((EFI_D_ERROR, "DxeTpm2MeasureBootHandler - TrEEMeasureGptTable - %r\n", Status));\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // GPT disk check done.\r
+ //\r
+ mTrEEMeasureGptTableFlag = TRUE;\r
+ }\r
+ }\r
+ FreePool (OrigDevicePathNode);\r
+ OrigDevicePathNode = DuplicateDevicePath (File);\r
+ ASSERT (OrigDevicePathNode != NULL);\r
+ break;\r
+ }\r
+ }\r
+ DevicePathNode = NextDevicePathNode (DevicePathNode);\r
+ }\r
+ }\r
+ \r
+ //\r
+ // 2. Measure PE image.\r
+ //\r
+ ApplicationRequired = FALSE;\r
+\r
+ //\r
+ // Check whether this device path support FVB protocol.\r
+ //\r
+ DevicePathNode = OrigDevicePathNode;\r
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &DevicePathNode, &Handle);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Don't check FV image, and directly return EFI_SUCCESS.\r
+ // It can be extended to the specific FV authentication according to the different requirement.\r
+ //\r
+ if (IsDevicePathEnd (DevicePathNode)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // The PE image from unmeasured Firmware volume need be measured\r
+ // The PE image from measured Firmware volume will be mearsured according to policy below.\r
+ // If it is driver, do not measure\r
+ // If it is application, still measure.\r
+ //\r
+ ApplicationRequired = TRUE;\r
+\r
+ if (mTrEECacheMeasuredHandle != Handle && mTrEEMeasuredHobData != NULL) {\r
+ //\r
+ // Search for Root FV of this PE image\r
+ //\r
+ TempHandle = Handle;\r
+ do {\r
+ Status = gBS->HandleProtocol(\r
+ TempHandle, \r
+ &gEfiFirmwareVolumeBlockProtocolGuid,\r
+ (VOID**)&FvbProtocol\r
+ );\r
+ TempHandle = FvbProtocol->ParentHandle;\r
+ } while (!EFI_ERROR(Status) && FvbProtocol->ParentHandle != NULL);\r
+\r
+ //\r
+ // Search in measured FV Hob\r
+ //\r
+ Status = FvbProtocol->GetPhysicalAddress(FvbProtocol, &FvAddress);\r
+ if (EFI_ERROR(Status)){\r
+ return Status;\r
+ }\r
+\r
+ ApplicationRequired = FALSE;\r
+\r
+ for (Index = 0; Index < mTrEEMeasuredHobData->Num; Index++) {\r
+ if(mTrEEMeasuredHobData->MeasuredFvBuf[Index].BlobBase == FvAddress) {\r
+ //\r
+ // Cache measured FV for next measurement\r
+ //\r
+ mTrEECacheMeasuredHandle = Handle;\r
+ ApplicationRequired = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // File is not found.\r
+ //\r
+ if (FileBuffer == NULL) {\r
+ Status = EFI_SECURITY_VIOLATION;\r
+ goto Finish;\r
+ }\r
+\r
+ mTrEEImageSize = FileSize;\r
+ mTrEEFileBuffer = FileBuffer;\r
+\r
+ //\r
+ // Measure PE Image\r
+ //\r
+ DevicePathNode = OrigDevicePathNode;\r
+ ZeroMem (&ImageContext, sizeof (ImageContext));\r
+ ImageContext.Handle = (VOID *) FileBuffer;\r
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeTpm2MeasureBootLibImageRead;\r
+\r
+ //\r
+ // Get information about the image being loaded\r
+ //\r
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // The information can't be got from the invalid PeImage\r
+ //\r
+ goto Finish;\r
+ }\r
+ \r
+ //\r
+ // Measure only application if Application flag is set\r
+ // Measure drivers and applications if Application flag is not set\r
+ //\r
+ if ((!ApplicationRequired) || \r
+ (ApplicationRequired && ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) { \r
+ //\r
+ // Print the image path to be measured.\r
+ // \r
+ DEBUG_CODE_BEGIN ();\r
+ CHAR16 *ToText;\r
+ ToText = ConvertDevicePathToText (\r
+ DevicePathNode,\r
+ FALSE,\r
+ TRUE\r
+ );\r
+ if (ToText != NULL) {\r
+ DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText));\r
+ FreePool (ToText);\r
+ }\r
+ DEBUG_CODE_END ();\r
+\r
+ //\r
+ // Measure PE image into TPM log.\r
+ //\r
+ Status = TrEEMeasurePeImage (\r
+ TreeProtocol,\r
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FileBuffer, \r
+ FileSize, \r
+ (UINTN) ImageContext.ImageAddress, \r
+ ImageContext.ImageType, \r
+ DevicePathNode\r
+ );\r
+ DEBUG ((EFI_D_ERROR, "DxeTpm2MeasureBootHandler - TrEEMeasurePeImage - %r\n", Status));\r
+ }\r
+\r
+ //\r
+ // Done, free the allocated resource.\r
+ //\r
+Finish:\r
+ if (OrigDevicePathNode != NULL) {\r
+ FreePool (OrigDevicePathNode);\r
+ }\r
+\r
+ DEBUG ((EFI_D_ERROR, "DxeTpm2MeasureBootHandler - %r\n", Status));\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Register the security handler to provide TPM measure boot service.\r
+\r
+ @param ImageHandle ImageHandle of the loaded driver.\r
+ @param SystemTable Pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS Register successfully.\r
+ @retval EFI_OUT_OF_RESOURCES No enough memory to register this handler.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeTpm2MeasureBootLibConstructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_HOB_GUID_TYPE *GuidHob;\r
+\r
+ GuidHob = NULL;\r
+\r
+ GuidHob = GetFirstGuidHob (&gMeasuredFvHobGuid);\r
+\r
+ if (GuidHob != NULL) {\r
+ mTrEEMeasuredHobData = GET_GUID_HOB_DATA (GuidHob);\r
+ }\r
+\r
+ return RegisterSecurity2Handler (\r
+ DxeTpm2MeasureBootHandler,\r
+ EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED\r
+ );\r
+}\r