From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by mx.groups.io with SMTP id smtpd.web09.9926.1639394389608982858 for ; Mon, 13 Dec 2021 03:19:50 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@intel.com header.s=intel header.b=X6uqxbRP; spf=pass (domain: intel.com, ip: 192.55.52.43, mailfrom: longlong.yang@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1639394389; x=1670930389; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=eNJ/NGs0wAf5dL5sB5uKb53lKAN3VWiMaDt+7HwiS6A=; b=X6uqxbRPfOVmOtuh7kCBT4Ookzi+I6Id8lc/D898AfDmFt3Ld26qVrHT xnUErrPYFf02k/0CjvxsSNKfJgu1wvn0DYq4kjDbPG84Q3IX4osn6RbaZ gikTJXBKIW95L4vzg6DuVeXUFd9ynjpbumenjhiXqb3vbk9BnTDr2vKgE Bc79m8tT6Ulvpb/b/ZGPljGk6315YO1ISukIrHI12wq30iRKDtthZUqIm drR5lKw4bSlZcMvyKknR6lMnMcW8RZI/oaGdEIg5H9GP9dN0zId05I/iT byLDxCbOO5Av6MeotgdtNgfbFWQe9QO7d3N3334zUBAkaT2JmVFS35Qnz A==; X-IronPort-AV: E=McAfee;i="6200,9189,10196"; a="324981710" X-IronPort-AV: E=Sophos;i="5.88,202,1635231600"; d="scan'208";a="324981710" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Dec 2021 03:19:47 -0800 X-IronPort-AV: E=Sophos;i="5.88,202,1635231600"; d="scan'208";a="464592437" Received: from longlon1-mobl2.ccr.corp.intel.com ([10.238.1.97]) by orsmga006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Dec 2021 03:19:44 -0800 From: longlong.yang@intel.com To: devel@edk2.groups.io Cc: Longlong Yang , Eric Dong , Ray Ni , Rahul Kumar , Jiewen Yao , Min M Xu , Qi Zhang Subject: [PATCH V3 1/1] UefiCpuPkg: Extend measurement of microcode patches to TPM Date: Mon, 13 Dec 2021 19:19:09 +0800 Message-Id: X-Mailer: git-send-email 2.31.1.windows.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3683 TCG specification says BIOS should extend measurement of microcode to TPM. However, reference BIOS is not doing this. BIOS shall extend measurement of microcode to TPM. Cc: Eric Dong Cc: Ray Ni Cc: Rahul Kumar Cc: Jiewen Yao Cc: Min M Xu Cc: Qi Zhang Signed-off-by: Longlong Yang --- .../MicrocodeMeasurementDxe.c | 280 ++++++++++++++++++ .../MicrocodeMeasurementDxe.inf | 56 ++++ .../MicrocodeMeasurementDxe.uni | 15 + .../MicrocodeMeasurementDxeExtra.uni | 12 + UefiCpuPkg/UefiCpuPkg.dsc | 1 + 5 files changed, 364 insertions(+) create mode 100644 UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxe.c create mode 100644 UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxe.inf create mode 100644 UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxe.uni create mode 100644 UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxeExtra.uni diff --git a/UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxe.c b/UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxe.c new file mode 100644 index 000000000000..6f7dcda789f9 --- /dev/null +++ b/UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxe.c @@ -0,0 +1,280 @@ +/** @file + This driver measures microcode patches to TPM. + + This driver consumes gEdkiiMicrocodePatchHobGuid, packs all unique microcode patch found in gEdkiiMicrocodePatchHobGuid to a binary blob, and measures the binary blob to TPM. + + 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 + +#define CPU_MICROCODE_MEASUREMENT_DESCRIPTION "Microcode Measurement" +#define CPU_MICROCODE_MEASUREMENT_EVENT_LOG_DESCRIPTION_LEN sizeof (CPU_MICROCODE_MEASUREMENT_DESCRIPTION) + +#pragma pack(1) +typedef struct { + UINT8 Description[CPU_MICROCODE_MEASUREMENT_EVENT_LOG_DESCRIPTION_LEN]; + UINTN NumberOfMicrocodePatchesMeasured; + UINTN SizeOfMicrocodePatchesMeasured; +} CPU_MICROCODE_MEASUREMENT_EVENT_LOG; +#pragma pack() + +/** + Helping function. + + The function is called by QuickSort to compare the order of offsets of + two microcode patches in RAM relative to their base address. Elements + will be in ascending order. + + @param[in] Offset1 The pointer to the offset of first microcode patch. + @param[in] Offset2 The pointer to the offset of second microcode patch. + + @retval 1 The offset of first microcode patch is bigger than that of the second. + @retval -1 The offset of first microcode patch is smaller than that of the second. + @retval 0 The offset of first microcode patch equals to that of the second. +**/ +INTN +EFIAPI +MicrocodePatchOffsetCompareFunction ( + IN CONST VOID *Offset1, + IN CONST VOID *Offset2 + ) +{ + if (*(UINT64 *)(Offset1) > *(UINT64 *)(Offset2)) { + return 1; + } else if (*(UINT64 *)(Offset1) < *(UINT64 *)(Offset2)) { + return -1; + } else { + return 0; + } +} + +/** + This function remove duplicate and invalid offsets in Offsets. + + This function remove duplicate and invalid offsets in Offsets. Invalid offset means MAX_UINT64 in Offsets. + + @param[in] Offsets Microcode offset list. + @param[in, out] Count On call as the count of raw microcode offset list; On return as count of the clean microcode offset list. + **/ +VOID +RemoveDuplicateAndInvalidOffset ( + IN UINT64 *Offsets, + IN OUT UINTN *Count + ) +{ + UINTN Index; + UINTN NewCount; + UINT64 LastOffset; + UINT64 QuickSortBuffer; + + // + // The order matters when packing all applied microcode patches to a single binary blob. + // Therefore it is a must to do sorting before packing. + // NOTE: We assumed that the order of address of every microcode patch in RAM is the same + // with the order of those in the Microcode Firmware Volume in FLASH. If any future updates + // made this assumption untenable, then needs a new solution to measure microcode patches. + // + QuickSort ( + Offsets, + *Count, + sizeof (UINT64), + MicrocodePatchOffsetCompareFunction, + (VOID *)&QuickSortBuffer + ); + + NewCount = 0; + LastOffset = MAX_UINT64; + for (Index = 0; Index < *Count; Index++) { + // + // When MAX_UINT64 element is met, all following elements are MAX_UINT64. + // + if (Offsets[Index] == MAX_UINT64) { + break; + } + + // + // Remove duplicated offsets + // + if (Offsets[Index] != LastOffset) { + LastOffset = Offsets[Index]; + Offsets[NewCount] = Offsets[Index]; + NewCount++; + } + } + + *Count = NewCount; +} + +/** + Callback function. + + Called after signaling of the Ready to Boot Event. Measure microcode patches binary blob with event type EV_CPU_MICROCODE to PCR[1] in TPM. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +MeasureMicrocodePatches ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + UINT32 PCRIndex; + UINT32 EventType; + CPU_MICROCODE_MEASUREMENT_EVENT_LOG EventLog; + UINT32 EventLogSize; + EFI_HOB_GUID_TYPE *GuidHob; + EDKII_MICROCODE_PATCH_HOB *MicrocodePatchHob; + UINT64 *Offsets; + UINTN Count; + UINTN Index; + UINTN TotalMicrocodeSize; + UINT8 *MicrocodePatchesBlob; + + PCRIndex = 1; + EventType = EV_CPU_MICROCODE; + AsciiStrCpyS ( + (CHAR8 *)(EventLog.Description), + CPU_MICROCODE_MEASUREMENT_EVENT_LOG_DESCRIPTION_LEN, + CPU_MICROCODE_MEASUREMENT_DESCRIPTION + ); + EventLog.NumberOfMicrocodePatchesMeasured = 0; + EventLog.SizeOfMicrocodePatchesMeasured = 0; + EventLogSize = sizeof (CPU_MICROCODE_MEASUREMENT_EVENT_LOG); + Offsets = NULL; + TotalMicrocodeSize = 0; + Count = 0; + + GuidHob = GetFirstGuidHob (&gEdkiiMicrocodePatchHobGuid); + if (NULL == GuidHob) { + DEBUG ((DEBUG_ERROR, "ERROR: GetFirstGuidHob (&gEdkiiMicrocodePatchHobGuid) failed.\n")); + return; + } + + MicrocodePatchHob = GET_GUID_HOB_DATA (GuidHob); + DEBUG ( + (DEBUG_INFO, + "INFO: Got MicrocodePatchHob with microcode patches starting address:0x%x, microcode patches region size:0x%x, processor count:0x%x\n", + MicrocodePatchHob->MicrocodePatchAddress, MicrocodePatchHob->MicrocodePatchRegionSize, + MicrocodePatchHob->ProcessorCount) + ); + + Offsets = AllocateCopyPool ( + MicrocodePatchHob->ProcessorCount * sizeof (UINT64), + MicrocodePatchHob->ProcessorSpecificPatchOffset + ); + Count = MicrocodePatchHob->ProcessorCount; + + RemoveDuplicateAndInvalidOffset (Offsets, &Count); + + if (0 == Count) { + DEBUG ((DEBUG_INFO, "INFO: No microcode patch is ever applied, skip the measurement of microcode!\n")); + FreePool (Offsets); + return; + } + + for (Index = 0; Index < Count; Index++) { + TotalMicrocodeSize += + GetMicrocodeLength ((CPU_MICROCODE_HEADER *)((UINTN)(MicrocodePatchHob->MicrocodePatchAddress + Offsets[Index]))); + } + + EventLog.NumberOfMicrocodePatchesMeasured = Count; + EventLog.SizeOfMicrocodePatchesMeasured = TotalMicrocodeSize; + + MicrocodePatchesBlob = AllocateZeroPool (TotalMicrocodeSize); + if (NULL == MicrocodePatchesBlob) { + DEBUG ((DEBUG_ERROR, "ERROR: AllocateZeroPool to MicrocodePatchesBlob failed!\n")); + FreePool (Offsets); + return; + } + + TotalMicrocodeSize = 0; + for (Index = 0; Index < Count; Index++) { + CopyMem ( + (VOID *)(MicrocodePatchesBlob + TotalMicrocodeSize), + (VOID *)((UINTN)(MicrocodePatchHob->MicrocodePatchAddress + Offsets[Index])), + (UINTN)(GetMicrocodeLength ( + (CPU_MICROCODE_HEADER *)((UINTN)(MicrocodePatchHob->MicrocodePatchAddress + + Offsets[Index])) + )) + ); + TotalMicrocodeSize += + GetMicrocodeLength ((CPU_MICROCODE_HEADER *)((UINTN)(MicrocodePatchHob->MicrocodePatchAddress + Offsets[Index]))); + } + + Status = TpmMeasureAndLogData ( + PCRIndex, // PCRIndex + EventType, // EventType + &EventLog, // EventLog + EventLogSize, // LogLen + MicrocodePatchesBlob, // HashData + TotalMicrocodeSize // HashDataLen + ); + if (!EFI_ERROR (Status)) { + gBS->CloseEvent (Event); + DEBUG ( + (DEBUG_INFO, + "INFO: %d Microcode patches are successfully extended to TPM! The total size measured to TPM is 0x%x\n", + Count, + TotalMicrocodeSize) + ); + } else { + DEBUG ((DEBUG_ERROR, "ERROR: TpmMeasureAndLogData failed with status %a!\n", Status)); + } + + FreePool (Offsets); + FreePool (MicrocodePatchesBlob); + return; +} + +/** + + Driver to produce microcode measurement. + + Driver to produce microcode measurement. Which install a callback function on ready to boot event. + + @param ImageHandle Module's image handle + @param SystemTable Pointer of EFI_SYSTEM_TABLE + + @return EFI_SUCCESS This function always complete successfully. + +**/ +EFI_STATUS +EFIAPI +MicrocodeMeasurementDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_EVENT Event; + + // + // Measure Microcode patches + // + EfiCreateEventReadyToBootEx ( + TPL_CALLBACK, + MeasureMicrocodePatches, + NULL, + &Event + ); + + return EFI_SUCCESS; +} diff --git a/UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxe.inf b/UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxe.inf new file mode 100644 index 000000000000..649fb9403fd2 --- /dev/null +++ b/UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxe.inf @@ -0,0 +1,56 @@ +## @file +# This driver measures microcode patches to TPM. +# +# This driver consumes gEdkiiMicrocodePatchHobGuid, packs all unique +# microcode patch found in gEdkiiMicrocodePatchHobGuid to a binary blob, +# and measures the binary blob to TPM. +# +# Copyright (c) 2021, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MicrocodeMeasurementDxe + MODULE_UNI_FILE = MicrocodeMeasurementDxe.uni + FILE_GUID = 0A32A803-ACDF-4C89-8293-91011548CD91 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = MicrocodeMeasurementDriverEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + MicrocodeMeasurementDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + MemoryAllocationLib + BaseMemoryLib + BaseLib + UefiLib + UefiDriverEntryPoint + DebugLib + HobLib + MicrocodeLib + TpmMeasurementLib + +[Guids] + gEdkiiMicrocodePatchHobGuid ## CONSUMES ## HOB + +[UserExtensions.TianoCore."ExtraFiles"] + MicrocodeMeasurementDxeExtra.uni + +[Depex] + TRUE diff --git a/UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxe.uni b/UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxe.uni new file mode 100644 index 000000000000..5a21e955fbbf --- /dev/null +++ b/UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxe.uni @@ -0,0 +1,15 @@ +// /** @file +// This driver measures microcode patches to TPM. +// +// This driver consumes gEdkiiMicrocodePatchHobGuid, packs all uniquemicrocode patch found in gEdkiiMicrocodePatchHobGuid to a binary blob, and measures the binary blob to TPM. +// +// Copyright (c) 2021, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "This driver measures Microcode Patches to TPM." + +#string STR_MODULE_DESCRIPTION #language en-US "This driver consumes gEdkiiMicrocodePatchHobGuid, packs all microcode patch found in gEdkiiMicrocodePatchHobGuid to a binary blob, and measure the binary blob to TPM." diff --git a/UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxeExtra.uni b/UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxeExtra.uni new file mode 100644 index 000000000000..6990cee8c6fd --- /dev/null +++ b/UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxeExtra.uni @@ -0,0 +1,12 @@ +// /** @file +// MicrocodeMeasurementDxe Localized Strings and Content +// +// Copyright (c) 2021, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"Microcode Patches Measurement DXE Driver" diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index 870b45284087..d1d61dd6a03b 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -119,6 +119,7 @@ UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.inf UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf + UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxe.inf [Components.IA32, Components.X64] UefiCpuPkg/CpuDxe/CpuDxe.inf -- 2.31.1.windows.1