From 4b0a622635f8ec18892b55c53ea69a0d22279af6 Mon Sep 17 00:00:00 2001 From: Min Xu Date: Mon, 16 May 2022 15:42:19 +0800 Subject: [PATCH] OvmfPkg/IntelTdx: Measure Td HobList and Configuration FV RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3853 TdHobList and Configuration FV are external data provided by Host VMM. These are not trusted in Td guest. So they should be validated , measured and extended to Td RTMR registers. In the meantime 2 EFI_CC_EVENT_HOB are created. These 2 GUIDed HOBs carry the hash value of TdHobList and Configuration FV. In DXE phase EFI_CC_EVENT can be created based on these 2 GUIDed HOBs. Cc: Ard Biesheuvel Cc: Jiewen Yao Cc: Jordan Justen Cc: Brijesh Singh Cc: Erdem Aktas Cc: James Bottomley Cc: Jiewen Yao Cc: Tom Lendacky Cc: Gerd Hoffmann Reviewed-by: Jiewen Yao Signed-off-by: Min Xu --- OvmfPkg/IntelTdx/IntelTdxX64.dsc | 4 + OvmfPkg/Library/PeilessStartupLib/IntelTdx.c | 163 ++++++++++++++++++ .../PeilessStartupLib/PeilessStartup.c | 31 ++++ .../PeilessStartupInternal.h | 17 ++ .../PeilessStartupLib/PeilessStartupLib.inf | 8 +- 5 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 OvmfPkg/Library/PeilessStartupLib/IntelTdx.c diff --git a/OvmfPkg/IntelTdx/IntelTdxX64.dsc b/OvmfPkg/IntelTdx/IntelTdxX64.dsc index dd8d446f4a..c51da39874 100644 --- a/OvmfPkg/IntelTdx/IntelTdxX64.dsc +++ b/OvmfPkg/IntelTdx/IntelTdxX64.dsc @@ -527,6 +527,10 @@ OvmfPkg/IntelTdx/Sec/SecMain.inf { NULL|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf + SecMeasurementLib|OvmfPkg/Library/SecMeasurementLib/SecMeasurementLibTdx.inf + BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SecCryptLib.inf + HashLib|SecurityPkg/Library/HashLibTdx/HashLibTdx.inf + NULL|SecurityPkg/Library/HashInstanceLibSha384/HashInstanceLibSha384.inf } # diff --git a/OvmfPkg/Library/PeilessStartupLib/IntelTdx.c b/OvmfPkg/Library/PeilessStartupLib/IntelTdx.c new file mode 100644 index 0000000000..d240d3b771 --- /dev/null +++ b/OvmfPkg/Library/PeilessStartupLib/IntelTdx.c @@ -0,0 +1,163 @@ +/** @file + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include "PeilessStartupInternal.h" + +/** + Check padding data all bit should be 1. + + @param[in] Buffer - A pointer to buffer header + @param[in] BufferSize - Buffer size + + @retval TRUE - The padding data is valid. + @retval TRUE - The padding data is invalid. + +**/ +BOOLEAN +CheckPaddingData ( + IN UINT8 *Buffer, + IN UINT32 BufferSize + ) +{ + UINT32 index; + + for (index = 0; index < BufferSize; index++) { + if (Buffer[index] != 0xFF) { + return FALSE; + } + } + + return TRUE; +} + +/** + Check the integrity of CFV data. + + @param[in] TdxCfvBase - A pointer to CFV header + @param[in] TdxCfvSize - CFV data size + + @retval TRUE - The CFV data is valid. + @retval FALSE - The CFV data is invalid. + +**/ +BOOLEAN +EFIAPI +TdxValidateCfv ( + IN UINT8 *TdxCfvBase, + IN UINT32 TdxCfvSize + ) +{ + UINT16 Checksum; + UINTN VariableBase; + UINT32 VariableOffset; + UINT32 VariableOffsetBeforeAlign; + EFI_FIRMWARE_VOLUME_HEADER *CfvFvHeader; + VARIABLE_STORE_HEADER *CfvVariableStoreHeader; + AUTHENTICATED_VARIABLE_HEADER *VariableHeader; + + static EFI_GUID FvHdrGUID = EFI_SYSTEM_NV_DATA_FV_GUID; + static EFI_GUID VarStoreHdrGUID = EFI_AUTHENTICATED_VARIABLE_GUID; + + VariableOffset = 0; + + if (TdxCfvBase == NULL) { + DEBUG ((DEBUG_ERROR, "TDX CFV: CFV pointer is NULL\n")); + return FALSE; + } + + // + // Verify the header zerovetor, filesystemguid, + // revision, signature, attributes, fvlength, checksum + // HeaderLength cannot be an odd number + // + CfvFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)TdxCfvBase; + + if ((!IsZeroBuffer (CfvFvHeader->ZeroVector, 16)) || + (!CompareGuid (&FvHdrGUID, &CfvFvHeader->FileSystemGuid)) || + (CfvFvHeader->Signature != EFI_FVH_SIGNATURE) || + (CfvFvHeader->Attributes != 0x4feff) || + (CfvFvHeader->Revision != EFI_FVH_REVISION) || + (CfvFvHeader->FvLength != TdxCfvSize) + ) + { + DEBUG ((DEBUG_ERROR, "TDX CFV: Basic FV headers were invalid\n")); + return FALSE; + } + + // + // Verify the header checksum + // + Checksum = CalculateSum16 ((VOID *)CfvFvHeader, CfvFvHeader->HeaderLength); + + if (Checksum != 0) { + DEBUG ((DEBUG_ERROR, "TDX CFV: FV checksum was invalid\n")); + return FALSE; + } + + // + // Verify the header signature, size, format, state + // + CfvVariableStoreHeader = (VARIABLE_STORE_HEADER *)(TdxCfvBase + CfvFvHeader->HeaderLength); + if ((!CompareGuid (&VarStoreHdrGUID, &CfvVariableStoreHeader->Signature)) || + (CfvVariableStoreHeader->Format != VARIABLE_STORE_FORMATTED) || + (CfvVariableStoreHeader->State != VARIABLE_STORE_HEALTHY) || + (CfvVariableStoreHeader->Size > (CfvFvHeader->FvLength - CfvFvHeader->HeaderLength)) || + (CfvVariableStoreHeader->Size < sizeof (VARIABLE_STORE_HEADER)) + ) + { + DEBUG ((DEBUG_ERROR, "TDX CFV: Variable Store header was invalid\n")); + return FALSE; + } + + // + // Verify the header startId, state + // Verify data to the end + // + VariableBase = (UINTN)TdxCfvBase + CfvFvHeader->HeaderLength + sizeof (VARIABLE_STORE_HEADER); + while (VariableOffset < (CfvVariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER))) { + VariableHeader = (AUTHENTICATED_VARIABLE_HEADER *)(VariableBase + VariableOffset); + if (VariableHeader->StartId != VARIABLE_DATA) { + if (!CheckPaddingData ((UINT8 *)VariableHeader, CfvVariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - VariableOffset)) { + DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n")); + return FALSE; + } + + VariableOffset = CfvVariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER); + } else { + if (!((VariableHeader->State == VAR_IN_DELETED_TRANSITION) || + (VariableHeader->State == VAR_DELETED) || + (VariableHeader->State == VAR_HEADER_VALID_ONLY) || + (VariableHeader->State == VAR_ADDED))) + { + DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n")); + return FALSE; + } + + VariableOffset += sizeof (AUTHENTICATED_VARIABLE_HEADER) + VariableHeader->NameSize + VariableHeader->DataSize; + // Verify VariableOffset should be less than or equal CfvVariableStoreHeader->Size - sizeof(VARIABLE_STORE_HEADER) + if (VariableOffset > (CfvVariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER))) { + DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n")); + return FALSE; + } + + VariableOffsetBeforeAlign = VariableOffset; + // 4 byte align + VariableOffset = (VariableOffset + 3) & (UINTN)(~3); + + if (!CheckPaddingData ((UINT8 *)(VariableBase + VariableOffsetBeforeAlign), VariableOffset - VariableOffsetBeforeAlign)) { + DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n")); + return FALSE; + } + } + } + + return TRUE; +} diff --git a/OvmfPkg/Library/PeilessStartupLib/PeilessStartup.c b/OvmfPkg/Library/PeilessStartupLib/PeilessStartup.c index 126eb74048..54236b956c 100644 --- a/OvmfPkg/Library/PeilessStartupLib/PeilessStartup.c +++ b/OvmfPkg/Library/PeilessStartupLib/PeilessStartup.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "PeilessStartupInternal.h" #define GET_GPAW_INIT_STATE(INFO) ((UINT8) ((INFO) & 0x3f)) @@ -133,11 +134,13 @@ PeilessStartup ( UINT32 DxeCodeSize; TD_RETURN_DATA TdReturnData; VOID *VmmHobList; + UINT8 *CfvBase; Status = EFI_SUCCESS; BootFv = NULL; VmmHobList = NULL; SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Context; + CfvBase = (UINT8 *)(UINTN)FixedPcdGet32 (PcdCfvBase); ZeroMem (&PlatformInfoHob, sizeof (PlatformInfoHob)); @@ -167,6 +170,34 @@ PeilessStartup ( DEBUG ((DEBUG_INFO, "HobList: %p\n", GetHobList ())); + if (TdIsEnabled ()) { + // + // Measure HobList + // + Status = MeasureHobList (VmmHobList); + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + CpuDeadLoop (); + } + + // + // Validate Tdx CFV + // + if (!TdxValidateCfv (CfvBase, FixedPcdGet32 (PcdCfvRawDataSize))) { + ASSERT (FALSE); + CpuDeadLoop (); + } + + // + // Measure Tdx CFV + // + Status = MeasureFvImage ((EFI_PHYSICAL_ADDRESS)(UINTN)CfvBase, FixedPcdGet32 (PcdCfvRawDataSize), 1); + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + CpuDeadLoop (); + } + } + // // Initialize the Platform // diff --git a/OvmfPkg/Library/PeilessStartupLib/PeilessStartupInternal.h b/OvmfPkg/Library/PeilessStartupLib/PeilessStartupInternal.h index 23e9e0be53..dd79b8a06b 100644 --- a/OvmfPkg/Library/PeilessStartupLib/PeilessStartupInternal.h +++ b/OvmfPkg/Library/PeilessStartupLib/PeilessStartupInternal.h @@ -52,4 +52,21 @@ EFIAPI ConstructSecHobList ( ); +/** + Check the integrity of CFV data. + + @param[in] TdxCfvBase - A pointer to CFV header + @param[in] TdxCfvSize - CFV data size + + @retval TRUE - The CFV data is valid. + @retval FALSE - The CFV data is invalid. + +**/ +BOOLEAN +EFIAPI +TdxValidateCfv ( + IN UINT8 *TdxCfvBase, + IN UINT32 TdxCfvSize + ); + #endif diff --git a/OvmfPkg/Library/PeilessStartupLib/PeilessStartupLib.inf b/OvmfPkg/Library/PeilessStartupLib/PeilessStartupLib.inf index 8791984586..c5d291f02b 100644 --- a/OvmfPkg/Library/PeilessStartupLib/PeilessStartupLib.inf +++ b/OvmfPkg/Library/PeilessStartupLib/PeilessStartupLib.inf @@ -29,8 +29,7 @@ PeilessStartup.c Hob.c DxeLoad.c - -[Sources.X64] + IntelTdx.c X64/VirtualMemory.c [Packages] @@ -39,6 +38,8 @@ UefiCpuPkg/UefiCpuPkg.dec OvmfPkg/OvmfPkg.dec EmbeddedPkg/EmbeddedPkg.dec + CryptoPkg/CryptoPkg.dec + SecurityPkg/SecurityPkg.dec [LibraryClasses] BaseLib @@ -56,6 +57,8 @@ PrePiLib QemuFwCfgLib PlatformInitLib + HashLib + SecMeasurementLib [Guids] gEfiHobMemoryAllocModuleGuid @@ -63,6 +66,7 @@ gUefiOvmfPkgPlatformInfoGuid gEfiMemoryTypeInformationGuid gPcdDataBaseHobGuid + gCcEventEntryHobGuid [Pcd] gUefiOvmfPkgTokenSpaceGuid.PcdCfvBase -- 2.39.2