From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by mx.groups.io with SMTP id smtpd.web09.4269.1631584662538995448 for ; Mon, 13 Sep 2021 18:57:45 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 134.134.136.100, mailfrom: min.m.xu@intel.com) X-IronPort-AV: E=McAfee;i="6200,9189,10106"; a="285538720" X-IronPort-AV: E=Sophos;i="5.85,291,1624345200"; d="scan'208";a="285538720" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Sep 2021 18:57:44 -0700 X-IronPort-AV: E=Sophos;i="5.85,291,1624345200"; d="scan'208";a="552035360" Received: from mxu9-mobl1.ccr.corp.intel.com ([10.249.169.243]) by fmsmga002-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Sep 2021 18:57:42 -0700 From: "Min Xu" To: devel@edk2.groups.io Cc: Min Xu , Jiewen Yao , Jian J Wang Subject: [PATCH 2/2] SecurityPkg: Add DxeTdMeasureBootLib for TD measure boot Date: Tue, 14 Sep 2021 09:57:20 +0800 Message-Id: <52fb81451dcd25c3a51edb6306cb76890169b87d.1631583583.git.min.m.xu@intel.com> X-Mailer: git-send-email 2.29.2.windows.2 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3625 The library instance provides security service of TD measure boot. DxeTdMeasureBootLibImageRead() function will make sure the PE/COFF image content read is within the image buffer. TdMeasurePeImage() function will accept untrusted PE/COFF image and validate its data structure within this image buffer before use. TdMeasureGptTable() function will receive untrusted GPT partition table, and parse partition data carefully. Cc: Jiewen Yao Cc: Jian J Wang Signed-off-by: Min Xu --- .../DxeTdMeasureBootLib/DxeTdMeasureBootLib.c | 688 ++++++++++++++++++ .../DxeTdMeasureBootLib.inf | 61 ++ .../DxeTdMeasureBootLib.uni | 21 + SecurityPkg/SecurityPkg.dsc | 5 + 4 files changed, 775 insertions(+) create mode 100644 SecurityPkg/Library/DxeTdMeasureBootLib/DxeTdMeasureBootLib.c create mode 100644 SecurityPkg/Library/DxeTdMeasureBootLib/DxeTdMeasureBootLib.inf create mode 100644 SecurityPkg/Library/DxeTdMeasureBootLib/DxeTdMeasureBootLib.uni diff --git a/SecurityPkg/Library/DxeTdMeasureBootLib/DxeTdMeasureBootLib.c b/SecurityPkg/Library/DxeTdMeasureBootLib/DxeTdMeasureBootLib.c new file mode 100644 index 000000000000..797925fb6888 --- /dev/null +++ b/SecurityPkg/Library/DxeTdMeasureBootLib/DxeTdMeasureBootLib.c @@ -0,0 +1,688 @@ +/** @file + The library instance provides security service of TD measure boot. + + Caution: This file requires additional review when modified. + This library will have external input - PE/COFF image and GPT partition. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + + DxeTdMeasureBootLibImageRead() function will make sure the PE/COFF image content + read is within the image buffer. + + TdMeasurePeImage() function will accept untrusted PE/COFF image and validate its + data structure within this image buffer before use. + + TdMeasureGptTable() function will receive untrusted GPT partition table, and parse + partition data carefully. + + Copyright (c) 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Flag to check GPT partition. It only need be measured once. +// +BOOLEAN mTdMeasureGptTableFlag = FALSE; +UINTN mTdMeasureGptCount = 0; +VOID *mTdFileBuffer; +UINTN mTdImageSize; +// +// Measured FV handle cache +// +EFI_HANDLE mTdCacheMeasuredHandle = NULL; +MEASURED_HOB_DATA *mTdMeasuredHobData = NULL; + +/** + Reads contents of a PE/COFF image in memory buffer. + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will make sure the PE/COFF image content + read is within the image buffer. + + @param FileHandle Pointer to the file handle to read the PE/COFF image. + @param FileOffset Offset into the PE/COFF image to begin the read operation. + @param ReadSize On input, the size in bytes of the requested read operation. + On output, the number of bytes actually read. + @param Buffer Output buffer that contains the data read from the PE/COFF image. + + @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size +**/ +EFI_STATUS +EFIAPI +DxeTdMeasureBootLibImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +{ + UINTN EndPosition; + + if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (MAX_ADDRESS - FileOffset < *ReadSize) { + return EFI_INVALID_PARAMETER; + } + + EndPosition = FileOffset + *ReadSize; + if (EndPosition > mTdImageSize) { + *ReadSize = (UINT32)(mTdImageSize - FileOffset); + } + + if (FileOffset >= mTdImageSize) { + *ReadSize = 0; + } + + CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize); + + return EFI_SUCCESS; +} + +/** + Measure GPT table data into TD Event log. + + Caution: This function may receive untrusted input. + The GPT partition table is external input, so this function should parse partition data carefully. + + @param TdProtocol Pointer to the located TD protocol instance. + @param GptHandle Handle that GPT partition was installed. + + @retval EFI_SUCCESS Successfully measure GPT table. + @retval EFI_UNSUPPORTED Not support GPT table on the given handle. + @retval EFI_DEVICE_ERROR Can't get GPT table because device error. + @retval EFI_OUT_OF_RESOURCES No enough resource to measure GPT table. + @retval other error value +**/ +EFI_STATUS +EFIAPI +TdMeasureGptTable ( + IN EFI_TD_PROTOCOL *TdProtocol, + IN EFI_HANDLE GptHandle + ) +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_DISK_IO_PROTOCOL *DiskIo; + EFI_PARTITION_TABLE_HEADER *PrimaryHeader; + EFI_PARTITION_ENTRY *PartitionEntry; + UINT8 *EntryPtr; + UINTN NumberOfPartition; + UINT32 Index; + EFI_TD_EVENT *TdEvent; + EFI_GPT_DATA *GptData; + UINT32 EventSize; + + if (mTdMeasureGptCount > 0) { + return EFI_SUCCESS; + } + + Status = gBS->HandleProtocol (GptHandle, &gEfiBlockIoProtocolGuid, (VOID**)&BlockIo); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + Status = gBS->HandleProtocol (GptHandle, &gEfiDiskIoProtocolGuid, (VOID**)&DiskIo); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + // + // Read the EFI Partition Table Header + // + PrimaryHeader = (EFI_PARTITION_TABLE_HEADER *) AllocatePool (BlockIo->Media->BlockSize); + if (PrimaryHeader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + 1 * BlockIo->Media->BlockSize, + BlockIo->Media->BlockSize, + (UINT8 *)PrimaryHeader + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n")); + FreePool (PrimaryHeader); + return EFI_DEVICE_ERROR; + } + // + // Read the partition entry. + // + EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry); + if (EntryPtr == NULL) { + FreePool (PrimaryHeader); + return EFI_OUT_OF_RESOURCES; + } + Status = DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), + PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry, + EntryPtr + ); + if (EFI_ERROR (Status)) { + FreePool (PrimaryHeader); + FreePool (EntryPtr); + return EFI_DEVICE_ERROR; + } + + // + // Count the valid partition + // + PartitionEntry = (EFI_PARTITION_ENTRY *)EntryPtr; + NumberOfPartition = 0; + for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) { + if (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) { + NumberOfPartition++; + } + PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry); + } + + // + // Prepare Data for Measurement + // + EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry); + TdEvent = (EFI_TD_EVENT *) AllocateZeroPool (EventSize + sizeof (EFI_TD_EVENT) - sizeof(TdEvent->Event)); + if (TdEvent == NULL) { + FreePool (PrimaryHeader); + FreePool (EntryPtr); + return EFI_OUT_OF_RESOURCES; + } + + TdEvent->Size = EventSize + sizeof (EFI_TD_EVENT) - sizeof(TdEvent->Event); + TdEvent->Header.HeaderSize = sizeof(EFI_TD_EVENT_HEADER); + TdEvent->Header.HeaderVersion = EFI_TD_EVENT_HEADER_VERSION; + TdEvent->Header.MrIndex = 1; + TdEvent->Header.EventType = EV_EFI_GPT_EVENT; + GptData = (EFI_GPT_DATA *) TdEvent->Event; + + // + // Copy the EFI_PARTITION_TABLE_HEADER and NumberOfPartition + // + CopyMem ((UINT8 *)GptData, (UINT8*)PrimaryHeader, sizeof (EFI_PARTITION_TABLE_HEADER)); + GptData->NumberOfPartitions = NumberOfPartition; + // + // Copy the valid partition entry + // + PartitionEntry = (EFI_PARTITION_ENTRY*)EntryPtr; + NumberOfPartition = 0; + for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) { + if (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) { + CopyMem ( + (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry, + (UINT8 *)PartitionEntry, + PrimaryHeader->SizeOfPartitionEntry + ); + NumberOfPartition++; + } + PartitionEntry =(EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry); + } + + // + // Measure the GPT data + // + Status = TdProtocol->HashLogExtendEvent ( + TdProtocol, + 0, + (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) GptData, + (UINT64) EventSize, + TdEvent + ); + if (!EFI_ERROR (Status)) { + mTdMeasureGptCount++; + } + + FreePool (PrimaryHeader); + FreePool (EntryPtr); + FreePool (TdEvent); + + return Status; +} + +/** + Measure PE image into TD log based on the authenticode image hashing in + PE/COFF Specification 8.0 Appendix A. + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will validate its data structure + within this image buffer before use. + + @param[in] TdProtocol Pointer to the located TD protocol instance. + @param[in] ImageAddress Start address of image buffer. + @param[in] ImageSize Image size + @param[in] LinkTimeBase Address that the image is loaded into memory. + @param[in] ImageType Image subsystem type. + @param[in] FilePath File path is corresponding to the input image. + + @retval EFI_SUCCESS Successfully measure image. + @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. + @retval EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format. + @retval other error value + +**/ +EFI_STATUS +EFIAPI +TdMeasurePeImage ( + IN EFI_TD_PROTOCOL *TdProtocol, + IN EFI_PHYSICAL_ADDRESS ImageAddress, + IN UINTN ImageSize, + IN UINTN LinkTimeBase, + IN UINT16 ImageType, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath + ) +{ + EFI_STATUS Status; + EFI_TD_EVENT *TdEvent; + EFI_IMAGE_LOAD_EVENT *ImageLoad; + UINT32 FilePathSize; + UINT32 EventSize; + + Status = EFI_UNSUPPORTED; + ImageLoad = NULL; + FilePathSize = (UINT32) GetDevicePathSize (FilePath); + + // + // Determine destination PCR by BootPolicy + // + EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize; + TdEvent = AllocateZeroPool (EventSize + sizeof (EFI_TD_EVENT) - sizeof(TdEvent->Event)); + if (TdEvent == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TdEvent->Size = EventSize + sizeof (EFI_TD_EVENT) - sizeof(TdEvent->Event); + TdEvent->Header.HeaderSize = sizeof(EFI_TD_EVENT_HEADER); + TdEvent->Header.HeaderVersion = EFI_TD_EVENT_HEADER_VERSION; + ImageLoad = (EFI_IMAGE_LOAD_EVENT *) TdEvent->Event; + + switch (ImageType) { + case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION: + TdEvent->Header.EventType = EV_EFI_BOOT_SERVICES_APPLICATION; + TdEvent->Header.MrIndex = 1; + break; + case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: + TdEvent->Header.EventType = EV_EFI_BOOT_SERVICES_DRIVER; + TdEvent->Header.MrIndex = 1; + break; + case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: + TdEvent->Header.EventType = EV_EFI_RUNTIME_SERVICES_DRIVER; + TdEvent->Header.MrIndex = 1; + break; + default: + DEBUG (( + DEBUG_ERROR, + "TdMeasurePeImage: Unknown subsystem type %d", + ImageType + )); + goto Finish; + } + + ImageLoad->ImageLocationInMemory = ImageAddress; + ImageLoad->ImageLengthInMemory = ImageSize; + ImageLoad->ImageLinkTimeAddress = LinkTimeBase; + ImageLoad->LengthOfDevicePath = FilePathSize; + if ((FilePath != NULL) && (FilePathSize != 0)) { + CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize); + } + + // + // Log the PE data + // + Status = TdProtocol->HashLogExtendEvent ( + TdProtocol, + PE_COFF_IMAGE, + ImageAddress, + ImageSize, + TdEvent + ); + if (Status == EFI_VOLUME_FULL) { + // + // Volume full here means the image is hashed and its result is extended to PCR. + // But the event log can't be saved since log area is full. + // Just return EFI_SUCCESS in order not to block the image load. + // + Status = EFI_SUCCESS; + } + +Finish: + FreePool (TdEvent); + + return Status; +} + +/** + The security handler is used to abstract platform-specific policy + from the DXE core response to an attempt to use a file that returns a + given status for the authentication check from the section extraction protocol. + + The possible responses in a given SAP implementation may include locking + flash upon failure to authenticate, attestation logging for all signed drivers, + and other exception operations. The File parameter allows for possible logging + within the SAP of the driver. + + If the file specified by File with an authentication status specified by + AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned. + + If the file specified by File with an authentication status specified by + AuthenticationStatus is not safe for the DXE Core to use under any circumstances, + then EFI_ACCESS_DENIED is returned. + + If the file specified by File with an authentication status specified by + AuthenticationStatus is not safe for the DXE Core to use right now, but it + might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is + returned. + + If check image specified by FileBuffer and File is NULL meanwhile, return EFI_ACCESS_DENIED. + + @param[in] AuthenticationStatus This is the authentication status returned + from the securitymeasurement services for the + input file. + @param[in] File This is a pointer to the device path of the file that is + being dispatched. This will optionally be used for logging. + @param[in] FileBuffer File buffer matches the input file device path. + @param[in] FileSize Size of File buffer matches the input file device path. + @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service. + + @retval EFI_SUCCESS The file specified by DevicePath and non-NULL + FileBuffer did authenticate, and the platform policy dictates + that the DXE Foundation may use the file. + @retval other error value +**/ +EFI_STATUS +EFIAPI +DxeTdMeasureBootHandler ( + IN UINT32 AuthenticationStatus, + IN CONST EFI_DEVICE_PATH_PROTOCOL *File, OPTIONAL + IN VOID *FileBuffer, + IN UINTN FileSize, + IN BOOLEAN BootPolicy + ) +{ + EFI_TD_PROTOCOL *TdProtocol; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; + EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode; + EFI_HANDLE Handle; + EFI_HANDLE TempHandle; + BOOLEAN ApplicationRequired; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; + EFI_PHYSICAL_ADDRESS FvAddress; + UINT32 Index; + + Status = gBS->LocateProtocol (&gEfiTdProtocolGuid, NULL, (VOID **) &TdProtocol); + if (EFI_ERROR (Status)) { + // + // TD protocol is not installed. So, TD is not present. + // Don't do any measurement, and directly return EFI_SUCCESS. + // + DEBUG ((DEBUG_VERBOSE, "DxeTdMeasureBootHandler - TD - %r\n", Status)); + return EFI_SUCCESS; + } + + // + // Copy File Device Path + // + OrigDevicePathNode = DuplicateDevicePath (File); + + // + // 1. Check whether this device path support BlockIo protocol. + // Is so, this device path may be a GPT device path. + // + DevicePathNode = OrigDevicePathNode; + Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle); + if (!EFI_ERROR (Status) && !mTdMeasureGptTableFlag) { + // + // Find the gpt partition on the given devicepath + // + DevicePathNode = OrigDevicePathNode; + ASSERT (DevicePathNode != NULL); + while (!IsDevicePathEnd (DevicePathNode)) { + // + // Find the Gpt partition + // + if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH && + DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP) { + // + // Check whether it is a gpt partition or not + // + if (((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER && + ((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->SignatureType == SIGNATURE_TYPE_GUID) { + + // + // Change the partition device path to its parent device path (disk) and get the handle. + // + DevicePathNode->Type = END_DEVICE_PATH_TYPE; + DevicePathNode->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + DevicePathNode = OrigDevicePathNode; + Status = gBS->LocateDevicePath ( + &gEfiDiskIoProtocolGuid, + &DevicePathNode, + &Handle + ); + if (!EFI_ERROR (Status)) { + // + // Measure GPT disk. + // + Status = TdMeasureGptTable (TdProtocol, Handle); + DEBUG ((DEBUG_INFO, "DxeTdMeasureBootHandler - TdMeasureGptTable - %r\n", Status)); + if (!EFI_ERROR (Status)) { + // + // GPT disk check done. + // + mTdMeasureGptTableFlag = TRUE; + } + } + FreePool (OrigDevicePathNode); + OrigDevicePathNode = DuplicateDevicePath (File); + ASSERT (OrigDevicePathNode != NULL); + break; + } + } + DevicePathNode = NextDevicePathNode (DevicePathNode); + } + } + + // + // 2. Measure PE image. + // + ApplicationRequired = FALSE; + + // + // Check whether this device path support FVB protocol. + // + DevicePathNode = OrigDevicePathNode; + Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &DevicePathNode, &Handle); + if (!EFI_ERROR (Status)) { + // + // Don't check FV image, and directly return EFI_SUCCESS. + // It can be extended to the specific FV authentication according to the different requirement. + // + if (IsDevicePathEnd (DevicePathNode)) { + return EFI_SUCCESS; + } + // + // The PE image from unmeasured Firmware volume need be measured + // The PE image from measured Firmware volume will be measured according to policy below. + // If it is driver, do not measure + // If it is application, still measure. + // + ApplicationRequired = TRUE; + + if (mTdCacheMeasuredHandle != Handle && mTdMeasuredHobData != NULL) { + // + // Search for Root FV of this PE image + // + TempHandle = Handle; + do { + Status = gBS->HandleProtocol( + TempHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID**)&FvbProtocol + ); + TempHandle = FvbProtocol->ParentHandle; + } while (!EFI_ERROR(Status) && FvbProtocol->ParentHandle != NULL); + + // + // Search in measured FV Hob + // + Status = FvbProtocol->GetPhysicalAddress(FvbProtocol, &FvAddress); + if (EFI_ERROR(Status)){ + return Status; + } + + ApplicationRequired = FALSE; + + for (Index = 0; Index < mTdMeasuredHobData->Num; Index++) { + if(mTdMeasuredHobData->MeasuredFvBuf[Index].BlobBase == FvAddress) { + // + // Cache measured FV for next measurement + // + mTdCacheMeasuredHandle = Handle; + ApplicationRequired = TRUE; + break; + } + } + } + } + + // + // File is not found. + // + if (FileBuffer == NULL) { + Status = EFI_SECURITY_VIOLATION; + goto Finish; + } + + mTdImageSize = FileSize; + mTdFileBuffer = FileBuffer; + + // + // Measure PE Image + // + DevicePathNode = OrigDevicePathNode; + ZeroMem (&ImageContext, sizeof (ImageContext)); + ImageContext.Handle = (VOID *) FileBuffer; + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeTdMeasureBootLibImageRead; + + // + // Get information about the image being loaded + // + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + // + // Check for invalid parameters. + // + if (File == NULL) { + Status = EFI_ACCESS_DENIED; + } + + // + // The information can't be got from the invalid PeImage + // + goto Finish; + } + + // + // Measure only application if Application flag is set + // Measure drivers and applications if Application flag is not set + // + if ((!ApplicationRequired) || + (ApplicationRequired && ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) { + // + // Print the image path to be measured. + // + DEBUG_CODE_BEGIN (); + CHAR16 *ToText; + ToText = ConvertDevicePathToText ( + DevicePathNode, + FALSE, + TRUE + ); + if (ToText != NULL) { + DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText)); + FreePool (ToText); + } + DEBUG_CODE_END (); + + // + // Measure PE image into TD log. + // + Status = TdMeasurePeImage ( + TdProtocol, + (EFI_PHYSICAL_ADDRESS) (UINTN) FileBuffer, + FileSize, + (UINTN) ImageContext.ImageAddress, + ImageContext.ImageType, + DevicePathNode + ); + DEBUG ((DEBUG_INFO, "DxeTdMeasureBootHandler - TdMeasurePeImage - %r\n", Status)); + } + + // + // Done, free the allocated resource. + // +Finish: + if (OrigDevicePathNode != NULL) { + FreePool (OrigDevicePathNode); + } + + DEBUG ((DEBUG_INFO, "DxeTdMeasureBootHandler - %r\n", Status)); + + return Status; +} + +/** + Register the security handler to provide TD measure boot service. + + @param ImageHandle ImageHandle of the loaded driver. + @param SystemTable Pointer to the EFI System Table. + + @retval EFI_SUCCESS Register successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to register this handler. +**/ +EFI_STATUS +EFIAPI +DxeTdMeasureBootLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + + GuidHob = NULL; + + GuidHob = GetFirstGuidHob (&gMeasuredFvHobGuid); + + if (GuidHob != NULL) { + mTdMeasuredHobData = GET_GUID_HOB_DATA (GuidHob); + } + + return RegisterSecurity2Handler ( + DxeTdMeasureBootHandler, + EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED + ); +} diff --git a/SecurityPkg/Library/DxeTdMeasureBootLib/DxeTdMeasureBootLib.inf b/SecurityPkg/Library/DxeTdMeasureBootLib/DxeTdMeasureBootLib.inf new file mode 100644 index 000000000000..defe2857749d --- /dev/null +++ b/SecurityPkg/Library/DxeTdMeasureBootLib/DxeTdMeasureBootLib.inf @@ -0,0 +1,61 @@ +## @file +# Provides security service for TD measured boot +# +# This library instance hooks LoadImage() API to measure every image that +# is not measured in PEI phase. And, it will also measure GPT partition. +# +# Caution: This module requires additional review when modified. +# This library will have external input - PE/COFF image and GPT partition. +# This external input must be validated carefully to avoid security issues such +# as buffer overflow or integer overflow. +# +# Copyright (c) 2021, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeTdMeasureBootLib + MODULE_UNI_FILE = DxeTdMeasureBootLib.uni + FILE_GUID = 5ECEEF3F-05ED-4BC8-B027-A6AD182BE2F3 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = DxeTdMeasureBootLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = X64 +# + +[Sources] + DxeTdMeasureBootLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + MemoryAllocationLib + DevicePathLib + UefiBootServicesTableLib + BaseCryptLib + PeCoffLib + BaseLib + SecurityManagementLib + HobLib + +[Guids] + gMeasuredFvHobGuid ## SOMETIMES_CONSUMES ## HOB + +[Protocols] + gEfiTdProtocolGuid ## SOMETIMES_CONSUMES + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES diff --git a/SecurityPkg/Library/DxeTdMeasureBootLib/DxeTdMeasureBootLib.uni b/SecurityPkg/Library/DxeTdMeasureBootLib/DxeTdMeasureBootLib.uni new file mode 100644 index 000000000000..65769e91127c --- /dev/null +++ b/SecurityPkg/Library/DxeTdMeasureBootLib/DxeTdMeasureBootLib.uni @@ -0,0 +1,21 @@ +// /** @file +// Provides security service for TD measured boot +// +// This library instance hooks LoadImage() API to measure every image that +// is not measured in PEI phase. And, it will also measure GPT partition. +// +// Caution: This module requires additional review when modified. +// This library will have external input - PE/COFF image and GPT partition. +// This external input must be validated carefully to avoid security issues such +// as buffer overflow or integer overflow. +// +// Copyright (c) 2021, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Provides security service for TD measured boot" + +#string STR_MODULE_DESCRIPTION #language en-US "This library instance hooks LoadImage() API to measure every image that is not measured in PEI phase. And, it will also measure GPT partition. Caution: This module requires additional review when modified. This library will have external input - PE/COFF image and GPT partition. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow." diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc index f1f678c492b3..8d8b6a38b1e4 100644 --- a/SecurityPkg/SecurityPkg.dsc +++ b/SecurityPkg/SecurityPkg.dsc @@ -218,6 +218,11 @@ SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.inf SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.inf + # + # TD + # + SecurityPkg/Library/DxeTdMeasureBootLib/DxeTdMeasureBootLib.inf + SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.inf -- 2.29.2.windows.2