public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Min Xu" <min.m.xu@intel.com>
To: devel@edk2.groups.io
Cc: Min Xu <min.m.xu@intel.com>, Jiewen Yao <jiewen.yao@intel.com>,
	Jian J Wang <jian.j.wang@intel.com>
Subject: [PATCH 2/2] SecurityPkg: Add DxeTdMeasureBootLib for TD measure boot
Date: Tue, 14 Sep 2021 09:57:20 +0800	[thread overview]
Message-ID: <52fb81451dcd25c3a51edb6306cb76890169b87d.1631583583.git.min.m.xu@intel.com> (raw)
In-Reply-To: <cover.1631583583.git.min.m.xu@intel.com>

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 <jiewen.yao@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 .../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.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/TdProtocol.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include <Guid/MeasuredFvHob.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/SecurityManagementLib.h>
+#include <Library/HobLib.h>
+
+//
+// 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.<BR>
+# 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.<BR>
+//
+// 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


      parent reply	other threads:[~2021-09-14  1:57 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-09-14  1:57 [PATCH 0/2] Introduce TdProtocol into EDK2 Min Xu
2021-09-14  1:57 ` [PATCH 1/2] MdePkg: Introduce TdProtocol for TD-Guest firmware Min Xu
2021-09-14  2:05   ` Yao, Jiewen
2021-09-15  5:49   ` 回复: [edk2-devel] " gaoliming
2021-09-15  6:04     ` Min Xu
2021-09-24 23:01     ` Yao, Jiewen
2021-09-26  0:53       ` 回复: " gaoliming
2021-09-26  1:00         ` Yao, Jiewen
2021-09-14  1:57 ` Min Xu [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=52fb81451dcd25c3a51edb6306cb76890169b87d.1631583583.git.min.m.xu@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox