/** @file\r
The library instance provides security service of TPM 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
+ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content\r
+ read is within the image buffer.\r
+\r
+ TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its\r
+ data structure within this image buffer before use.\r
+\r
+ TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse\r
+ partition data carefully.\r
+\r
Copyright (c) 2009 - 2012, 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
#include <PiDxe.h>\r
\r
#include <Protocol/TcgService.h>\r
-#include <Protocol/FirmwareVolume2.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/TrustedFvHob.h>\r
\r
#include <Library/BaseLib.h>\r
#include <Library/DebugLib.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
UINTN mMeasureGptCount = 0;\r
VOID *mFileBuffer;\r
UINTN mImageSize;\r
+//\r
+// Measured FV handle cache\r
+//\r
+EFI_HANDLE mCacheMeasuredHandle = NULL;\r
+UINT32 *mGuidHobData = 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
/**\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 TcgProtocol Pointer to the located TCG protocol instance.\r
@param GptHandle Handle that GPT partition was installed.\r
\r
if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mZeroGuid)) {\r
NumberOfPartition++; \r
}\r
- PartitionEntry++;\r
+ PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);\r
}\r
\r
//\r
- // Parepare Data for Measurement\r
+ // Prepare Data for Measurement\r
// \r
EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) \r
+ NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);\r
- TcgEvent = (TCG_PCR_EVENT *) AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT));\r
+ TcgEvent = (TCG_PCR_EVENT *) AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT_HDR));\r
if (TcgEvent == NULL) {\r
FreePool (PrimaryHeader);\r
FreePool (EntryPtr);\r
for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {\r
if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mZeroGuid)) {\r
CopyMem (\r
- (UINT8 *)&GptData->Partitions + NumberOfPartition * sizeof (EFI_PARTITION_ENTRY),\r
+ (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry,\r
(UINT8 *)PartitionEntry,\r
- sizeof (EFI_PARTITION_ENTRY)\r
+ PrimaryHeader->SizeOfPartitionEntry\r
);\r
NumberOfPartition++;\r
}\r
- PartitionEntry++;\r
+ PartitionEntry =(EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);\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] TcgProtocol Pointer to the located TCG protocol instance.\r
@param[in] ImageAddress Start address of image buffer.\r
@param[in] ImageSize Image size\r
// Measuring PE/COFF Image Header;\r
// But CheckSum field and SECURITY data directory (certificate) are excluded\r
//\r
- Magic = Hdr.Pe32->OptionalHeader.Magic;\r
+ if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value \r
+ // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the \r
+ // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
+ // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
+ //\r
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+ } else {\r
+ //\r
+ // Get the magic value from the PE/COFF Optional Header\r
+ //\r
+ Magic = Hdr.Pe32->OptionalHeader.Magic;\r
+ }\r
\r
//\r
// 3. Calculate the distance from the base of the image header to the image checksum address.\r
might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is \r
returned.\r
\r
- @param[in, out] AuthenticationStatus This is the authentication status returned\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 File did authenticate, and the\r
- platform policy dictates that the DXE Core may use File.\r
- @retval EFI_INVALID_PARAMETER File is NULL.\r
- @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and\r
- the platform policy dictates that File should be placed\r
- in the untrusted state. A file may be promoted from\r
- the untrusted to the trusted state at a future time\r
- with a call to the Trust() DXE Service.\r
- @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and\r
- the platform policy dictates that File should not be\r
- used for any purpose.\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
DxeTpmMeasureBootHandler (\r
- IN OUT UINT32 AuthenticationStatus,\r
+ IN UINT32 AuthenticationStatus,\r
IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
- IN VOID *FileBuffer OPTIONAL,\r
- IN UINTN FileSize OPTIONAL\r
+ IN VOID *FileBuffer,\r
+ IN UINTN FileSize,\r
+ IN BOOLEAN BootPolicy\r
)\r
{\r
- EFI_TCG_PROTOCOL *TcgProtocol;\r
- EFI_STATUS Status;\r
- TCG_EFI_BOOT_SERVICE_CAPABILITY ProtocolCapability;\r
- UINT32 TCGFeatureFlags;\r
- EFI_PHYSICAL_ADDRESS EventLogLocation;\r
- EFI_PHYSICAL_ADDRESS EventLogLastEntry;\r
- EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
- EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode;\r
- EFI_HANDLE Handle;\r
- BOOLEAN ApplicationRequired;\r
- PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
-\r
- if (File == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
+ EFI_TCG_PROTOCOL *TcgProtocol;\r
+ EFI_STATUS Status;\r
+ TCG_EFI_BOOT_SERVICE_CAPABILITY ProtocolCapability;\r
+ UINT32 TCGFeatureFlags;\r
+ EFI_PHYSICAL_ADDRESS EventLogLocation;\r
+ EFI_PHYSICAL_ADDRESS EventLogLastEntry;\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
+ EFI_PLATFORM_FIRMWARE_BLOB *TrustedFvBuf;\r
+ UINT32 Index;\r
\r
Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol);\r
if (EFI_ERROR (Status)) {\r
// Copy File Device Path\r
//\r
OrigDevicePathNode = DuplicateDevicePath (File);\r
- ASSERT (OrigDevicePathNode != NULL);\r
\r
//\r
// 1. Check whether this device path support BlockIo protocol.\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
ApplicationRequired = FALSE;\r
\r
//\r
- // Check whether this device path support FV2 protocol.\r
+ // Check whether this device path support FVB protocol.\r
//\r
DevicePathNode = OrigDevicePathNode;\r
- Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePathNode, &Handle);\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
return EFI_SUCCESS;\r
}\r
//\r
- // The image from Firmware image will not be mearsured.\r
- // Current policy doesn't measure PeImage from Firmware if it is driver\r
- // If the got PeImage is application, it will be still be measured.\r
+ // The PE image from untrusted Firmware volume need be measured\r
+ // The PE image from trusted 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 (mCacheMeasuredHandle != Handle && mGuidHobData != 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
+ TrustedFvBuf = (EFI_PLATFORM_FIRMWARE_BLOB *)(mGuidHobData + 1);\r
+ ApplicationRequired = FALSE;\r
+\r
+ for (Index = 0; Index < *mGuidHobData; Index++) {\r
+ if(TrustedFvBuf[Index].BlobBase == FvAddress) {\r
+ //\r
+ // Cache measured FV for next measurement\r
+ //\r
+ mCacheMeasuredHandle = Handle;\r
+ ApplicationRequired = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ }\r
}\r
- \r
+\r
//\r
// File is not found.\r
//\r
// Done, free the allocated resource.\r
//\r
Finish:\r
- FreePool (OrigDevicePathNode);\r
+ if (OrigDevicePathNode != NULL) {\r
+ FreePool (OrigDevicePathNode);\r
+ }\r
\r
return Status;\r
}\r
IN EFI_SYSTEM_TABLE *SystemTable\r
)\r
{\r
- return RegisterSecurityHandler (\r
+ EFI_HOB_GUID_TYPE *GuidHob;\r
+\r
+ GuidHob = NULL;\r
+\r
+ GuidHob = GetFirstGuidHob (&gTrustedFvHobGuid);\r
+\r
+ if (GuidHob != NULL) {\r
+ mGuidHobData = GET_GUID_HOB_DATA (GuidHob);\r
+ }\r
+\r
+ return RegisterSecurity2Handler (\r
DxeTpmMeasureBootHandler,\r
EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED\r
);\r