| Message ID | 20241126022526.3389121-1-hongxu.jia@windriver.com |
|---|---|
| State | Accepted |
| Delegated to: | Steve Sakoman |
| Headers | show |
| Series | [kirkstone,V2,01/13] ovmf: Fix CVE-2022-36763 | expand |
I am getting build time errors with this patch:
ERROR: ovmf-edk2-stable202202-r0 do_patch: Applying patch
'CVE-2022-36763-0001.patch' on target directory
'/home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/git'
CmdError('quilt --quiltrc
/home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/recipe-sysroot-native/etc/quiltrc
push', 0, 'stdout: Applying patch CVE-2022-36763-0001.patch
patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
Hunk #1 FAILED at 20 (different line endings).
Hunk #2 FAILED at 44 (different line endings).
Hunk #3 FAILED at 144 (different line endings).
Hunk #4 FAILED at 195 (different line endings).
Hunk #5 FAILED at 223 (different line endings).
Hunk #6 FAILED at 248 (different line endings).
Hunk #7 FAILED at 310 (different line endings).
Hunk #8 FAILED at 326 (different line endings).
Hunk #9 FAILED at 443 (different line endings).
Hunk #10 FAILED at 515 (different line endings).
Hunk #11 FAILED at 646 (different line endings).
11 out of 11 hunks FAILED -- rejects in file
SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
Hunk #1 FAILED at 37 (different line endings).
Hunk #2 FAILED at 46 (different line endings).
Hunk #3 FAILED at 65 (different line endings).
3 out of 3 hunks FAILED -- rejects in file
SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c
patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h
patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c
patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf
patching file SecurityPkg/SecurityPkg.ci.yaml
Hunk #1 FAILED at 15 (different line endings).
1 out of 1 hunk FAILED -- rejects in file SecurityPkg/SecurityPkg.ci.yaml
Patch CVE-2022-36763-0001.patch does not apply (enforce with -f)
Please submit a V2 of this series with the line ending issues fixed.
Thanks!
Steve
On Mon, Nov 25, 2024 at 6:25 PM Hongxu Jia <hongxu.jia@windriver.com> wrote:
>
> From: Soumya Sambu <soumya.sambu@windriver.com>
>
> EDK2 is susceptible to a vulnerability in the Tcg2MeasureGptTable()
> function, allowing a user to trigger a heap buffer overflow via a local
> network. Successful exploitation of this vulnerability may result in a
> compromise of confidentiality, integrity, and/or availability.
>
> References:
> https://nvd.nist.gov/vuln/detail/CVE-2022-36763
>
> Upstream-patches:
> https://github.com/tianocore/edk2/commit/224446543206450ddb5830e6abd026d61d3c7f4b
> https://github.com/tianocore/edk2/commit/4776a1b39ee08fc45c70c1eab5a0195f325000d3
> https://github.com/tianocore/edk2/commit/1ddcb9fc6b4164e882687b031e8beacfcf7df29e
>
> Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
> ---
> .../ovmf/ovmf/CVE-2022-36763-0001.patch | 985 ++++++++++++++++++
> .../ovmf/ovmf/CVE-2022-36763-0002.patch | 889 ++++++++++++++++
> .../ovmf/ovmf/CVE-2022-36763-0003.patch | 55 +
> meta/recipes-core/ovmf/ovmf_git.bb | 3 +
> 4 files changed, 1932 insertions(+)
> create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch
> create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch
> create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch
>
> diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch
> new file mode 100644
> index 0000000000..93cefe7740
> --- /dev/null
> +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch
> @@ -0,0 +1,985 @@
> +From 224446543206450ddb5830e6abd026d61d3c7f4b Mon Sep 17 00:00:00 2001
> +From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com>
> +Date: Fri, 12 Jan 2024 02:16:01 +0800
> +Subject: [PATCH] SecurityPkg: DxeTpm2MeasureBootLib: SECURITY PATCH 4117 - CVE
> + 2022-36763
> +
> +This commit contains the patch files and tests for DxeTpm2MeasureBootLib
> +CVE 2022-36763.
> +
> +Cc: Jiewen Yao <jiewen.yao@intel.com>
> +
> +Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com>
> +
> +CVE: CVE-2022-36763
> +
> +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/224446543206450ddb5830e6abd026d61d3c7f4b]
> +
> +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
> +---
> + .../DxeTpm2MeasureBootLib.c | 69 ++--
> + .../DxeTpm2MeasureBootLib.inf | 4 +-
> + .../DxeTpm2MeasureBootLibSanitization.c | 275 ++++++++++++++++
> + .../DxeTpm2MeasureBootLibSanitization.h | 113 +++++++
> + .../DxeTpm2MeasureBootLibSanitizationTest.c | 303 ++++++++++++++++++
> + ...Tpm2MeasureBootLibSanitizationTestHost.inf | 28 ++
> + SecurityPkg/SecurityPkg.ci.yaml | 1 +
> + 7 files changed, 763 insertions(+), 30 deletions(-)
> + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c
> + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h
> + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c
> + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf
> +
> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
> +index 36a256a7af..0475103d6e 100644
> +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
> +@@ -20,6 +20,8 @@ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
> + (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> ++Copyright (c) Microsoft Corporation.<BR>
> ++SPDX-License-Identifier: BSD-2-Clause-Patent
> + **/
> +
> + #include <PiDxe.h>
> +@@ -44,6 +46,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> + #include <Library/HobLib.h>
> + #include <Protocol/CcMeasurement.h>
> +
> ++#include "DxeTpm2MeasureBootLibSanitization.h"
> ++
> + typedef struct {
> + EFI_TCG2_PROTOCOL *Tcg2Protocol;
> + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol;
> +@@ -144,10 +148,11 @@ Tcg2MeasureGptTable (
> + EFI_TCG2_EVENT *Tcg2Event;
> + EFI_CC_EVENT *CcEvent;
> + EFI_GPT_DATA *GptData;
> +- UINT32 EventSize;
> ++ UINT32 TcgEventSize;
> + EFI_TCG2_PROTOCOL *Tcg2Protocol;
> + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol;
> + EFI_CC_MR_INDEX MrIndex;
> ++ UINT32 AllocSize;
> +
> + if (mTcg2MeasureGptCount > 0) {
> + return EFI_SUCCESS;
> +@@ -195,25 +200,22 @@ Tcg2MeasureGptTable (
> + BlockIo->Media->BlockSize,
> + (UINT8 *)PrimaryHeader
> + );
> +- if (EFI_ERROR (Status)) {
> +- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n"));
> ++ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) {
> ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n"));
> + FreePool (PrimaryHeader);
> + return EFI_DEVICE_ERROR;
> + }
> +
> + //
> +- // PrimaryHeader->SizeOfPartitionEntry should not be zero
> ++ // Read the partition entry.
> + //
> +- if (PrimaryHeader->SizeOfPartitionEntry == 0) {
> +- DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry should not be zero!\n"));
> ++ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize);
> ++ if (EFI_ERROR (Status)) {
> + FreePool (PrimaryHeader);
> + return EFI_BAD_BUFFER_SIZE;
> + }
> +
> +- //
> +- // Read the partition entry.
> +- //
> +- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
> ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize);
> + if (EntryPtr == NULL) {
> + FreePool (PrimaryHeader);
> + return EFI_OUT_OF_RESOURCES;
> +@@ -223,7 +225,7 @@ Tcg2MeasureGptTable (
> + DiskIo,
> + BlockIo->Media->MediaId,
> + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
> +- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry,
> ++ AllocSize,
> + EntryPtr
> + );
> + if (EFI_ERROR (Status)) {
> +@@ -248,16 +250,21 @@ Tcg2MeasureGptTable (
> + //
> + // Prepare Data for Measurement (CcProtocol and Tcg2Protocol)
> + //
> +- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions)
> +- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);
> +- EventPtr = (UINT8 *)AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event));
> ++ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &TcgEventSize);
> ++ if (EFI_ERROR (Status)) {
> ++ FreePool (PrimaryHeader);
> ++ FreePool (EntryPtr);
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ EventPtr = (UINT8 *)AllocateZeroPool (TcgEventSize);
> + if (EventPtr == NULL) {
> + Status = EFI_OUT_OF_RESOURCES;
> + goto Exit;
> + }
> +
> + Tcg2Event = (EFI_TCG2_EVENT *)EventPtr;
> +- Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event);
> ++ Tcg2Event->Size = TcgEventSize;
> + Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER);
> + Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;
> + Tcg2Event->Header.PCRIndex = 5;
> +@@ -310,7 +317,7 @@ Tcg2MeasureGptTable (
> + CcProtocol,
> + 0,
> + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData,
> +- (UINT64)EventSize,
> ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event),
> + CcEvent
> + );
> + if (!EFI_ERROR (Status)) {
> +@@ -326,7 +333,7 @@ Tcg2MeasureGptTable (
> + Tcg2Protocol,
> + 0,
> + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData,
> +- (UINT64)EventSize,
> ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event),
> + Tcg2Event
> + );
> + if (!EFI_ERROR (Status)) {
> +@@ -443,11 +450,13 @@ Tcg2MeasurePeImage (
> + Tcg2Event->Header.PCRIndex = 2;
> + break;
> + default:
> +- DEBUG ((
> +- DEBUG_ERROR,
> +- "Tcg2MeasurePeImage: Unknown subsystem type %d",
> +- ImageType
> +- ));
> ++ DEBUG (
> ++ (
> ++ DEBUG_ERROR,
> ++ "Tcg2MeasurePeImage: Unknown subsystem type %d",
> ++ ImageType
> ++ )
> ++ );
> + goto Finish;
> + }
> +
> +@@ -515,7 +524,7 @@ Finish:
> +
> + @param MeasureBootProtocols Pointer to the located measure boot protocol instances.
> +
> +- @retval EFI_SUCCESS Sucessfully locate the measure boot protocol instances (at least one instance).
> ++ @retval EFI_SUCCESS Successfully locate the measure boot protocol instances (at least one instance).
> + @retval EFI_UNSUPPORTED Measure boot is not supported.
> + **/
> + EFI_STATUS
> +@@ -646,12 +655,14 @@ DxeTpm2MeasureBootHandler (
> + return EFI_SUCCESS;
> + }
> +
> +- DEBUG ((
> +- DEBUG_INFO,
> +- "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n",
> +- MeasureBootProtocols.Tcg2Protocol,
> +- MeasureBootProtocols.CcProtocol
> +- ));
> ++ DEBUG (
> ++ (
> ++ DEBUG_INFO,
> ++ "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n",
> ++ MeasureBootProtocols.Tcg2Protocol,
> ++ MeasureBootProtocols.CcProtocol
> ++ )
> ++ );
> +
> + //
> + // Copy File Device Path
> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
> +index 6dca79a20c..28995f438d 100644
> +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
> +@@ -37,6 +37,8 @@
> +
> + [Sources]
> + DxeTpm2MeasureBootLib.c
> ++ DxeTpm2MeasureBootLibSanitization.c
> ++ DxeTpm2MeasureBootLibSanitization.h
> +
> + [Packages]
> + MdePkg/MdePkg.dec
> +@@ -46,6 +48,7 @@
> +
> + [LibraryClasses]
> + BaseMemoryLib
> ++ SafeIntLib
> + DebugLib
> + MemoryAllocationLib
> + DevicePathLib
> +@@ -65,4 +68,3 @@
> + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES
> + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
> + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES
> +-
> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c
> +new file mode 100644
> +index 0000000000..e2309655d3
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c
> +@@ -0,0 +1,275 @@
> ++/** @file
> ++ The library instance provides security service of TPM2 measure boot and
> ++ Confidential Computing (CC) 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.
> ++
> ++ This file will pull out the validation logic from the following functions, in an
> ++ attempt to validate the untrusted input in the form of unit tests
> ++
> ++ These are those functions:
> ++
> ++ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content
> ++ read is within the image buffer.
> ++
> ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse
> ++ partition data carefully.
> ++
> ++ Copyright (c) Microsoft Corporation.<BR>
> ++ SPDX-License-Identifier: BSD-2-Clause-Patent
> ++**/
> ++#include <Uefi.h>
> ++#include <Uefi/UefiSpec.h>
> ++#include <Library/SafeIntLib.h>
> ++#include <Library/UefiLib.h>
> ++#include <Library/DebugLib.h>
> ++#include <Library/BaseLib.h>
> ++#include <IndustryStandard/UefiTcgPlatform.h>
> ++#include <Protocol/BlockIo.h>
> ++#include <Library/MemoryAllocationLib.h>
> ++
> ++#include "DxeTpm2MeasureBootLibSanitization.h"
> ++
> ++#define GPT_HEADER_REVISION_V1 0x00010000
> ++
> ++/**
> ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse
> ++ However this function will not attempt to verify the validity of the GPT partition
> ++ It will check the following:
> ++ - Signature
> ++ - Revision
> ++ - AlternateLBA
> ++ - FirstUsableLBA
> ++ - LastUsableLBA
> ++ - PartitionEntryLBA
> ++ - NumberOfPartitionEntries
> ++ - SizeOfPartitionEntry
> ++ - BlockIo
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[in] BlockIo
> ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure.
> ++
> ++ @retval EFI_SUCCESS
> ++ The EFI_PARTITION_TABLE_HEADER structure is valid.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ The EFI_PARTITION_TABLE_HEADER structure is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizeEfiPartitionTableHeader (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo
> ++ )
> ++{
> ++ //
> ++ // Verify that the input parameters are safe to use
> ++ //
> ++ if (PrimaryHeader == NULL) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n"));
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ //
> ++ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII)
> ++ //
> ++ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ //
> ++ // The version must be GPT_HEADER_REVISION_V1 (0x00010000)
> ++ //
> ++ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ //
> ++ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size
> ++ //
> ++ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ //
> ++ // The partition entries should all be before the first usable block
> ++ //
> ++ if (PrimaryHeader->FirstUsableLBA <= PrimaryHeader->PartitionEntryLBA) {
> ++ DEBUG ((DEBUG_ERROR, "GPT PartitionEntryLBA is not less than FirstUsableLBA!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ //
> ++ // Check that the PartitionEntryLBA greater than the Max LBA
> ++ // This will be used later for multiplication
> ++ //
> ++ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ //
> ++ // Check that the number of partition entries is greater than zero
> ++ //
> ++ if (PrimaryHeader->NumberOfPartitionEntries == 0) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ //
> ++ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory
> ++ //
> ++ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) {
> ++ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ //
> ++ // This check is to prevent overflow when calculating the allocation size for the partition entries
> ++ // This check will be used later for multiplication
> ++ //
> ++ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ return EFI_SUCCESS;
> ++}
> ++
> ++/**
> ++ This function will validate that the allocation size from the primary header is sane
> ++ It will check the following:
> ++ - AllocationSize does not overflow
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[out] AllocationSize
> ++ Pointer to the allocation size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The allocation size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ The allocation size is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizePrimaryHeaderAllocationSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ OUT UINT32 *AllocationSize
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++
> ++ if (PrimaryHeader == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ if (AllocationSize == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ //
> ++ // Replacing logic:
> ++ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry;
> ++ //
> ++ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n"));
> ++ return EFI_BAD_BUFFER_SIZE;
> ++ }
> ++
> ++ return EFI_SUCCESS;
> ++}
> ++
> ++/**
> ++ This function will validate that the Gpt Event Size calculated from the primary header is sane
> ++ It will check the following:
> ++ - EventSize does not overflow
> ++
> ++ Important: This function includes the entire length of the allocated space, including
> ++ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this
> ++ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event))
> ++ from the size of the buffer before hashing.
> ++
> ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++ @param[in] NumberOfPartition - Number of partitions.
> ++ @param[out] EventSize - Pointer to the event size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The event size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ Overflow would have occurred.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ One of the passed parameters was invalid.
> ++**/
> ++EFI_STATUS
> ++SanitizePrimaryHeaderGptEventSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN UINTN NumberOfPartition,
> ++ OUT UINT32 *EventSize
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++ UINT32 SafeNumberOfPartitions;
> ++
> ++ if (PrimaryHeader == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ if (EventSize == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ //
> ++ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32
> ++ //
> ++ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n"));
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ //
> ++ // Replacing logic:
> ++ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry);
> ++ //
> ++ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n"));
> ++ return EFI_BAD_BUFFER_SIZE;
> ++ }
> ++
> ++ //
> ++ // Replacing logic:
> ++ // *EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event);
> ++ //
> ++ Status = SafeUint32Add (
> ++ OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions),
> ++ *EventSize,
> ++ EventSize
> ++ );
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n"));
> ++ return EFI_BAD_BUFFER_SIZE;
> ++ }
> ++
> ++ return EFI_SUCCESS;
> ++}
> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h
> +new file mode 100644
> +index 0000000000..048b738987
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h
> +@@ -0,0 +1,113 @@
> ++/** @file
> ++ This file includes the function prototypes for the sanitization functions.
> ++
> ++ These are those functions:
> ++
> ++ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content
> ++ read is within the image buffer.
> ++
> ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse
> ++ partition data carefully.
> ++
> ++ Copyright (c) Microsoft Corporation.<BR>
> ++ SPDX-License-Identifier: BSD-2-Clause-Patent
> ++
> ++**/
> ++
> ++#ifndef DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_
> ++#define DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_
> ++
> ++#include <Uefi.h>
> ++#include <Uefi/UefiSpec.h>
> ++#include <Protocol/BlockIo.h>
> ++#include <IndustryStandard/UefiTcgPlatform.h>
> ++#include <Protocol/Tcg2Protocol.h>
> ++
> ++/**
> ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse
> ++ However this function will not attempt to verify the validity of the GPT partition
> ++ It will check the following:
> ++ - Signature
> ++ - Revision
> ++ - AlternateLBA
> ++ - FirstUsableLBA
> ++ - LastUsableLBA
> ++ - PartitionEntryLBA
> ++ - NumberOfPartitionEntries
> ++ - SizeOfPartitionEntry
> ++ - BlockIo
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[in] BlockIo
> ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure.
> ++
> ++ @retval EFI_SUCCESS
> ++ The EFI_PARTITION_TABLE_HEADER structure is valid.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ The EFI_PARTITION_TABLE_HEADER structure is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizeEfiPartitionTableHeader (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo
> ++ );
> ++
> ++/**
> ++ This function will validate that the allocation size from the primary header is sane
> ++ It will check the following:
> ++ - AllocationSize does not overflow
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[out] AllocationSize
> ++ Pointer to the allocation size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The allocation size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ The allocation size is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizePrimaryHeaderAllocationSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ OUT UINT32 *AllocationSize
> ++ );
> ++
> ++/**
> ++ This function will validate that the Gpt Event Size calculated from the primary header is sane
> ++ It will check the following:
> ++ - EventSize does not overflow
> ++
> ++ Important: This function includes the entire length of the allocated space, including
> ++ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this
> ++ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event))
> ++ from the size of the buffer before hashing.
> ++
> ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++ @param[in] NumberOfPartition - Number of partitions.
> ++ @param[out] EventSize - Pointer to the event size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The event size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ Overflow would have occurred.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ One of the passed parameters was invalid.
> ++**/
> ++EFI_STATUS
> ++SanitizePrimaryHeaderGptEventSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN UINTN NumberOfPartition,
> ++ OUT UINT32 *EventSize
> ++ );
> ++
> ++#endif // DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_
> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c
> +new file mode 100644
> +index 0000000000..3eb9763e3c
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c
> +@@ -0,0 +1,303 @@
> ++/** @file
> ++ This file includes the unit test cases for the DxeTpm2MeasureBootLibSanitizationTest.c.
> ++
> ++ Copyright (c) Microsoft Corporation.<BR>
> ++ SPDX-License-Identifier: BSD-2-Clause-Patent
> ++**/
> ++
> ++#include <Uefi.h>
> ++#include <Library/UefiLib.h>
> ++#include <Library/DebugLib.h>
> ++#include <Library/UnitTestLib.h>
> ++#include <Protocol/BlockIo.h>
> ++#include <Library/MemoryAllocationLib.h>
> ++#include <Library/BaseMemoryLib.h>
> ++#include <IndustryStandard/UefiTcgPlatform.h>
> ++#include <Protocol/Tcg2Protocol.h>
> ++
> ++#include "../DxeTpm2MeasureBootLibSanitization.h"
> ++
> ++#define UNIT_TEST_NAME "DxeTpm2MeasureBootLibSanitizationTest"
> ++#define UNIT_TEST_VERSION "1.0"
> ++
> ++#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000
> ++#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1
> ++#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128
> ++
> ++/**
> ++ This function tests the SanitizeEfiPartitionTableHeader function.
> ++ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER
> ++ structure will not cause undefined or unexpected behavior.
> ++
> ++ In general the TPM should still be able to measure the data, but
> ++ be the header should be sanitized to prevent any unexpected behavior.
> ++
> ++ @param[in] Context The unit test context.
> ++
> ++ @retval UNIT_TEST_PASSED The test passed.
> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
> ++**/
> ++UNIT_TEST_STATUS
> ++EFIAPI
> ++TestSanitizeEfiPartitionTableHeader (
> ++ IN UNIT_TEST_CONTEXT Context
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
> ++ EFI_BLOCK_IO_PROTOCOL BlockIo;
> ++ EFI_BLOCK_IO_MEDIA BlockMedia;
> ++
> ++ // Generate EFI_BLOCK_IO_MEDIA test data
> ++ BlockMedia.MediaId = 1;
> ++ BlockMedia.RemovableMedia = FALSE;
> ++ BlockMedia.MediaPresent = TRUE;
> ++ BlockMedia.LogicalPartition = FALSE;
> ++ BlockMedia.ReadOnly = FALSE;
> ++ BlockMedia.WriteCaching = FALSE;
> ++ BlockMedia.BlockSize = 512;
> ++ BlockMedia.IoAlign = 1;
> ++ BlockMedia.LastBlock = 0;
> ++
> ++ // Generate EFI_BLOCK_IO_PROTOCOL test data
> ++ BlockIo.Revision = 1;
> ++ BlockIo.Media = &BlockMedia;
> ++ BlockIo.Reset = NULL;
> ++ BlockIo.ReadBlocks = NULL;
> ++ BlockIo.WriteBlocks = NULL;
> ++ BlockIo.FlushBlocks = NULL;
> ++
> ++ // Geneate EFI_PARTITION_TABLE_HEADER test data
> ++ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID;
> ++ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION;
> ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER);
> ++ PrimaryHeader.MyLBA = 1;
> ++ PrimaryHeader.AlternateLBA = 2;
> ++ PrimaryHeader.FirstUsableLBA = 3;
> ++ PrimaryHeader.LastUsableLBA = 4;
> ++ PrimaryHeader.PartitionEntryLBA = 5;
> ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES;
> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid
> ++
> ++ // Calculate the CRC32 of the PrimaryHeader
> ++ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize);
> ++
> ++ // Test that a normal PrimaryHeader passes validation
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_NOT_EFI_ERROR (Status);
> ++
> ++ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR
> ++ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!""
> ++ PrimaryHeader.NumberOfPartitionEntries = 0;
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
> ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++
> ++ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR
> ++ // Should print "Invalid Partition Table Header Size!"
> ++ PrimaryHeader.Header.HeaderSize = 0;
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
> ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER);
> ++
> ++ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR
> ++ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!"
> ++ PrimaryHeader.SizeOfPartitionEntry = 1;
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
> ++
> ++ return UNIT_TEST_PASSED;
> ++}
> ++
> ++/**
> ++ This function tests the SanitizePrimaryHeaderAllocationSize function.
> ++ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER
> ++ structure will not cause an overflow when calculating the allocation size.
> ++
> ++ @param[in] Context The unit test context.
> ++
> ++ @retval UNIT_TEST_PASSED The test passed.
> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
> ++**/
> ++UNIT_TEST_STATUS
> ++EFIAPI
> ++TestSanitizePrimaryHeaderAllocationSize (
> ++ IN UNIT_TEST_CONTEXT Context
> ++ )
> ++{
> ++ UINT32 AllocationSize;
> ++
> ++ EFI_STATUS Status;
> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
> ++
> ++ // Test that a normal PrimaryHeader passes validation
> ++ PrimaryHeader.NumberOfPartitionEntries = 5;
> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_NOT_EFI_ERROR (Status);
> ++
> ++ // Test that the allocation size is correct compared to the existing logic
> ++ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry);
> ++
> ++ // Test that an overflow is detected
> ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32;
> ++ PrimaryHeader.SizeOfPartitionEntry = 5;
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ // Test the inverse
> ++ PrimaryHeader.NumberOfPartitionEntries = 5;
> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ // Test the worst case scenario
> ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32;
> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
> ++
> ++ return UNIT_TEST_PASSED;
> ++}
> ++
> ++/**
> ++ This function tests the SanitizePrimaryHeaderGptEventSize function.
> ++ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure
> ++ will not cause an overflow when calculating the event size.
> ++
> ++ @param[in] Context The unit test context.
> ++
> ++ @retval UNIT_TEST_PASSED The test passed.
> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
> ++**/
> ++UNIT_TEST_STATUS
> ++EFIAPI
> ++TestSanitizePrimaryHeaderGptEventSize (
> ++ IN UNIT_TEST_CONTEXT Context
> ++ )
> ++{
> ++ UINT32 EventSize;
> ++ UINT32 ExistingLogicEventSize;
> ++ EFI_STATUS Status;
> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
> ++ UINTN NumberOfPartition;
> ++ EFI_GPT_DATA *GptData;
> ++ EFI_TCG2_EVENT *Tcg2Event;
> ++
> ++ Tcg2Event = NULL;
> ++ GptData = NULL;
> ++
> ++ // Test that a normal PrimaryHeader passes validation
> ++ PrimaryHeader.NumberOfPartitionEntries = 5;
> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++
> ++ // set the number of partitions
> ++ NumberOfPartition = 13;
> ++
> ++ // that the primary event size is correct
> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize);
> ++ UT_ASSERT_NOT_EFI_ERROR (Status);
> ++
> ++ // Calculate the existing logic event size
> ++ ExistingLogicEventSize = (UINT32)(OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions)
> ++ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry);
> ++
> ++ // Check that the event size is correct
> ++ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize);
> ++
> ++ // Tests that the primary event size may not overflow
> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ // Test that the size of partition entries may not overflow
> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
> ++
> ++ return UNIT_TEST_PASSED;
> ++}
> ++
> ++// *--------------------------------------------------------------------*
> ++// * Unit Test Code Main Function
> ++// *--------------------------------------------------------------------*
> ++
> ++/**
> ++ This function acts as the entry point for the unit tests.
> ++
> ++ @retval UNIT_TEST_PASSED The test passed.
> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
> ++ @retval others The test failed.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++UefiTestMain (
> ++ VOID
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++ UNIT_TEST_FRAMEWORK_HANDLE Framework;
> ++ UNIT_TEST_SUITE_HANDLE Tcg2MeasureBootLibValidationTestSuite;
> ++
> ++ Framework = NULL;
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME));
> ++
> ++ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status));
> ++ goto EXIT;
> ++ }
> ++
> ++ Status = CreateUnitTestSuite (&Tcg2MeasureBootLibValidationTestSuite, Framework, "Tcg2MeasureBootLibValidationTestSuite", "Common.Tcg2MeasureBootLibValidation", NULL, NULL);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for Tcg2MeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME));
> ++ Status = EFI_OUT_OF_RESOURCES;
> ++ goto EXIT;
> ++ }
> ++
> ++ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context
> ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.Tcg2MeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL);
> ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL);
> ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL);
> ++
> ++ Status = RunAllTestSuites (Framework);
> ++
> ++EXIT:
> ++ if (Framework != NULL) {
> ++ FreeUnitTestFramework (Framework);
> ++ }
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME));
> ++ return Status;
> ++}
> ++
> ++///
> ++/// Avoid ECC error for function name that starts with lower case letter
> ++///
> ++#define DxeTpm2MeasureBootLibUnitTestMain main
> ++
> ++/**
> ++ Standard POSIX C entry point for host based unit test execution.
> ++
> ++ @param[in] Argc Number of arguments
> ++ @param[in] Argv Array of pointers to arguments
> ++
> ++ @retval 0 Success
> ++ @retval other Error
> ++**/
> ++INT32
> ++DxeTpm2MeasureBootLibUnitTestMain (
> ++ IN INT32 Argc,
> ++ IN CHAR8 *Argv[]
> ++ )
> ++{
> ++ return (INT32)UefiTestMain ();
> ++}
> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf
> +new file mode 100644
> +index 0000000000..2999aa2a44
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf
> +@@ -0,0 +1,28 @@
> ++## @file
> ++# This file builds the unit tests for DxeTpm2MeasureBootLib
> ++#
> ++# Copyright (C) Microsoft Corporation.<BR>
> ++# SPDX-License-Identifier: BSD-2-Clause-Patent
> ++##
> ++
> ++[Defines]
> ++ INF_VERSION = 0x00010006
> ++ BASE_NAME = DxeTpm2MeasuredBootLibTest
> ++ FILE_GUID = 144d757f-d423-484e-9309-a23695fad5bd
> ++ MODULE_TYPE = HOST_APPLICATION
> ++ VERSION_STRING = 1.0
> ++ ENTRY_POINT = main
> ++
> ++[Sources]
> ++ DxeTpm2MeasureBootLibSanitizationTest.c
> ++ ../DxeTpm2MeasureBootLibSanitization.c
> ++
> ++[Packages]
> ++ MdePkg/MdePkg.dec
> ++
> ++[LibraryClasses]
> ++ BaseLib
> ++ DebugLib
> ++ UnitTestLib
> ++ PrintLib
> ++ SafeIntLib
> +diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml
> +index 7912142398..da811fdf93 100644
> +--- a/SecurityPkg/SecurityPkg.ci.yaml
> ++++ b/SecurityPkg/SecurityPkg.ci.yaml
> +@@ -15,6 +15,7 @@
> + ## "<ErrorID>", "<KeyWord>"
> + ## ]
> + "ExceptionList": [
> ++ "8001", "DxeTpm2MeasureBootLibUnitTestMain",
> + ],
> + ## Both file path and directory path are accepted.
> + "IgnoreFiles": [
> +--
> +2.40.0
> +
> diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch
> new file mode 100644
> index 0000000000..6c20cc305e
> --- /dev/null
> +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch
> @@ -0,0 +1,889 @@
> +From 4776a1b39ee08fc45c70c1eab5a0195f325000d3 Mon Sep 17 00:00:00 2001
> +From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com>
> +Date: Fri, 12 Jan 2024 02:16:02 +0800
> +Subject: [PATCH] SecurityPkg: DxeTpmMeasureBootLib: SECURITY PATCH 4117 - CVE
> + 2022-36763
> +
> +This commit contains the patch files and tests for DxeTpmMeasureBootLib
> +CVE 2022-36763.
> +
> +Cc: Jiewen Yao <jiewen.yao@intel.com>
> +
> +Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com>
> +Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
> +
> +CVE: CVE-2022-36763
> +
> +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/4776a1b39ee08fc45c70c1eab5a0195f325000d3]
> +
> +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
> +---
> + .../DxeTpmMeasureBootLib.c | 40 ++-
> + .../DxeTpmMeasureBootLib.inf | 4 +-
> + .../DxeTpmMeasureBootLibSanitization.c | 241 ++++++++++++++
> + .../DxeTpmMeasureBootLibSanitization.h | 114 +++++++
> + .../DxeTpmMeasureBootLibSanitizationTest.c | 301 ++++++++++++++++++
> + ...eTpmMeasureBootLibSanitizationTestHost.inf | 28 ++
> + SecurityPkg/SecurityPkg.ci.yaml | 1 +
> + 7 files changed, 715 insertions(+), 14 deletions(-)
> + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c
> + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h
> + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c
> + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf
> +
> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
> +index 220393dd2b..669ab19134 100644
> +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
> +@@ -18,6 +18,8 @@
> + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> ++Copyright (c) Microsoft Corporation.<BR>
> ++SPDX-License-Identifier: BSD-2-Clause-Patent
> + **/
> +
> + #include <PiDxe.h>
> +@@ -40,6 +42,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> + #include <Library/SecurityManagementLib.h>
> + #include <Library/HobLib.h>
> +
> ++#include "DxeTpmMeasureBootLibSanitization.h"
> ++
> + //
> + // Flag to check GPT partition. It only need be measured once.
> + //
> +@@ -136,6 +140,9 @@ TcgMeasureGptTable (
> + UINT32 EventSize;
> + UINT32 EventNumber;
> + EFI_PHYSICAL_ADDRESS EventLogLastEntry;
> ++ UINT32 AllocSize;
> ++
> ++ GptData = NULL;
> +
> + if (mMeasureGptCount > 0) {
> + return EFI_SUCCESS;
> +@@ -166,8 +173,8 @@ TcgMeasureGptTable (
> + BlockIo->Media->BlockSize,
> + (UINT8 *)PrimaryHeader
> + );
> +- if (EFI_ERROR (Status)) {
> +- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n"));
> ++ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) {
> ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n"));
> + FreePool (PrimaryHeader);
> + return EFI_DEVICE_ERROR;
> + }
> +@@ -175,7 +182,13 @@ TcgMeasureGptTable (
> + //
> + // Read the partition entry.
> + //
> +- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
> ++ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize);
> ++ if (EFI_ERROR (Status)) {
> ++ FreePool (PrimaryHeader);
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize);
> + if (EntryPtr == NULL) {
> + FreePool (PrimaryHeader);
> + return EFI_OUT_OF_RESOURCES;
> +@@ -185,7 +198,7 @@ TcgMeasureGptTable (
> + DiskIo,
> + BlockIo->Media->MediaId,
> + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
> +- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry,
> ++ AllocSize,
> + EntryPtr
> + );
> + if (EFI_ERROR (Status)) {
> +@@ -210,9 +223,8 @@ TcgMeasureGptTable (
> + //
> + // Prepare Data for Measurement
> + //
> +- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions)
> +- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);
> +- TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT_HDR));
> ++ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &EventSize);
> ++ TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize);
> + if (TcgEvent == NULL) {
> + FreePool (PrimaryHeader);
> + FreePool (EntryPtr);
> +@@ -221,7 +233,7 @@ TcgMeasureGptTable (
> +
> + TcgEvent->PCRIndex = 5;
> + TcgEvent->EventType = EV_EFI_GPT_EVENT;
> +- TcgEvent->EventSize = EventSize;
> ++ TcgEvent->EventSize = EventSize - sizeof (TCG_PCR_EVENT_HDR);
> + GptData = (EFI_GPT_DATA *)TcgEvent->Event;
> +
> + //
> +@@ -361,11 +373,13 @@ TcgMeasurePeImage (
> + TcgEvent->PCRIndex = 2;
> + break;
> + default:
> +- DEBUG ((
> +- DEBUG_ERROR,
> +- "TcgMeasurePeImage: Unknown subsystem type %d",
> +- ImageType
> +- ));
> ++ DEBUG (
> ++ (
> ++ DEBUG_ERROR,
> ++ "TcgMeasurePeImage: Unknown subsystem type %d",
> ++ ImageType
> ++ )
> ++ );
> + goto Finish;
> + }
> +
> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
> +index ebab6f7c1e..414c654d15 100644
> +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
> +@@ -32,6 +32,8 @@
> +
> + [Sources]
> + DxeTpmMeasureBootLib.c
> ++ DxeTpmMeasureBootLibSanitization.c
> ++ DxeTpmMeasureBootLibSanitization.h
> +
> + [Packages]
> + MdePkg/MdePkg.dec
> +@@ -41,6 +43,7 @@
> +
> + [LibraryClasses]
> + BaseMemoryLib
> ++ SafeIntLib
> + DebugLib
> + MemoryAllocationLib
> + DevicePathLib
> +@@ -59,4 +62,3 @@
> + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES
> + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
> + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES
> +-
> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c
> +new file mode 100644
> +index 0000000000..a3fa46f5e6
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c
> +@@ -0,0 +1,241 @@
> ++/** @file
> ++ The library instance provides security service of TPM2 measure boot and
> ++ Confidential Computing (CC) 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.
> ++
> ++ This file will pull out the validation logic from the following functions, in an
> ++ attempt to validate the untrusted input in the form of unit tests
> ++
> ++ These are those functions:
> ++
> ++ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content
> ++ read is within the image buffer.
> ++
> ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse
> ++ partition data carefully.
> ++
> ++ Copyright (c) Microsoft Corporation.<BR>
> ++ SPDX-License-Identifier: BSD-2-Clause-Patent
> ++**/
> ++#include <Uefi.h>
> ++#include <Uefi/UefiSpec.h>
> ++#include <Library/SafeIntLib.h>
> ++#include <Library/UefiLib.h>
> ++#include <Library/DebugLib.h>
> ++#include <Library/BaseLib.h>
> ++#include <IndustryStandard/UefiTcgPlatform.h>
> ++#include <Protocol/BlockIo.h>
> ++#include <Library/MemoryAllocationLib.h>
> ++
> ++#include "DxeTpmMeasureBootLibSanitization.h"
> ++
> ++#define GPT_HEADER_REVISION_V1 0x00010000
> ++
> ++/**
> ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse
> ++ However this function will not attempt to verify the validity of the GPT partition
> ++ It will check the following:
> ++ - Signature
> ++ - Revision
> ++ - AlternateLBA
> ++ - FirstUsableLBA
> ++ - LastUsableLBA
> ++ - PartitionEntryLBA
> ++ - NumberOfPartitionEntries
> ++ - SizeOfPartitionEntry
> ++ - BlockIo
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[in] BlockIo
> ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure.
> ++
> ++ @retval EFI_SUCCESS
> ++ The EFI_PARTITION_TABLE_HEADER structure is valid.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ The EFI_PARTITION_TABLE_HEADER structure is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizeEfiPartitionTableHeader (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo
> ++ )
> ++{
> ++ // Verify that the input parameters are safe to use
> ++ if (PrimaryHeader == NULL) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n"));
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII)
> ++ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ // The version must be GPT_HEADER_REVISION_V1 (0x00010000)
> ++ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size
> ++ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ // check that the PartitionEntryLBA greater than the Max LBA
> ++ // This will be used later for multiplication
> ++ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ // Check that the number of partition entries is greater than zero
> ++ if (PrimaryHeader->NumberOfPartitionEntries == 0) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory
> ++ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) {
> ++ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ // This check is to prevent overflow when calculating the allocation size for the partition entries
> ++ // This check will be used later for multiplication
> ++ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ return EFI_SUCCESS;
> ++}
> ++
> ++/**
> ++ This function will validate that the allocation size from the primary header is sane
> ++ It will check the following:
> ++ - AllocationSize does not overflow
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[out] AllocationSize
> ++ Pointer to the allocation size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The allocation size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ The allocation size is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizePrimaryHeaderAllocationSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ OUT UINT32 *AllocationSize
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++
> ++ if (PrimaryHeader == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ if (AllocationSize == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ // Replacing logic:
> ++ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry;
> ++ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n"));
> ++ return EFI_BAD_BUFFER_SIZE;
> ++ }
> ++
> ++ return EFI_SUCCESS;
> ++}
> ++
> ++/**
> ++ This function will validate that the Gpt Event Size calculated from the primary header is sane
> ++ It will check the following:
> ++ - EventSize does not overflow
> ++
> ++ Important: This function includes the entire length of the allocated space, including the
> ++ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract
> ++ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing.
> ++
> ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++ @param[in] NumberOfPartition - Number of partitions.
> ++ @param[out] EventSize - Pointer to the event size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The event size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ Overflow would have occurred.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ One of the passed parameters was invalid.
> ++**/
> ++EFI_STATUS
> ++SanitizePrimaryHeaderGptEventSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN UINTN NumberOfPartition,
> ++ OUT UINT32 *EventSize
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++ UINT32 SafeNumberOfPartitions;
> ++
> ++ if (PrimaryHeader == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ if (EventSize == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32
> ++ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n"));
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ // Replacing logic:
> ++ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry + sizeof (TCG_PCR_EVENT_HDR));
> ++ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n"));
> ++ return EFI_BAD_BUFFER_SIZE;
> ++ }
> ++
> ++ Status = SafeUint32Add (
> ++ sizeof (TCG_PCR_EVENT_HDR) +
> ++ OFFSET_OF (EFI_GPT_DATA, Partitions),
> ++ *EventSize,
> ++ EventSize
> ++ );
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n"));
> ++ return EFI_BAD_BUFFER_SIZE;
> ++ }
> ++
> ++ return EFI_SUCCESS;
> ++}
> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h
> +new file mode 100644
> +index 0000000000..0d9d00c281
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h
> +@@ -0,0 +1,114 @@
> ++/** @file
> ++ This file includes the function prototypes for the sanitization functions.
> ++
> ++ These are those functions:
> ++
> ++ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content
> ++ read is within the image buffer.
> ++
> ++ TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its
> ++ data structure within this image buffer before use.
> ++
> ++ TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse
> ++ partition data carefully.
> ++
> ++ Copyright (c) Microsoft Corporation.<BR>
> ++ SPDX-License-Identifier: BSD-2-Clause-Patent
> ++
> ++**/
> ++
> ++#ifndef DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_
> ++#define DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_
> ++
> ++#include <Uefi.h>
> ++#include <Uefi/UefiSpec.h>
> ++#include <Protocol/BlockIo.h>
> ++#include <IndustryStandard/UefiTcgPlatform.h>
> ++
> ++/**
> ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse
> ++ However this function will not attempt to verify the validity of the GPT partition
> ++ It will check the following:
> ++ - Signature
> ++ - Revision
> ++ - AlternateLBA
> ++ - FirstUsableLBA
> ++ - LastUsableLBA
> ++ - PartitionEntryLBA
> ++ - NumberOfPartitionEntries
> ++ - SizeOfPartitionEntry
> ++ - BlockIo
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[in] BlockIo
> ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure.
> ++
> ++ @retval EFI_SUCCESS
> ++ The EFI_PARTITION_TABLE_HEADER structure is valid.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ The EFI_PARTITION_TABLE_HEADER structure is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizeEfiPartitionTableHeader (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo
> ++ );
> ++
> ++/**
> ++ This function will validate that the allocation size from the primary header is sane
> ++ It will check the following:
> ++ - AllocationSize does not overflow
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[out] AllocationSize
> ++ Pointer to the allocation size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The allocation size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ The allocation size is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizePrimaryHeaderAllocationSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ OUT UINT32 *AllocationSize
> ++ );
> ++
> ++/**
> ++ This function will validate that the Gpt Event Size calculated from the primary header is sane
> ++ It will check the following:
> ++ - EventSize does not overflow
> ++
> ++ Important: This function includes the entire length of the allocated space, including the
> ++ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract
> ++ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing.
> ++
> ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++ @param[in] NumberOfPartition - Number of partitions.
> ++ @param[out] EventSize - Pointer to the event size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The event size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ Overflow would have occurred.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ One of the passed parameters was invalid.
> ++**/
> ++EFI_STATUS
> ++SanitizePrimaryHeaderGptEventSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN UINTN NumberOfPartition,
> ++ OUT UINT32 *EventSize
> ++ );
> ++
> ++#endif // DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_
> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c
> +new file mode 100644
> +index 0000000000..eeb928cdb0
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c
> +@@ -0,0 +1,301 @@
> ++/** @file
> ++This file includes the unit test cases for the DxeTpmMeasureBootLibSanitizationTest.c.
> ++
> ++Copyright (c) Microsoft Corporation.<BR>
> ++SPDX-License-Identifier: BSD-2-Clause-Patent
> ++**/
> ++
> ++#include <Uefi.h>
> ++#include <Library/UefiLib.h>
> ++#include <Library/DebugLib.h>
> ++#include <Library/UnitTestLib.h>
> ++#include <Protocol/BlockIo.h>
> ++#include <Library/MemoryAllocationLib.h>
> ++#include <Library/BaseMemoryLib.h>
> ++#include <IndustryStandard/UefiTcgPlatform.h>
> ++
> ++#include "../DxeTpmMeasureBootLibSanitization.h"
> ++
> ++#define UNIT_TEST_NAME "DxeTpmMeasureBootLibSanitizationTest"
> ++#define UNIT_TEST_VERSION "1.0"
> ++
> ++#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000
> ++#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1
> ++#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128
> ++
> ++/**
> ++ This function tests the SanitizeEfiPartitionTableHeader function.
> ++ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER
> ++ structure will not cause undefined or unexpected behavior.
> ++
> ++ In general the TPM should still be able to measure the data, but
> ++ be the header should be sanitized to prevent any unexpected behavior.
> ++
> ++ @param[in] Context The unit test context.
> ++
> ++ @retval UNIT_TEST_PASSED The test passed.
> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
> ++**/
> ++UNIT_TEST_STATUS
> ++EFIAPI
> ++TestSanitizeEfiPartitionTableHeader (
> ++ IN UNIT_TEST_CONTEXT Context
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
> ++ EFI_BLOCK_IO_PROTOCOL BlockIo;
> ++ EFI_BLOCK_IO_MEDIA BlockMedia;
> ++
> ++ // Generate EFI_BLOCK_IO_MEDIA test data
> ++ BlockMedia.MediaId = 1;
> ++ BlockMedia.RemovableMedia = FALSE;
> ++ BlockMedia.MediaPresent = TRUE;
> ++ BlockMedia.LogicalPartition = FALSE;
> ++ BlockMedia.ReadOnly = FALSE;
> ++ BlockMedia.WriteCaching = FALSE;
> ++ BlockMedia.BlockSize = 512;
> ++ BlockMedia.IoAlign = 1;
> ++ BlockMedia.LastBlock = 0;
> ++
> ++ // Generate EFI_BLOCK_IO_PROTOCOL test data
> ++ BlockIo.Revision = 1;
> ++ BlockIo.Media = &BlockMedia;
> ++ BlockIo.Reset = NULL;
> ++ BlockIo.ReadBlocks = NULL;
> ++ BlockIo.WriteBlocks = NULL;
> ++ BlockIo.FlushBlocks = NULL;
> ++
> ++ // Geneate EFI_PARTITION_TABLE_HEADER test data
> ++ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID;
> ++ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION;
> ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER);
> ++ PrimaryHeader.MyLBA = 1;
> ++ PrimaryHeader.AlternateLBA = 2;
> ++ PrimaryHeader.FirstUsableLBA = 3;
> ++ PrimaryHeader.LastUsableLBA = 4;
> ++ PrimaryHeader.PartitionEntryLBA = 5;
> ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES;
> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid
> ++
> ++ // Calculate the CRC32 of the PrimaryHeader
> ++ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize);
> ++
> ++ // Test that a normal PrimaryHeader passes validation
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_NOT_EFI_ERROR (Status);
> ++
> ++ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR
> ++ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!""
> ++ PrimaryHeader.NumberOfPartitionEntries = 0;
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
> ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++
> ++ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR
> ++ // Should print "Invalid Partition Table Header Size!"
> ++ PrimaryHeader.Header.HeaderSize = 0;
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
> ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER);
> ++
> ++ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR
> ++ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!"
> ++ PrimaryHeader.SizeOfPartitionEntry = 1;
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
> ++
> ++ return UNIT_TEST_PASSED;
> ++}
> ++
> ++/**
> ++ This function tests the SanitizePrimaryHeaderAllocationSize function.
> ++ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER
> ++ structure will not cause an overflow when calculating the allocation size.
> ++
> ++ @param[in] Context The unit test context.
> ++
> ++ @retval UNIT_TEST_PASSED The test passed.
> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
> ++**/
> ++UNIT_TEST_STATUS
> ++EFIAPI
> ++TestSanitizePrimaryHeaderAllocationSize (
> ++ IN UNIT_TEST_CONTEXT Context
> ++ )
> ++{
> ++ UINT32 AllocationSize;
> ++
> ++ EFI_STATUS Status;
> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
> ++
> ++ // Test that a normal PrimaryHeader passes validation
> ++ PrimaryHeader.NumberOfPartitionEntries = 5;
> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_NOT_EFI_ERROR (Status);
> ++
> ++ // Test that the allocation size is correct compared to the existing logic
> ++ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry);
> ++
> ++ // Test that an overflow is detected
> ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32;
> ++ PrimaryHeader.SizeOfPartitionEntry = 5;
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ // Test the inverse
> ++ PrimaryHeader.NumberOfPartitionEntries = 5;
> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ // Test the worst case scenario
> ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32;
> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
> ++
> ++ return UNIT_TEST_PASSED;
> ++}
> ++
> ++/**
> ++ This function tests the SanitizePrimaryHeaderGptEventSize function.
> ++ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure
> ++ will not cause an overflow when calculating the event size.
> ++
> ++ @param[in] Context The unit test context.
> ++
> ++ @retval UNIT_TEST_PASSED The test passed.
> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
> ++**/
> ++UNIT_TEST_STATUS
> ++EFIAPI
> ++TestSanitizePrimaryHeaderGptEventSize (
> ++ IN UNIT_TEST_CONTEXT Context
> ++ )
> ++{
> ++ UINT32 EventSize;
> ++ UINT32 ExistingLogicEventSize;
> ++ EFI_STATUS Status;
> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
> ++ UINTN NumberOfPartition;
> ++ EFI_GPT_DATA *GptData;
> ++
> ++ GptData = NULL;
> ++
> ++ // Test that a normal PrimaryHeader passes validation
> ++ PrimaryHeader.NumberOfPartitionEntries = 5;
> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++
> ++ // set the number of partitions
> ++ NumberOfPartition = 13;
> ++
> ++ // that the primary event size is correct
> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize);
> ++ UT_ASSERT_NOT_EFI_ERROR (Status);
> ++
> ++ // Calculate the existing logic event size
> ++ ExistingLogicEventSize = (UINT32)(sizeof (TCG_PCR_EVENT_HDR) + OFFSET_OF (EFI_GPT_DATA, Partitions)
> ++ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry);
> ++
> ++ // Check that the event size is correct
> ++ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize);
> ++
> ++ // Tests that the primary event size may not overflow
> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ // Test that the size of partition entries may not overflow
> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
> ++
> ++ return UNIT_TEST_PASSED;
> ++}
> ++
> ++// *--------------------------------------------------------------------*
> ++// * Unit Test Code Main Function
> ++// *--------------------------------------------------------------------*
> ++
> ++/**
> ++ This function acts as the entry point for the unit tests.
> ++
> ++ @param argc - The number of command line arguments
> ++ @param argv - The command line arguments
> ++
> ++ @return int - The status of the test
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++UefiTestMain (
> ++ VOID
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++ UNIT_TEST_FRAMEWORK_HANDLE Framework;
> ++ UNIT_TEST_SUITE_HANDLE TcgMeasureBootLibValidationTestSuite;
> ++
> ++ Framework = NULL;
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME));
> ++
> ++ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status));
> ++ goto EXIT;
> ++ }
> ++
> ++ Status = CreateUnitTestSuite (&TcgMeasureBootLibValidationTestSuite, Framework, "TcgMeasureBootLibValidationTestSuite", "Common.TcgMeasureBootLibValidation", NULL, NULL);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for TcgMeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME));
> ++ Status = EFI_OUT_OF_RESOURCES;
> ++ goto EXIT;
> ++ }
> ++
> ++ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context
> ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.TcgMeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL);
> ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL);
> ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL);
> ++
> ++ Status = RunAllTestSuites (Framework);
> ++
> ++EXIT:
> ++ if (Framework != NULL) {
> ++ FreeUnitTestFramework (Framework);
> ++ }
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME));
> ++ return Status;
> ++}
> ++
> ++///
> ++/// Avoid ECC error for function name that starts with lower case letter
> ++///
> ++#define DxeTpmMeasureBootLibUnitTestMain main
> ++
> ++/**
> ++ Standard POSIX C entry point for host based unit test execution.
> ++
> ++ @param[in] Argc Number of arguments
> ++ @param[in] Argv Array of pointers to arguments
> ++
> ++ @retval 0 Success
> ++ @retval other Error
> ++**/
> ++INT32
> ++DxeTpmMeasureBootLibUnitTestMain (
> ++ IN INT32 Argc,
> ++ IN CHAR8 *Argv[]
> ++ )
> ++{
> ++ return (INT32)UefiTestMain ();
> ++}
> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf
> +new file mode 100644
> +index 0000000000..47b0811b00
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf
> +@@ -0,0 +1,28 @@
> ++## @file
> ++# This file builds the unit tests for DxeTpmMeasureBootLib
> ++#
> ++# Copyright (C) Microsoft Corporation.<BR>
> ++# SPDX-License-Identifier: BSD-2-Clause-Patent
> ++##
> ++
> ++[Defines]
> ++ INF_VERSION = 0x00010006
> ++ BASE_NAME = DxeTpmMeasuredBootLibTest
> ++ FILE_GUID = eb01bc38-309c-4d3e-967e-9f078c90772f
> ++ MODULE_TYPE = HOST_APPLICATION
> ++ VERSION_STRING = 1.0
> ++ ENTRY_POINT = main
> ++
> ++[Sources]
> ++ DxeTpmMeasureBootLibSanitizationTest.c
> ++ ../DxeTpmMeasureBootLibSanitization.c
> ++
> ++[Packages]
> ++ MdePkg/MdePkg.dec
> ++
> ++[LibraryClasses]
> ++ BaseLib
> ++ DebugLib
> ++ UnitTestLib
> ++ PrintLib
> ++ SafeIntLib
> +diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml
> +index da811fdf93..0e40eaa0fe 100644
> +--- a/SecurityPkg/SecurityPkg.ci.yaml
> ++++ b/SecurityPkg/SecurityPkg.ci.yaml
> +@@ -16,6 +16,7 @@
> + ## ]
> + "ExceptionList": [
> + "8001", "DxeTpm2MeasureBootLibUnitTestMain",
> ++ "8001", "DxeTpmMeasureBootLibUnitTestMain"
> + ],
> + ## Both file path and directory path are accepted.
> + "IgnoreFiles": [
> +--
> +2.40.0
> +
> diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch
> new file mode 100644
> index 0000000000..59bd5c4910
> --- /dev/null
> +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch
> @@ -0,0 +1,55 @@
> +From 1ddcb9fc6b4164e882687b031e8beacfcf7df29e Mon Sep 17 00:00:00 2001
> +From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com>
> +Date: Fri, 12 Jan 2024 02:16:03 +0800
> +Subject: [PATCH] SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml
> +
> +This creates / adds a security file that tracks the security fixes
> +found in this package and can be used to find the fixes that were
> +applied.
> +
> +Cc: Jiewen Yao <jiewen.yao@intel.com>
> +
> +Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com>
> +Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
> +
> +CVE: CVE-2022-36763
> +
> +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1ddcb9fc6b4164e882687b031e8beacfcf7df29e]
> +
> +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
> +---
> + SecurityPkg/SecurityFixes.yaml | 22 ++++++++++++++++++++++
> + 1 file changed, 22 insertions(+)
> + create mode 100644 SecurityPkg/SecurityFixes.yaml
> +
> +diff --git a/SecurityPkg/SecurityFixes.yaml b/SecurityPkg/SecurityFixes.yaml
> +new file mode 100644
> +index 0000000000..f9e3e7be74
> +--- /dev/null
> ++++ b/SecurityPkg/SecurityFixes.yaml
> +@@ -0,0 +1,22 @@
> ++## @file
> ++# Security Fixes for SecurityPkg
> ++#
> ++# Copyright (c) Microsoft Corporation
> ++# SPDX-License-Identifier: BSD-2-Clause-Patent
> ++##
> ++CVE_2022_36763:
> ++ commit_titles:
> ++ - "SecurityPkg: DxeTpm2Measurement: SECURITY PATCH 4117 - CVE 2022-36763"
> ++ - "SecurityPkg: DxeTpmMeasurement: SECURITY PATCH 4117 - CVE 2022-36763"
> ++ - "SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml"
> ++ cve: CVE-2022-36763
> ++ date_reported: 2022-10-25 11:31 UTC
> ++ description: (CVE-2022-36763) - Heap Buffer Overflow in Tcg2MeasureGptTable()
> ++ note: This patch is related to and supersedes TCBZ2168
> ++ files_impacted:
> ++ - Library\DxeTpm2MeasureBootLib\DxeTpm2MeasureBootLib.c
> ++ - Library\DxeTpmMeasureBootLib\DxeTpmMeasureBootLib.c
> ++ links:
> ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4117
> ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=2168
> ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=1990
> +--
> +2.40.0
> +
> diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb
> index 84e3360a3a..78d86ad879 100644
> --- a/meta/recipes-core/ovmf/ovmf_git.bb
> +++ b/meta/recipes-core/ovmf/ovmf_git.bb
> @@ -27,6 +27,9 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \
> file://0006-reproducible.patch \
> file://0001-BaseTools-fix-gcc12-warning.patch \
> file://0001-BaseTools-fix-gcc12-warning-1.patch \
> + file://CVE-2022-36763-0001.patch \
> + file://CVE-2022-36763-0002.patch \
> + file://CVE-2022-36763-0003.patch \
> "
>
> PV = "edk2-stable202202"
> --
> 2.25.1
>
Hi Steve,
I am afraid the issue was caused by CR("^M") in ovmf source code
The source of ovmf use CR (^M) as new line, we should use 'git am --keep-cr xxxx.patch' to apply the patch,
otherwise do_patch failed
But I do not know how you apply the patch to your build or via patchtest automatically, do you use git am with option --keep-cr?
//Hongxu
________________________________
From: Steve Sakoman <steve@sakoman.com>
Sent: Wednesday, November 27, 2024 10:50 PM
To: Jia, Hongxu <Hongxu.Jia@windriver.com>
Cc: openembedded-core@lists.openembedded.org <openembedded-core@lists.openembedded.org>
Subject: Re: [kirkstone][PATCH V2 01/13] ovmf: Fix CVE-2022-36763
CAUTION: This email comes from a non Wind River email account!
Do not click links or open attachments unless you recognize the sender and know the content is safe.
I am getting build time errors with this patch:
ERROR: ovmf-edk2-stable202202-r0 do_patch: Applying patch
'CVE-2022-36763-0001.patch' on target directory
'/home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/git'
CmdError('quilt --quiltrc
/home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/recipe-sysroot-native/etc/quiltrc
push', 0, 'stdout: Applying patch CVE-2022-36763-0001.patch
patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
Hunk #1 FAILED at 20 (different line endings).
Hunk #2 FAILED at 44 (different line endings).
Hunk #3 FAILED at 144 (different line endings).
Hunk #4 FAILED at 195 (different line endings).
Hunk #5 FAILED at 223 (different line endings).
Hunk #6 FAILED at 248 (different line endings).
Hunk #7 FAILED at 310 (different line endings).
Hunk #8 FAILED at 326 (different line endings).
Hunk #9 FAILED at 443 (different line endings).
Hunk #10 FAILED at 515 (different line endings).
Hunk #11 FAILED at 646 (different line endings).
11 out of 11 hunks FAILED -- rejects in file
SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
Hunk #1 FAILED at 37 (different line endings).
Hunk #2 FAILED at 46 (different line endings).
Hunk #3 FAILED at 65 (different line endings).
3 out of 3 hunks FAILED -- rejects in file
SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c
patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h
patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c
patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf
patching file SecurityPkg/SecurityPkg.ci.yaml
Hunk #1 FAILED at 15 (different line endings).
1 out of 1 hunk FAILED -- rejects in file SecurityPkg/SecurityPkg.ci.yaml
Patch CVE-2022-36763-0001.patch does not apply (enforce with -f)
Please submit a V2 of this series with the line ending issues fixed.
Thanks!
Steve
On Mon, Nov 25, 2024 at 6:25 PM Hongxu Jia <hongxu.jia@windriver.com> wrote:
>
> From: Soumya Sambu <soumya.sambu@windriver.com>
>
> EDK2 is susceptible to a vulnerability in the Tcg2MeasureGptTable()
> function, allowing a user to trigger a heap buffer overflow via a local
> network. Successful exploitation of this vulnerability may result in a
> compromise of confidentiality, integrity, and/or availability.
>
> References:
> https://nvd.nist.gov/vuln/detail/CVE-2022-36763
>
> Upstream-patches:
> https://github.com/tianocore/edk2/commit/224446543206450ddb5830e6abd026d61d3c7f4b
> https://github.com/tianocore/edk2/commit/4776a1b39ee08fc45c70c1eab5a0195f325000d3
> https://github.com/tianocore/edk2/commit/1ddcb9fc6b4164e882687b031e8beacfcf7df29e
>
> Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
> ---
> .../ovmf/ovmf/CVE-2022-36763-0001.patch | 985 ++++++++++++++++++
> .../ovmf/ovmf/CVE-2022-36763-0002.patch | 889 ++++++++++++++++
> .../ovmf/ovmf/CVE-2022-36763-0003.patch | 55 +
> meta/recipes-core/ovmf/ovmf_git.bb | 3 +
> 4 files changed, 1932 insertions(+)
> create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch
> create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch
> create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch
>
> diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch
> new file mode 100644
> index 0000000000..93cefe7740
> --- /dev/null
> +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch
> @@ -0,0 +1,985 @@
> +From 224446543206450ddb5830e6abd026d61d3c7f4b Mon Sep 17 00:00:00 2001
> +From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com>
> +Date: Fri, 12 Jan 2024 02:16:01 +0800
> +Subject: [PATCH] SecurityPkg: DxeTpm2MeasureBootLib: SECURITY PATCH 4117 - CVE
> + 2022-36763
> +
> +This commit contains the patch files and tests for DxeTpm2MeasureBootLib
> +CVE 2022-36763.
> +
> +Cc: Jiewen Yao <jiewen.yao@intel.com>
> +
> +Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com>
> +
> +CVE: CVE-2022-36763
> +
> +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/224446543206450ddb5830e6abd026d61d3c7f4b]
> +
> +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
> +---
> + .../DxeTpm2MeasureBootLib.c | 69 ++--
> + .../DxeTpm2MeasureBootLib.inf | 4 +-
> + .../DxeTpm2MeasureBootLibSanitization.c | 275 ++++++++++++++++
> + .../DxeTpm2MeasureBootLibSanitization.h | 113 +++++++
> + .../DxeTpm2MeasureBootLibSanitizationTest.c | 303 ++++++++++++++++++
> + ...Tpm2MeasureBootLibSanitizationTestHost.inf | 28 ++
> + SecurityPkg/SecurityPkg.ci.yaml | 1 +
> + 7 files changed, 763 insertions(+), 30 deletions(-)
> + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c
> + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h
> + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c
> + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf
> +
> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
> +index 36a256a7af..0475103d6e 100644
> +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
> +@@ -20,6 +20,8 @@ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
> + (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> ++Copyright (c) Microsoft Corporation.<BR>
> ++SPDX-License-Identifier: BSD-2-Clause-Patent
> + **/
> +
> + #include <PiDxe.h>
> +@@ -44,6 +46,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> + #include <Library/HobLib.h>
> + #include <Protocol/CcMeasurement.h>
> +
> ++#include "DxeTpm2MeasureBootLibSanitization.h"
> ++
> + typedef struct {
> + EFI_TCG2_PROTOCOL *Tcg2Protocol;
> + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol;
> +@@ -144,10 +148,11 @@ Tcg2MeasureGptTable (
> + EFI_TCG2_EVENT *Tcg2Event;
> + EFI_CC_EVENT *CcEvent;
> + EFI_GPT_DATA *GptData;
> +- UINT32 EventSize;
> ++ UINT32 TcgEventSize;
> + EFI_TCG2_PROTOCOL *Tcg2Protocol;
> + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol;
> + EFI_CC_MR_INDEX MrIndex;
> ++ UINT32 AllocSize;
> +
> + if (mTcg2MeasureGptCount > 0) {
> + return EFI_SUCCESS;
> +@@ -195,25 +200,22 @@ Tcg2MeasureGptTable (
> + BlockIo->Media->BlockSize,
> + (UINT8 *)PrimaryHeader
> + );
> +- if (EFI_ERROR (Status)) {
> +- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n"));
> ++ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) {
> ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n"));
> + FreePool (PrimaryHeader);
> + return EFI_DEVICE_ERROR;
> + }
> +
> + //
> +- // PrimaryHeader->SizeOfPartitionEntry should not be zero
> ++ // Read the partition entry.
> + //
> +- if (PrimaryHeader->SizeOfPartitionEntry == 0) {
> +- DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry should not be zero!\n"));
> ++ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize);
> ++ if (EFI_ERROR (Status)) {
> + FreePool (PrimaryHeader);
> + return EFI_BAD_BUFFER_SIZE;
> + }
> +
> +- //
> +- // Read the partition entry.
> +- //
> +- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
> ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize);
> + if (EntryPtr == NULL) {
> + FreePool (PrimaryHeader);
> + return EFI_OUT_OF_RESOURCES;
> +@@ -223,7 +225,7 @@ Tcg2MeasureGptTable (
> + DiskIo,
> + BlockIo->Media->MediaId,
> + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
> +- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry,
> ++ AllocSize,
> + EntryPtr
> + );
> + if (EFI_ERROR (Status)) {
> +@@ -248,16 +250,21 @@ Tcg2MeasureGptTable (
> + //
> + // Prepare Data for Measurement (CcProtocol and Tcg2Protocol)
> + //
> +- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions)
> +- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);
> +- EventPtr = (UINT8 *)AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event));
> ++ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &TcgEventSize);
> ++ if (EFI_ERROR (Status)) {
> ++ FreePool (PrimaryHeader);
> ++ FreePool (EntryPtr);
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ EventPtr = (UINT8 *)AllocateZeroPool (TcgEventSize);
> + if (EventPtr == NULL) {
> + Status = EFI_OUT_OF_RESOURCES;
> + goto Exit;
> + }
> +
> + Tcg2Event = (EFI_TCG2_EVENT *)EventPtr;
> +- Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event);
> ++ Tcg2Event->Size = TcgEventSize;
> + Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER);
> + Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;
> + Tcg2Event->Header.PCRIndex = 5;
> +@@ -310,7 +317,7 @@ Tcg2MeasureGptTable (
> + CcProtocol,
> + 0,
> + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData,
> +- (UINT64)EventSize,
> ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event),
> + CcEvent
> + );
> + if (!EFI_ERROR (Status)) {
> +@@ -326,7 +333,7 @@ Tcg2MeasureGptTable (
> + Tcg2Protocol,
> + 0,
> + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData,
> +- (UINT64)EventSize,
> ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event),
> + Tcg2Event
> + );
> + if (!EFI_ERROR (Status)) {
> +@@ -443,11 +450,13 @@ Tcg2MeasurePeImage (
> + Tcg2Event->Header.PCRIndex = 2;
> + break;
> + default:
> +- DEBUG ((
> +- DEBUG_ERROR,
> +- "Tcg2MeasurePeImage: Unknown subsystem type %d",
> +- ImageType
> +- ));
> ++ DEBUG (
> ++ (
> ++ DEBUG_ERROR,
> ++ "Tcg2MeasurePeImage: Unknown subsystem type %d",
> ++ ImageType
> ++ )
> ++ );
> + goto Finish;
> + }
> +
> +@@ -515,7 +524,7 @@ Finish:
> +
> + @param MeasureBootProtocols Pointer to the located measure boot protocol instances.
> +
> +- @retval EFI_SUCCESS Sucessfully locate the measure boot protocol instances (at least one instance).
> ++ @retval EFI_SUCCESS Successfully locate the measure boot protocol instances (at least one instance).
> + @retval EFI_UNSUPPORTED Measure boot is not supported.
> + **/
> + EFI_STATUS
> +@@ -646,12 +655,14 @@ DxeTpm2MeasureBootHandler (
> + return EFI_SUCCESS;
> + }
> +
> +- DEBUG ((
> +- DEBUG_INFO,
> +- "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n",
> +- MeasureBootProtocols.Tcg2Protocol,
> +- MeasureBootProtocols.CcProtocol
> +- ));
> ++ DEBUG (
> ++ (
> ++ DEBUG_INFO,
> ++ "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n",
> ++ MeasureBootProtocols.Tcg2Protocol,
> ++ MeasureBootProtocols.CcProtocol
> ++ )
> ++ );
> +
> + //
> + // Copy File Device Path
> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
> +index 6dca79a20c..28995f438d 100644
> +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
> +@@ -37,6 +37,8 @@
> +
> + [Sources]
> + DxeTpm2MeasureBootLib.c
> ++ DxeTpm2MeasureBootLibSanitization.c
> ++ DxeTpm2MeasureBootLibSanitization.h
> +
> + [Packages]
> + MdePkg/MdePkg.dec
> +@@ -46,6 +48,7 @@
> +
> + [LibraryClasses]
> + BaseMemoryLib
> ++ SafeIntLib
> + DebugLib
> + MemoryAllocationLib
> + DevicePathLib
> +@@ -65,4 +68,3 @@
> + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES
> + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
> + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES
> +-
> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c
> +new file mode 100644
> +index 0000000000..e2309655d3
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c
> +@@ -0,0 +1,275 @@
> ++/** @file
> ++ The library instance provides security service of TPM2 measure boot and
> ++ Confidential Computing (CC) 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.
> ++
> ++ This file will pull out the validation logic from the following functions, in an
> ++ attempt to validate the untrusted input in the form of unit tests
> ++
> ++ These are those functions:
> ++
> ++ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content
> ++ read is within the image buffer.
> ++
> ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse
> ++ partition data carefully.
> ++
> ++ Copyright (c) Microsoft Corporation.<BR>
> ++ SPDX-License-Identifier: BSD-2-Clause-Patent
> ++**/
> ++#include <Uefi.h>
> ++#include <Uefi/UefiSpec.h>
> ++#include <Library/SafeIntLib.h>
> ++#include <Library/UefiLib.h>
> ++#include <Library/DebugLib.h>
> ++#include <Library/BaseLib.h>
> ++#include <IndustryStandard/UefiTcgPlatform.h>
> ++#include <Protocol/BlockIo.h>
> ++#include <Library/MemoryAllocationLib.h>
> ++
> ++#include "DxeTpm2MeasureBootLibSanitization.h"
> ++
> ++#define GPT_HEADER_REVISION_V1 0x00010000
> ++
> ++/**
> ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse
> ++ However this function will not attempt to verify the validity of the GPT partition
> ++ It will check the following:
> ++ - Signature
> ++ - Revision
> ++ - AlternateLBA
> ++ - FirstUsableLBA
> ++ - LastUsableLBA
> ++ - PartitionEntryLBA
> ++ - NumberOfPartitionEntries
> ++ - SizeOfPartitionEntry
> ++ - BlockIo
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[in] BlockIo
> ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure.
> ++
> ++ @retval EFI_SUCCESS
> ++ The EFI_PARTITION_TABLE_HEADER structure is valid.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ The EFI_PARTITION_TABLE_HEADER structure is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizeEfiPartitionTableHeader (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo
> ++ )
> ++{
> ++ //
> ++ // Verify that the input parameters are safe to use
> ++ //
> ++ if (PrimaryHeader == NULL) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n"));
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ //
> ++ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII)
> ++ //
> ++ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ //
> ++ // The version must be GPT_HEADER_REVISION_V1 (0x00010000)
> ++ //
> ++ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ //
> ++ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size
> ++ //
> ++ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ //
> ++ // The partition entries should all be before the first usable block
> ++ //
> ++ if (PrimaryHeader->FirstUsableLBA <= PrimaryHeader->PartitionEntryLBA) {
> ++ DEBUG ((DEBUG_ERROR, "GPT PartitionEntryLBA is not less than FirstUsableLBA!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ //
> ++ // Check that the PartitionEntryLBA greater than the Max LBA
> ++ // This will be used later for multiplication
> ++ //
> ++ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ //
> ++ // Check that the number of partition entries is greater than zero
> ++ //
> ++ if (PrimaryHeader->NumberOfPartitionEntries == 0) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ //
> ++ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory
> ++ //
> ++ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) {
> ++ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ //
> ++ // This check is to prevent overflow when calculating the allocation size for the partition entries
> ++ // This check will be used later for multiplication
> ++ //
> ++ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ return EFI_SUCCESS;
> ++}
> ++
> ++/**
> ++ This function will validate that the allocation size from the primary header is sane
> ++ It will check the following:
> ++ - AllocationSize does not overflow
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[out] AllocationSize
> ++ Pointer to the allocation size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The allocation size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ The allocation size is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizePrimaryHeaderAllocationSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ OUT UINT32 *AllocationSize
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++
> ++ if (PrimaryHeader == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ if (AllocationSize == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ //
> ++ // Replacing logic:
> ++ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry;
> ++ //
> ++ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n"));
> ++ return EFI_BAD_BUFFER_SIZE;
> ++ }
> ++
> ++ return EFI_SUCCESS;
> ++}
> ++
> ++/**
> ++ This function will validate that the Gpt Event Size calculated from the primary header is sane
> ++ It will check the following:
> ++ - EventSize does not overflow
> ++
> ++ Important: This function includes the entire length of the allocated space, including
> ++ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this
> ++ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event))
> ++ from the size of the buffer before hashing.
> ++
> ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++ @param[in] NumberOfPartition - Number of partitions.
> ++ @param[out] EventSize - Pointer to the event size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The event size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ Overflow would have occurred.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ One of the passed parameters was invalid.
> ++**/
> ++EFI_STATUS
> ++SanitizePrimaryHeaderGptEventSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN UINTN NumberOfPartition,
> ++ OUT UINT32 *EventSize
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++ UINT32 SafeNumberOfPartitions;
> ++
> ++ if (PrimaryHeader == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ if (EventSize == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ //
> ++ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32
> ++ //
> ++ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n"));
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ //
> ++ // Replacing logic:
> ++ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry);
> ++ //
> ++ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n"));
> ++ return EFI_BAD_BUFFER_SIZE;
> ++ }
> ++
> ++ //
> ++ // Replacing logic:
> ++ // *EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event);
> ++ //
> ++ Status = SafeUint32Add (
> ++ OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions),
> ++ *EventSize,
> ++ EventSize
> ++ );
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n"));
> ++ return EFI_BAD_BUFFER_SIZE;
> ++ }
> ++
> ++ return EFI_SUCCESS;
> ++}
> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h
> +new file mode 100644
> +index 0000000000..048b738987
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h
> +@@ -0,0 +1,113 @@
> ++/** @file
> ++ This file includes the function prototypes for the sanitization functions.
> ++
> ++ These are those functions:
> ++
> ++ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content
> ++ read is within the image buffer.
> ++
> ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse
> ++ partition data carefully.
> ++
> ++ Copyright (c) Microsoft Corporation.<BR>
> ++ SPDX-License-Identifier: BSD-2-Clause-Patent
> ++
> ++**/
> ++
> ++#ifndef DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_
> ++#define DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_
> ++
> ++#include <Uefi.h>
> ++#include <Uefi/UefiSpec.h>
> ++#include <Protocol/BlockIo.h>
> ++#include <IndustryStandard/UefiTcgPlatform.h>
> ++#include <Protocol/Tcg2Protocol.h>
> ++
> ++/**
> ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse
> ++ However this function will not attempt to verify the validity of the GPT partition
> ++ It will check the following:
> ++ - Signature
> ++ - Revision
> ++ - AlternateLBA
> ++ - FirstUsableLBA
> ++ - LastUsableLBA
> ++ - PartitionEntryLBA
> ++ - NumberOfPartitionEntries
> ++ - SizeOfPartitionEntry
> ++ - BlockIo
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[in] BlockIo
> ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure.
> ++
> ++ @retval EFI_SUCCESS
> ++ The EFI_PARTITION_TABLE_HEADER structure is valid.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ The EFI_PARTITION_TABLE_HEADER structure is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizeEfiPartitionTableHeader (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo
> ++ );
> ++
> ++/**
> ++ This function will validate that the allocation size from the primary header is sane
> ++ It will check the following:
> ++ - AllocationSize does not overflow
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[out] AllocationSize
> ++ Pointer to the allocation size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The allocation size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ The allocation size is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizePrimaryHeaderAllocationSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ OUT UINT32 *AllocationSize
> ++ );
> ++
> ++/**
> ++ This function will validate that the Gpt Event Size calculated from the primary header is sane
> ++ It will check the following:
> ++ - EventSize does not overflow
> ++
> ++ Important: This function includes the entire length of the allocated space, including
> ++ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this
> ++ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event))
> ++ from the size of the buffer before hashing.
> ++
> ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++ @param[in] NumberOfPartition - Number of partitions.
> ++ @param[out] EventSize - Pointer to the event size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The event size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ Overflow would have occurred.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ One of the passed parameters was invalid.
> ++**/
> ++EFI_STATUS
> ++SanitizePrimaryHeaderGptEventSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN UINTN NumberOfPartition,
> ++ OUT UINT32 *EventSize
> ++ );
> ++
> ++#endif // DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_
> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c
> +new file mode 100644
> +index 0000000000..3eb9763e3c
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c
> +@@ -0,0 +1,303 @@
> ++/** @file
> ++ This file includes the unit test cases for the DxeTpm2MeasureBootLibSanitizationTest.c.
> ++
> ++ Copyright (c) Microsoft Corporation.<BR>
> ++ SPDX-License-Identifier: BSD-2-Clause-Patent
> ++**/
> ++
> ++#include <Uefi.h>
> ++#include <Library/UefiLib.h>
> ++#include <Library/DebugLib.h>
> ++#include <Library/UnitTestLib.h>
> ++#include <Protocol/BlockIo.h>
> ++#include <Library/MemoryAllocationLib.h>
> ++#include <Library/BaseMemoryLib.h>
> ++#include <IndustryStandard/UefiTcgPlatform.h>
> ++#include <Protocol/Tcg2Protocol.h>
> ++
> ++#include "../DxeTpm2MeasureBootLibSanitization.h"
> ++
> ++#define UNIT_TEST_NAME "DxeTpm2MeasureBootLibSanitizationTest"
> ++#define UNIT_TEST_VERSION "1.0"
> ++
> ++#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000
> ++#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1
> ++#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128
> ++
> ++/**
> ++ This function tests the SanitizeEfiPartitionTableHeader function.
> ++ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER
> ++ structure will not cause undefined or unexpected behavior.
> ++
> ++ In general the TPM should still be able to measure the data, but
> ++ be the header should be sanitized to prevent any unexpected behavior.
> ++
> ++ @param[in] Context The unit test context.
> ++
> ++ @retval UNIT_TEST_PASSED The test passed.
> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
> ++**/
> ++UNIT_TEST_STATUS
> ++EFIAPI
> ++TestSanitizeEfiPartitionTableHeader (
> ++ IN UNIT_TEST_CONTEXT Context
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
> ++ EFI_BLOCK_IO_PROTOCOL BlockIo;
> ++ EFI_BLOCK_IO_MEDIA BlockMedia;
> ++
> ++ // Generate EFI_BLOCK_IO_MEDIA test data
> ++ BlockMedia.MediaId = 1;
> ++ BlockMedia.RemovableMedia = FALSE;
> ++ BlockMedia.MediaPresent = TRUE;
> ++ BlockMedia.LogicalPartition = FALSE;
> ++ BlockMedia.ReadOnly = FALSE;
> ++ BlockMedia.WriteCaching = FALSE;
> ++ BlockMedia.BlockSize = 512;
> ++ BlockMedia.IoAlign = 1;
> ++ BlockMedia.LastBlock = 0;
> ++
> ++ // Generate EFI_BLOCK_IO_PROTOCOL test data
> ++ BlockIo.Revision = 1;
> ++ BlockIo.Media = &BlockMedia;
> ++ BlockIo.Reset = NULL;
> ++ BlockIo.ReadBlocks = NULL;
> ++ BlockIo.WriteBlocks = NULL;
> ++ BlockIo.FlushBlocks = NULL;
> ++
> ++ // Geneate EFI_PARTITION_TABLE_HEADER test data
> ++ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID;
> ++ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION;
> ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER);
> ++ PrimaryHeader.MyLBA = 1;
> ++ PrimaryHeader.AlternateLBA = 2;
> ++ PrimaryHeader.FirstUsableLBA = 3;
> ++ PrimaryHeader.LastUsableLBA = 4;
> ++ PrimaryHeader.PartitionEntryLBA = 5;
> ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES;
> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid
> ++
> ++ // Calculate the CRC32 of the PrimaryHeader
> ++ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize);
> ++
> ++ // Test that a normal PrimaryHeader passes validation
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_NOT_EFI_ERROR (Status);
> ++
> ++ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR
> ++ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!""
> ++ PrimaryHeader.NumberOfPartitionEntries = 0;
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
> ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++
> ++ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR
> ++ // Should print "Invalid Partition Table Header Size!"
> ++ PrimaryHeader.Header.HeaderSize = 0;
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
> ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER);
> ++
> ++ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR
> ++ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!"
> ++ PrimaryHeader.SizeOfPartitionEntry = 1;
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
> ++
> ++ return UNIT_TEST_PASSED;
> ++}
> ++
> ++/**
> ++ This function tests the SanitizePrimaryHeaderAllocationSize function.
> ++ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER
> ++ structure will not cause an overflow when calculating the allocation size.
> ++
> ++ @param[in] Context The unit test context.
> ++
> ++ @retval UNIT_TEST_PASSED The test passed.
> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
> ++**/
> ++UNIT_TEST_STATUS
> ++EFIAPI
> ++TestSanitizePrimaryHeaderAllocationSize (
> ++ IN UNIT_TEST_CONTEXT Context
> ++ )
> ++{
> ++ UINT32 AllocationSize;
> ++
> ++ EFI_STATUS Status;
> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
> ++
> ++ // Test that a normal PrimaryHeader passes validation
> ++ PrimaryHeader.NumberOfPartitionEntries = 5;
> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_NOT_EFI_ERROR (Status);
> ++
> ++ // Test that the allocation size is correct compared to the existing logic
> ++ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry);
> ++
> ++ // Test that an overflow is detected
> ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32;
> ++ PrimaryHeader.SizeOfPartitionEntry = 5;
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ // Test the inverse
> ++ PrimaryHeader.NumberOfPartitionEntries = 5;
> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ // Test the worst case scenario
> ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32;
> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
> ++
> ++ return UNIT_TEST_PASSED;
> ++}
> ++
> ++/**
> ++ This function tests the SanitizePrimaryHeaderGptEventSize function.
> ++ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure
> ++ will not cause an overflow when calculating the event size.
> ++
> ++ @param[in] Context The unit test context.
> ++
> ++ @retval UNIT_TEST_PASSED The test passed.
> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
> ++**/
> ++UNIT_TEST_STATUS
> ++EFIAPI
> ++TestSanitizePrimaryHeaderGptEventSize (
> ++ IN UNIT_TEST_CONTEXT Context
> ++ )
> ++{
> ++ UINT32 EventSize;
> ++ UINT32 ExistingLogicEventSize;
> ++ EFI_STATUS Status;
> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
> ++ UINTN NumberOfPartition;
> ++ EFI_GPT_DATA *GptData;
> ++ EFI_TCG2_EVENT *Tcg2Event;
> ++
> ++ Tcg2Event = NULL;
> ++ GptData = NULL;
> ++
> ++ // Test that a normal PrimaryHeader passes validation
> ++ PrimaryHeader.NumberOfPartitionEntries = 5;
> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++
> ++ // set the number of partitions
> ++ NumberOfPartition = 13;
> ++
> ++ // that the primary event size is correct
> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize);
> ++ UT_ASSERT_NOT_EFI_ERROR (Status);
> ++
> ++ // Calculate the existing logic event size
> ++ ExistingLogicEventSize = (UINT32)(OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions)
> ++ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry);
> ++
> ++ // Check that the event size is correct
> ++ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize);
> ++
> ++ // Tests that the primary event size may not overflow
> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ // Test that the size of partition entries may not overflow
> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
> ++
> ++ return UNIT_TEST_PASSED;
> ++}
> ++
> ++// *--------------------------------------------------------------------*
> ++// * Unit Test Code Main Function
> ++// *--------------------------------------------------------------------*
> ++
> ++/**
> ++ This function acts as the entry point for the unit tests.
> ++
> ++ @retval UNIT_TEST_PASSED The test passed.
> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
> ++ @retval others The test failed.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++UefiTestMain (
> ++ VOID
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++ UNIT_TEST_FRAMEWORK_HANDLE Framework;
> ++ UNIT_TEST_SUITE_HANDLE Tcg2MeasureBootLibValidationTestSuite;
> ++
> ++ Framework = NULL;
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME));
> ++
> ++ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status));
> ++ goto EXIT;
> ++ }
> ++
> ++ Status = CreateUnitTestSuite (&Tcg2MeasureBootLibValidationTestSuite, Framework, "Tcg2MeasureBootLibValidationTestSuite", "Common.Tcg2MeasureBootLibValidation", NULL, NULL);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for Tcg2MeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME));
> ++ Status = EFI_OUT_OF_RESOURCES;
> ++ goto EXIT;
> ++ }
> ++
> ++ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context
> ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.Tcg2MeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL);
> ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL);
> ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL);
> ++
> ++ Status = RunAllTestSuites (Framework);
> ++
> ++EXIT:
> ++ if (Framework != NULL) {
> ++ FreeUnitTestFramework (Framework);
> ++ }
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME));
> ++ return Status;
> ++}
> ++
> ++///
> ++/// Avoid ECC error for function name that starts with lower case letter
> ++///
> ++#define DxeTpm2MeasureBootLibUnitTestMain main
> ++
> ++/**
> ++ Standard POSIX C entry point for host based unit test execution.
> ++
> ++ @param[in] Argc Number of arguments
> ++ @param[in] Argv Array of pointers to arguments
> ++
> ++ @retval 0 Success
> ++ @retval other Error
> ++**/
> ++INT32
> ++DxeTpm2MeasureBootLibUnitTestMain (
> ++ IN INT32 Argc,
> ++ IN CHAR8 *Argv[]
> ++ )
> ++{
> ++ return (INT32)UefiTestMain ();
> ++}
> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf
> +new file mode 100644
> +index 0000000000..2999aa2a44
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf
> +@@ -0,0 +1,28 @@
> ++## @file
> ++# This file builds the unit tests for DxeTpm2MeasureBootLib
> ++#
> ++# Copyright (C) Microsoft Corporation.<BR>
> ++# SPDX-License-Identifier: BSD-2-Clause-Patent
> ++##
> ++
> ++[Defines]
> ++ INF_VERSION = 0x00010006
> ++ BASE_NAME = DxeTpm2MeasuredBootLibTest
> ++ FILE_GUID = 144d757f-d423-484e-9309-a23695fad5bd
> ++ MODULE_TYPE = HOST_APPLICATION
> ++ VERSION_STRING = 1.0
> ++ ENTRY_POINT = main
> ++
> ++[Sources]
> ++ DxeTpm2MeasureBootLibSanitizationTest.c
> ++ ../DxeTpm2MeasureBootLibSanitization.c
> ++
> ++[Packages]
> ++ MdePkg/MdePkg.dec
> ++
> ++[LibraryClasses]
> ++ BaseLib
> ++ DebugLib
> ++ UnitTestLib
> ++ PrintLib
> ++ SafeIntLib
> +diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml
> +index 7912142398..da811fdf93 100644
> +--- a/SecurityPkg/SecurityPkg.ci.yaml
> ++++ b/SecurityPkg/SecurityPkg.ci.yaml
> +@@ -15,6 +15,7 @@
> + ## "<ErrorID>", "<KeyWord>"
> + ## ]
> + "ExceptionList": [
> ++ "8001", "DxeTpm2MeasureBootLibUnitTestMain",
> + ],
> + ## Both file path and directory path are accepted.
> + "IgnoreFiles": [
> +--
> +2.40.0
> +
> diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch
> new file mode 100644
> index 0000000000..6c20cc305e
> --- /dev/null
> +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch
> @@ -0,0 +1,889 @@
> +From 4776a1b39ee08fc45c70c1eab5a0195f325000d3 Mon Sep 17 00:00:00 2001
> +From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com>
> +Date: Fri, 12 Jan 2024 02:16:02 +0800
> +Subject: [PATCH] SecurityPkg: DxeTpmMeasureBootLib: SECURITY PATCH 4117 - CVE
> + 2022-36763
> +
> +This commit contains the patch files and tests for DxeTpmMeasureBootLib
> +CVE 2022-36763.
> +
> +Cc: Jiewen Yao <jiewen.yao@intel.com>
> +
> +Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com>
> +Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
> +
> +CVE: CVE-2022-36763
> +
> +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/4776a1b39ee08fc45c70c1eab5a0195f325000d3]
> +
> +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
> +---
> + .../DxeTpmMeasureBootLib.c | 40 ++-
> + .../DxeTpmMeasureBootLib.inf | 4 +-
> + .../DxeTpmMeasureBootLibSanitization.c | 241 ++++++++++++++
> + .../DxeTpmMeasureBootLibSanitization.h | 114 +++++++
> + .../DxeTpmMeasureBootLibSanitizationTest.c | 301 ++++++++++++++++++
> + ...eTpmMeasureBootLibSanitizationTestHost.inf | 28 ++
> + SecurityPkg/SecurityPkg.ci.yaml | 1 +
> + 7 files changed, 715 insertions(+), 14 deletions(-)
> + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c
> + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h
> + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c
> + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf
> +
> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
> +index 220393dd2b..669ab19134 100644
> +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
> +@@ -18,6 +18,8 @@
> + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> ++Copyright (c) Microsoft Corporation.<BR>
> ++SPDX-License-Identifier: BSD-2-Clause-Patent
> + **/
> +
> + #include <PiDxe.h>
> +@@ -40,6 +42,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> + #include <Library/SecurityManagementLib.h>
> + #include <Library/HobLib.h>
> +
> ++#include "DxeTpmMeasureBootLibSanitization.h"
> ++
> + //
> + // Flag to check GPT partition. It only need be measured once.
> + //
> +@@ -136,6 +140,9 @@ TcgMeasureGptTable (
> + UINT32 EventSize;
> + UINT32 EventNumber;
> + EFI_PHYSICAL_ADDRESS EventLogLastEntry;
> ++ UINT32 AllocSize;
> ++
> ++ GptData = NULL;
> +
> + if (mMeasureGptCount > 0) {
> + return EFI_SUCCESS;
> +@@ -166,8 +173,8 @@ TcgMeasureGptTable (
> + BlockIo->Media->BlockSize,
> + (UINT8 *)PrimaryHeader
> + );
> +- if (EFI_ERROR (Status)) {
> +- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n"));
> ++ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) {
> ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n"));
> + FreePool (PrimaryHeader);
> + return EFI_DEVICE_ERROR;
> + }
> +@@ -175,7 +182,13 @@ TcgMeasureGptTable (
> + //
> + // Read the partition entry.
> + //
> +- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
> ++ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize);
> ++ if (EFI_ERROR (Status)) {
> ++ FreePool (PrimaryHeader);
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize);
> + if (EntryPtr == NULL) {
> + FreePool (PrimaryHeader);
> + return EFI_OUT_OF_RESOURCES;
> +@@ -185,7 +198,7 @@ TcgMeasureGptTable (
> + DiskIo,
> + BlockIo->Media->MediaId,
> + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
> +- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry,
> ++ AllocSize,
> + EntryPtr
> + );
> + if (EFI_ERROR (Status)) {
> +@@ -210,9 +223,8 @@ TcgMeasureGptTable (
> + //
> + // Prepare Data for Measurement
> + //
> +- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions)
> +- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);
> +- TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT_HDR));
> ++ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &EventSize);
> ++ TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize);
> + if (TcgEvent == NULL) {
> + FreePool (PrimaryHeader);
> + FreePool (EntryPtr);
> +@@ -221,7 +233,7 @@ TcgMeasureGptTable (
> +
> + TcgEvent->PCRIndex = 5;
> + TcgEvent->EventType = EV_EFI_GPT_EVENT;
> +- TcgEvent->EventSize = EventSize;
> ++ TcgEvent->EventSize = EventSize - sizeof (TCG_PCR_EVENT_HDR);
> + GptData = (EFI_GPT_DATA *)TcgEvent->Event;
> +
> + //
> +@@ -361,11 +373,13 @@ TcgMeasurePeImage (
> + TcgEvent->PCRIndex = 2;
> + break;
> + default:
> +- DEBUG ((
> +- DEBUG_ERROR,
> +- "TcgMeasurePeImage: Unknown subsystem type %d",
> +- ImageType
> +- ));
> ++ DEBUG (
> ++ (
> ++ DEBUG_ERROR,
> ++ "TcgMeasurePeImage: Unknown subsystem type %d",
> ++ ImageType
> ++ )
> ++ );
> + goto Finish;
> + }
> +
> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
> +index ebab6f7c1e..414c654d15 100644
> +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
> +@@ -32,6 +32,8 @@
> +
> + [Sources]
> + DxeTpmMeasureBootLib.c
> ++ DxeTpmMeasureBootLibSanitization.c
> ++ DxeTpmMeasureBootLibSanitization.h
> +
> + [Packages]
> + MdePkg/MdePkg.dec
> +@@ -41,6 +43,7 @@
> +
> + [LibraryClasses]
> + BaseMemoryLib
> ++ SafeIntLib
> + DebugLib
> + MemoryAllocationLib
> + DevicePathLib
> +@@ -59,4 +62,3 @@
> + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES
> + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
> + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES
> +-
> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c
> +new file mode 100644
> +index 0000000000..a3fa46f5e6
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c
> +@@ -0,0 +1,241 @@
> ++/** @file
> ++ The library instance provides security service of TPM2 measure boot and
> ++ Confidential Computing (CC) 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.
> ++
> ++ This file will pull out the validation logic from the following functions, in an
> ++ attempt to validate the untrusted input in the form of unit tests
> ++
> ++ These are those functions:
> ++
> ++ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content
> ++ read is within the image buffer.
> ++
> ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse
> ++ partition data carefully.
> ++
> ++ Copyright (c) Microsoft Corporation.<BR>
> ++ SPDX-License-Identifier: BSD-2-Clause-Patent
> ++**/
> ++#include <Uefi.h>
> ++#include <Uefi/UefiSpec.h>
> ++#include <Library/SafeIntLib.h>
> ++#include <Library/UefiLib.h>
> ++#include <Library/DebugLib.h>
> ++#include <Library/BaseLib.h>
> ++#include <IndustryStandard/UefiTcgPlatform.h>
> ++#include <Protocol/BlockIo.h>
> ++#include <Library/MemoryAllocationLib.h>
> ++
> ++#include "DxeTpmMeasureBootLibSanitization.h"
> ++
> ++#define GPT_HEADER_REVISION_V1 0x00010000
> ++
> ++/**
> ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse
> ++ However this function will not attempt to verify the validity of the GPT partition
> ++ It will check the following:
> ++ - Signature
> ++ - Revision
> ++ - AlternateLBA
> ++ - FirstUsableLBA
> ++ - LastUsableLBA
> ++ - PartitionEntryLBA
> ++ - NumberOfPartitionEntries
> ++ - SizeOfPartitionEntry
> ++ - BlockIo
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[in] BlockIo
> ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure.
> ++
> ++ @retval EFI_SUCCESS
> ++ The EFI_PARTITION_TABLE_HEADER structure is valid.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ The EFI_PARTITION_TABLE_HEADER structure is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizeEfiPartitionTableHeader (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo
> ++ )
> ++{
> ++ // Verify that the input parameters are safe to use
> ++ if (PrimaryHeader == NULL) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n"));
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII)
> ++ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ // The version must be GPT_HEADER_REVISION_V1 (0x00010000)
> ++ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size
> ++ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ // check that the PartitionEntryLBA greater than the Max LBA
> ++ // This will be used later for multiplication
> ++ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ // Check that the number of partition entries is greater than zero
> ++ if (PrimaryHeader->NumberOfPartitionEntries == 0) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory
> ++ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) {
> ++ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ // This check is to prevent overflow when calculating the allocation size for the partition entries
> ++ // This check will be used later for multiplication
> ++ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) {
> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
> ++ return EFI_DEVICE_ERROR;
> ++ }
> ++
> ++ return EFI_SUCCESS;
> ++}
> ++
> ++/**
> ++ This function will validate that the allocation size from the primary header is sane
> ++ It will check the following:
> ++ - AllocationSize does not overflow
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[out] AllocationSize
> ++ Pointer to the allocation size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The allocation size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ The allocation size is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizePrimaryHeaderAllocationSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ OUT UINT32 *AllocationSize
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++
> ++ if (PrimaryHeader == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ if (AllocationSize == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ // Replacing logic:
> ++ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry;
> ++ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n"));
> ++ return EFI_BAD_BUFFER_SIZE;
> ++ }
> ++
> ++ return EFI_SUCCESS;
> ++}
> ++
> ++/**
> ++ This function will validate that the Gpt Event Size calculated from the primary header is sane
> ++ It will check the following:
> ++ - EventSize does not overflow
> ++
> ++ Important: This function includes the entire length of the allocated space, including the
> ++ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract
> ++ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing.
> ++
> ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++ @param[in] NumberOfPartition - Number of partitions.
> ++ @param[out] EventSize - Pointer to the event size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The event size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ Overflow would have occurred.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ One of the passed parameters was invalid.
> ++**/
> ++EFI_STATUS
> ++SanitizePrimaryHeaderGptEventSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN UINTN NumberOfPartition,
> ++ OUT UINT32 *EventSize
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++ UINT32 SafeNumberOfPartitions;
> ++
> ++ if (PrimaryHeader == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ if (EventSize == NULL) {
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32
> ++ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n"));
> ++ return EFI_INVALID_PARAMETER;
> ++ }
> ++
> ++ // Replacing logic:
> ++ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry + sizeof (TCG_PCR_EVENT_HDR));
> ++ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n"));
> ++ return EFI_BAD_BUFFER_SIZE;
> ++ }
> ++
> ++ Status = SafeUint32Add (
> ++ sizeof (TCG_PCR_EVENT_HDR) +
> ++ OFFSET_OF (EFI_GPT_DATA, Partitions),
> ++ *EventSize,
> ++ EventSize
> ++ );
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n"));
> ++ return EFI_BAD_BUFFER_SIZE;
> ++ }
> ++
> ++ return EFI_SUCCESS;
> ++}
> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h
> +new file mode 100644
> +index 0000000000..0d9d00c281
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h
> +@@ -0,0 +1,114 @@
> ++/** @file
> ++ This file includes the function prototypes for the sanitization functions.
> ++
> ++ These are those functions:
> ++
> ++ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content
> ++ read is within the image buffer.
> ++
> ++ TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its
> ++ data structure within this image buffer before use.
> ++
> ++ TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse
> ++ partition data carefully.
> ++
> ++ Copyright (c) Microsoft Corporation.<BR>
> ++ SPDX-License-Identifier: BSD-2-Clause-Patent
> ++
> ++**/
> ++
> ++#ifndef DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_
> ++#define DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_
> ++
> ++#include <Uefi.h>
> ++#include <Uefi/UefiSpec.h>
> ++#include <Protocol/BlockIo.h>
> ++#include <IndustryStandard/UefiTcgPlatform.h>
> ++
> ++/**
> ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse
> ++ However this function will not attempt to verify the validity of the GPT partition
> ++ It will check the following:
> ++ - Signature
> ++ - Revision
> ++ - AlternateLBA
> ++ - FirstUsableLBA
> ++ - LastUsableLBA
> ++ - PartitionEntryLBA
> ++ - NumberOfPartitionEntries
> ++ - SizeOfPartitionEntry
> ++ - BlockIo
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[in] BlockIo
> ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure.
> ++
> ++ @retval EFI_SUCCESS
> ++ The EFI_PARTITION_TABLE_HEADER structure is valid.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ The EFI_PARTITION_TABLE_HEADER structure is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizeEfiPartitionTableHeader (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo
> ++ );
> ++
> ++/**
> ++ This function will validate that the allocation size from the primary header is sane
> ++ It will check the following:
> ++ - AllocationSize does not overflow
> ++
> ++ @param[in] PrimaryHeader
> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++
> ++ @param[out] AllocationSize
> ++ Pointer to the allocation size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The allocation size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ The allocation size is invalid.
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++SanitizePrimaryHeaderAllocationSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ OUT UINT32 *AllocationSize
> ++ );
> ++
> ++/**
> ++ This function will validate that the Gpt Event Size calculated from the primary header is sane
> ++ It will check the following:
> ++ - EventSize does not overflow
> ++
> ++ Important: This function includes the entire length of the allocated space, including the
> ++ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract
> ++ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing.
> ++
> ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure.
> ++ @param[in] NumberOfPartition - Number of partitions.
> ++ @param[out] EventSize - Pointer to the event size.
> ++
> ++ @retval EFI_SUCCESS
> ++ The event size is valid.
> ++
> ++ @retval EFI_OUT_OF_RESOURCES
> ++ Overflow would have occurred.
> ++
> ++ @retval EFI_INVALID_PARAMETER
> ++ One of the passed parameters was invalid.
> ++**/
> ++EFI_STATUS
> ++SanitizePrimaryHeaderGptEventSize (
> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
> ++ IN UINTN NumberOfPartition,
> ++ OUT UINT32 *EventSize
> ++ );
> ++
> ++#endif // DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_
> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c
> +new file mode 100644
> +index 0000000000..eeb928cdb0
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c
> +@@ -0,0 +1,301 @@
> ++/** @file
> ++This file includes the unit test cases for the DxeTpmMeasureBootLibSanitizationTest.c.
> ++
> ++Copyright (c) Microsoft Corporation.<BR>
> ++SPDX-License-Identifier: BSD-2-Clause-Patent
> ++**/
> ++
> ++#include <Uefi.h>
> ++#include <Library/UefiLib.h>
> ++#include <Library/DebugLib.h>
> ++#include <Library/UnitTestLib.h>
> ++#include <Protocol/BlockIo.h>
> ++#include <Library/MemoryAllocationLib.h>
> ++#include <Library/BaseMemoryLib.h>
> ++#include <IndustryStandard/UefiTcgPlatform.h>
> ++
> ++#include "../DxeTpmMeasureBootLibSanitization.h"
> ++
> ++#define UNIT_TEST_NAME "DxeTpmMeasureBootLibSanitizationTest"
> ++#define UNIT_TEST_VERSION "1.0"
> ++
> ++#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000
> ++#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1
> ++#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128
> ++
> ++/**
> ++ This function tests the SanitizeEfiPartitionTableHeader function.
> ++ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER
> ++ structure will not cause undefined or unexpected behavior.
> ++
> ++ In general the TPM should still be able to measure the data, but
> ++ be the header should be sanitized to prevent any unexpected behavior.
> ++
> ++ @param[in] Context The unit test context.
> ++
> ++ @retval UNIT_TEST_PASSED The test passed.
> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
> ++**/
> ++UNIT_TEST_STATUS
> ++EFIAPI
> ++TestSanitizeEfiPartitionTableHeader (
> ++ IN UNIT_TEST_CONTEXT Context
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
> ++ EFI_BLOCK_IO_PROTOCOL BlockIo;
> ++ EFI_BLOCK_IO_MEDIA BlockMedia;
> ++
> ++ // Generate EFI_BLOCK_IO_MEDIA test data
> ++ BlockMedia.MediaId = 1;
> ++ BlockMedia.RemovableMedia = FALSE;
> ++ BlockMedia.MediaPresent = TRUE;
> ++ BlockMedia.LogicalPartition = FALSE;
> ++ BlockMedia.ReadOnly = FALSE;
> ++ BlockMedia.WriteCaching = FALSE;
> ++ BlockMedia.BlockSize = 512;
> ++ BlockMedia.IoAlign = 1;
> ++ BlockMedia.LastBlock = 0;
> ++
> ++ // Generate EFI_BLOCK_IO_PROTOCOL test data
> ++ BlockIo.Revision = 1;
> ++ BlockIo.Media = &BlockMedia;
> ++ BlockIo.Reset = NULL;
> ++ BlockIo.ReadBlocks = NULL;
> ++ BlockIo.WriteBlocks = NULL;
> ++ BlockIo.FlushBlocks = NULL;
> ++
> ++ // Geneate EFI_PARTITION_TABLE_HEADER test data
> ++ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID;
> ++ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION;
> ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER);
> ++ PrimaryHeader.MyLBA = 1;
> ++ PrimaryHeader.AlternateLBA = 2;
> ++ PrimaryHeader.FirstUsableLBA = 3;
> ++ PrimaryHeader.LastUsableLBA = 4;
> ++ PrimaryHeader.PartitionEntryLBA = 5;
> ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES;
> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid
> ++
> ++ // Calculate the CRC32 of the PrimaryHeader
> ++ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize);
> ++
> ++ // Test that a normal PrimaryHeader passes validation
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_NOT_EFI_ERROR (Status);
> ++
> ++ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR
> ++ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!""
> ++ PrimaryHeader.NumberOfPartitionEntries = 0;
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
> ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++
> ++ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR
> ++ // Should print "Invalid Partition Table Header Size!"
> ++ PrimaryHeader.Header.HeaderSize = 0;
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
> ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER);
> ++
> ++ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR
> ++ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!"
> ++ PrimaryHeader.SizeOfPartitionEntry = 1;
> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
> ++
> ++ return UNIT_TEST_PASSED;
> ++}
> ++
> ++/**
> ++ This function tests the SanitizePrimaryHeaderAllocationSize function.
> ++ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER
> ++ structure will not cause an overflow when calculating the allocation size.
> ++
> ++ @param[in] Context The unit test context.
> ++
> ++ @retval UNIT_TEST_PASSED The test passed.
> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
> ++**/
> ++UNIT_TEST_STATUS
> ++EFIAPI
> ++TestSanitizePrimaryHeaderAllocationSize (
> ++ IN UNIT_TEST_CONTEXT Context
> ++ )
> ++{
> ++ UINT32 AllocationSize;
> ++
> ++ EFI_STATUS Status;
> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
> ++
> ++ // Test that a normal PrimaryHeader passes validation
> ++ PrimaryHeader.NumberOfPartitionEntries = 5;
> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_NOT_EFI_ERROR (Status);
> ++
> ++ // Test that the allocation size is correct compared to the existing logic
> ++ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry);
> ++
> ++ // Test that an overflow is detected
> ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32;
> ++ PrimaryHeader.SizeOfPartitionEntry = 5;
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ // Test the inverse
> ++ PrimaryHeader.NumberOfPartitionEntries = 5;
> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ // Test the worst case scenario
> ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32;
> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
> ++
> ++ return UNIT_TEST_PASSED;
> ++}
> ++
> ++/**
> ++ This function tests the SanitizePrimaryHeaderGptEventSize function.
> ++ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure
> ++ will not cause an overflow when calculating the event size.
> ++
> ++ @param[in] Context The unit test context.
> ++
> ++ @retval UNIT_TEST_PASSED The test passed.
> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
> ++**/
> ++UNIT_TEST_STATUS
> ++EFIAPI
> ++TestSanitizePrimaryHeaderGptEventSize (
> ++ IN UNIT_TEST_CONTEXT Context
> ++ )
> ++{
> ++ UINT32 EventSize;
> ++ UINT32 ExistingLogicEventSize;
> ++ EFI_STATUS Status;
> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
> ++ UINTN NumberOfPartition;
> ++ EFI_GPT_DATA *GptData;
> ++
> ++ GptData = NULL;
> ++
> ++ // Test that a normal PrimaryHeader passes validation
> ++ PrimaryHeader.NumberOfPartitionEntries = 5;
> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
> ++
> ++ // set the number of partitions
> ++ NumberOfPartition = 13;
> ++
> ++ // that the primary event size is correct
> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize);
> ++ UT_ASSERT_NOT_EFI_ERROR (Status);
> ++
> ++ // Calculate the existing logic event size
> ++ ExistingLogicEventSize = (UINT32)(sizeof (TCG_PCR_EVENT_HDR) + OFFSET_OF (EFI_GPT_DATA, Partitions)
> ++ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry);
> ++
> ++ // Check that the event size is correct
> ++ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize);
> ++
> ++ // Tests that the primary event size may not overflow
> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ // Test that the size of partition entries may not overflow
> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize);
> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
> ++
> ++ return UNIT_TEST_PASSED;
> ++}
> ++
> ++// *--------------------------------------------------------------------*
> ++// * Unit Test Code Main Function
> ++// *--------------------------------------------------------------------*
> ++
> ++/**
> ++ This function acts as the entry point for the unit tests.
> ++
> ++ @param argc - The number of command line arguments
> ++ @param argv - The command line arguments
> ++
> ++ @return int - The status of the test
> ++**/
> ++EFI_STATUS
> ++EFIAPI
> ++UefiTestMain (
> ++ VOID
> ++ )
> ++{
> ++ EFI_STATUS Status;
> ++ UNIT_TEST_FRAMEWORK_HANDLE Framework;
> ++ UNIT_TEST_SUITE_HANDLE TcgMeasureBootLibValidationTestSuite;
> ++
> ++ Framework = NULL;
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME));
> ++
> ++ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status));
> ++ goto EXIT;
> ++ }
> ++
> ++ Status = CreateUnitTestSuite (&TcgMeasureBootLibValidationTestSuite, Framework, "TcgMeasureBootLibValidationTestSuite", "Common.TcgMeasureBootLibValidation", NULL, NULL);
> ++ if (EFI_ERROR (Status)) {
> ++ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for TcgMeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME));
> ++ Status = EFI_OUT_OF_RESOURCES;
> ++ goto EXIT;
> ++ }
> ++
> ++ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context
> ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.TcgMeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL);
> ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL);
> ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL);
> ++
> ++ Status = RunAllTestSuites (Framework);
> ++
> ++EXIT:
> ++ if (Framework != NULL) {
> ++ FreeUnitTestFramework (Framework);
> ++ }
> ++
> ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME));
> ++ return Status;
> ++}
> ++
> ++///
> ++/// Avoid ECC error for function name that starts with lower case letter
> ++///
> ++#define DxeTpmMeasureBootLibUnitTestMain main
> ++
> ++/**
> ++ Standard POSIX C entry point for host based unit test execution.
> ++
> ++ @param[in] Argc Number of arguments
> ++ @param[in] Argv Array of pointers to arguments
> ++
> ++ @retval 0 Success
> ++ @retval other Error
> ++**/
> ++INT32
> ++DxeTpmMeasureBootLibUnitTestMain (
> ++ IN INT32 Argc,
> ++ IN CHAR8 *Argv[]
> ++ )
> ++{
> ++ return (INT32)UefiTestMain ();
> ++}
> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf
> +new file mode 100644
> +index 0000000000..47b0811b00
> +--- /dev/null
> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf
> +@@ -0,0 +1,28 @@
> ++## @file
> ++# This file builds the unit tests for DxeTpmMeasureBootLib
> ++#
> ++# Copyright (C) Microsoft Corporation.<BR>
> ++# SPDX-License-Identifier: BSD-2-Clause-Patent
> ++##
> ++
> ++[Defines]
> ++ INF_VERSION = 0x00010006
> ++ BASE_NAME = DxeTpmMeasuredBootLibTest
> ++ FILE_GUID = eb01bc38-309c-4d3e-967e-9f078c90772f
> ++ MODULE_TYPE = HOST_APPLICATION
> ++ VERSION_STRING = 1.0
> ++ ENTRY_POINT = main
> ++
> ++[Sources]
> ++ DxeTpmMeasureBootLibSanitizationTest.c
> ++ ../DxeTpmMeasureBootLibSanitization.c
> ++
> ++[Packages]
> ++ MdePkg/MdePkg.dec
> ++
> ++[LibraryClasses]
> ++ BaseLib
> ++ DebugLib
> ++ UnitTestLib
> ++ PrintLib
> ++ SafeIntLib
> +diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml
> +index da811fdf93..0e40eaa0fe 100644
> +--- a/SecurityPkg/SecurityPkg.ci.yaml
> ++++ b/SecurityPkg/SecurityPkg.ci.yaml
> +@@ -16,6 +16,7 @@
> + ## ]
> + "ExceptionList": [
> + "8001", "DxeTpm2MeasureBootLibUnitTestMain",
> ++ "8001", "DxeTpmMeasureBootLibUnitTestMain"
> + ],
> + ## Both file path and directory path are accepted.
> + "IgnoreFiles": [
> +--
> +2.40.0
> +
> diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch
> new file mode 100644
> index 0000000000..59bd5c4910
> --- /dev/null
> +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch
> @@ -0,0 +1,55 @@
> +From 1ddcb9fc6b4164e882687b031e8beacfcf7df29e Mon Sep 17 00:00:00 2001
> +From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com>
> +Date: Fri, 12 Jan 2024 02:16:03 +0800
> +Subject: [PATCH] SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml
> +
> +This creates / adds a security file that tracks the security fixes
> +found in this package and can be used to find the fixes that were
> +applied.
> +
> +Cc: Jiewen Yao <jiewen.yao@intel.com>
> +
> +Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com>
> +Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
> +
> +CVE: CVE-2022-36763
> +
> +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1ddcb9fc6b4164e882687b031e8beacfcf7df29e]
> +
> +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
> +---
> + SecurityPkg/SecurityFixes.yaml | 22 ++++++++++++++++++++++
> + 1 file changed, 22 insertions(+)
> + create mode 100644 SecurityPkg/SecurityFixes.yaml
> +
> +diff --git a/SecurityPkg/SecurityFixes.yaml b/SecurityPkg/SecurityFixes.yaml
> +new file mode 100644
> +index 0000000000..f9e3e7be74
> +--- /dev/null
> ++++ b/SecurityPkg/SecurityFixes.yaml
> +@@ -0,0 +1,22 @@
> ++## @file
> ++# Security Fixes for SecurityPkg
> ++#
> ++# Copyright (c) Microsoft Corporation
> ++# SPDX-License-Identifier: BSD-2-Clause-Patent
> ++##
> ++CVE_2022_36763:
> ++ commit_titles:
> ++ - "SecurityPkg: DxeTpm2Measurement: SECURITY PATCH 4117 - CVE 2022-36763"
> ++ - "SecurityPkg: DxeTpmMeasurement: SECURITY PATCH 4117 - CVE 2022-36763"
> ++ - "SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml"
> ++ cve: CVE-2022-36763
> ++ date_reported: 2022-10-25 11:31 UTC
> ++ description: (CVE-2022-36763) - Heap Buffer Overflow in Tcg2MeasureGptTable()
> ++ note: This patch is related to and supersedes TCBZ2168
> ++ files_impacted:
> ++ - Library\DxeTpm2MeasureBootLib\DxeTpm2MeasureBootLib.c
> ++ - Library\DxeTpmMeasureBootLib\DxeTpmMeasureBootLib.c
> ++ links:
> ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4117
> ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=2168
> ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=1990
> +--
> +2.40.0
> +
> diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb
> index 84e3360a3a..78d86ad879 100644
> --- a/meta/recipes-core/ovmf/ovmf_git.bb
> +++ b/meta/recipes-core/ovmf/ovmf_git.bb
> @@ -27,6 +27,9 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \
> file://0006-reproducible.patch \
> file://0001-BaseTools-fix-gcc12-warning.patch \
> file://0001-BaseTools-fix-gcc12-warning-1.patch \
> + file://CVE-2022-36763-0001.patch \
> + file://CVE-2022-36763-0002.patch \
> + file://CVE-2022-36763-0003.patch \
> "
>
> PV = "edk2-stable202202"
> --
> 2.25.1
>
On Thu, Nov 28, 2024 at 12:15 AM Jia, Hongxu <Hongxu.Jia@windriver.com> wrote: > > Hi Steve, > > I am afraid the issue was caused by CR("^M") in ovmf source code > > The source of ovmf use CR (^M) as new line, we should use 'git am --keep-cr xxxx.patch' to apply the patch, > otherwise do_patch failed > > But I do not know how you apply the patch to your build or via patchtest automatically, do you use git am with option --keep-cr? I download the patch from patchworks using the "mbox" button and the apply it like this: $ git am --keep-cr ~/Downloads/kirkstone-V2-01-13-ovmf-Fix-CVE-2022-36763.patch Applying: ovmf: Fix CVE-2022-36763 .git/rebase-apply/patch:56: trailing whitespace. .git/rebase-apply/patch:60: trailing whitespace. .git/rebase-apply/patch:65: trailing whitespace. .git/rebase-apply/patch:81: trailing whitespace. .git/rebase-apply/patch:95: trailing whitespace. warning: squelched 27 whitespace errors warning: 32 lines add whitespace errors. $ bitbake ovmf Loading cache: 100% | | ETA: --:--:-- <snip> NOTE: Executing Tasks ERROR: ovmf-edk2-stable202202-r0 do_patch: Applying patch 'CVE-2022-36763-0001.patch' on target directory '/home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/git' CmdError('quilt --quiltrc /home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/recipe-sysroot-native/etc/quiltrc push', 0, 'stdout: Applying patch CVE-2022-36763-0001.patch patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c Hunk #1 FAILED at 20 (different line endings). Hunk #2 FAILED at 44 (different line endings). Hunk #3 FAILED at 144 (different line endings). Hunk #4 FAILED at 195 (different line endings). Hunk #5 FAILED at 223 (different line endings). Hunk #6 FAILED at 248 (different line endings). Hunk #7 FAILED at 310 (different line endings). Hunk #8 FAILED at 326 (different line endings). Hunk #9 FAILED at 443 (different line endings). Hunk #10 FAILED at 515 (different line endings). Hunk #11 FAILED at 646 (different line endings). 11 out of 11 hunks FAILED -- rejects in file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf Hunk #1 FAILED at 37 (different line endings). Hunk #2 FAILED at 46 (different line endings). Hunk #3 FAILED at 65 (different line endings). 3 out of 3 hunks FAILED -- rejects in file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf patching file SecurityPkg/SecurityPkg.ci.yaml Hunk #1 FAILED at 15 (different line endings). 1 out of 1 hunk FAILED -- rejects in file SecurityPkg/SecurityPkg.ci.yaml Patch CVE-2022-36763-0001.patch does not apply (enforce with -f) stderr: ') ERROR: Logfile of failure stored in: /home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/temp/log.do_patch.2851600 ERROR: Task (/home/steve/builds/poky-contrib-kirkstone/meta/recipes-core/ovmf/ovmf_git.bb:do_patch) failed with exit code '1' NOTE: Tasks Summary: Attempted 1094 tasks of which 1085 didn't need to be rerun and 1 failed. Complete CVE report summary created at: /home/steve/builds/poky-contrib-kirkstone/build/tmp/log/cve/cve-summary NOTE: Generating JSON CVE summary Complete CVE JSON report summary created at: /home/steve/builds/poky-contrib-kirkstone/build/tmp/log/cve/cve-summary.json Summary: 1 task failed: /home/steve/builds/poky-contrib-kirkstone/meta/recipes-core/ovmf/ovmf_git.bb:do_patch Summary: There was 1 ERROR message, returning a non-zero exit code. Any suggestions? Steve > ________________________________ > From: Steve Sakoman <steve@sakoman.com> > Sent: Wednesday, November 27, 2024 10:50 PM > To: Jia, Hongxu <Hongxu.Jia@windriver.com> > Cc: openembedded-core@lists.openembedded.org <openembedded-core@lists.openembedded.org> > Subject: Re: [kirkstone][PATCH V2 01/13] ovmf: Fix CVE-2022-36763 > > CAUTION: This email comes from a non Wind River email account! > Do not click links or open attachments unless you recognize the sender and know the content is safe. > > I am getting build time errors with this patch: > > ERROR: ovmf-edk2-stable202202-r0 do_patch: Applying patch > 'CVE-2022-36763-0001.patch' on target directory > '/home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/git' > CmdError('quilt --quiltrc > /home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/recipe-sysroot-native/etc/quiltrc > push', 0, 'stdout: Applying patch CVE-2022-36763-0001.patch > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c > Hunk #1 FAILED at 20 (different line endings). > Hunk #2 FAILED at 44 (different line endings). > Hunk #3 FAILED at 144 (different line endings). > Hunk #4 FAILED at 195 (different line endings). > Hunk #5 FAILED at 223 (different line endings). > Hunk #6 FAILED at 248 (different line endings). > Hunk #7 FAILED at 310 (different line endings). > Hunk #8 FAILED at 326 (different line endings). > Hunk #9 FAILED at 443 (different line endings). > Hunk #10 FAILED at 515 (different line endings). > Hunk #11 FAILED at 646 (different line endings). > 11 out of 11 hunks FAILED -- rejects in file > SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf > Hunk #1 FAILED at 37 (different line endings). > Hunk #2 FAILED at 46 (different line endings). > Hunk #3 FAILED at 65 (different line endings). > 3 out of 3 hunks FAILED -- rejects in file > SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf > patching file SecurityPkg/SecurityPkg.ci.yaml > Hunk #1 FAILED at 15 (different line endings). > 1 out of 1 hunk FAILED -- rejects in file SecurityPkg/SecurityPkg.ci.yaml > Patch CVE-2022-36763-0001.patch does not apply (enforce with -f) > > Please submit a V2 of this series with the line ending issues fixed. > > Thanks! > > Steve > > On Mon, Nov 25, 2024 at 6:25 PM Hongxu Jia <hongxu.jia@windriver.com> wrote: > > > > From: Soumya Sambu <soumya.sambu@windriver.com> > > > > EDK2 is susceptible to a vulnerability in the Tcg2MeasureGptTable() > > function, allowing a user to trigger a heap buffer overflow via a local > > network. Successful exploitation of this vulnerability may result in a > > compromise of confidentiality, integrity, and/or availability. > > > > References: > > https://nvd.nist.gov/vuln/detail/CVE-2022-36763 > > > > Upstream-patches: > > https://github.com/tianocore/edk2/commit/224446543206450ddb5830e6abd026d61d3c7f4b > > https://github.com/tianocore/edk2/commit/4776a1b39ee08fc45c70c1eab5a0195f325000d3 > > https://github.com/tianocore/edk2/commit/1ddcb9fc6b4164e882687b031e8beacfcf7df29e > > > > Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> > > --- > > .../ovmf/ovmf/CVE-2022-36763-0001.patch | 985 ++++++++++++++++++ > > .../ovmf/ovmf/CVE-2022-36763-0002.patch | 889 ++++++++++++++++ > > .../ovmf/ovmf/CVE-2022-36763-0003.patch | 55 + > > meta/recipes-core/ovmf/ovmf_git.bb | 3 + > > 4 files changed, 1932 insertions(+) > > create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch > > create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch > > create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch > > > > diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch > > new file mode 100644 > > index 0000000000..93cefe7740 > > --- /dev/null > > +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch > > @@ -0,0 +1,985 @@ > > +From 224446543206450ddb5830e6abd026d61d3c7f4b Mon Sep 17 00:00:00 2001 > > +From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com> > > +Date: Fri, 12 Jan 2024 02:16:01 +0800 > > +Subject: [PATCH] SecurityPkg: DxeTpm2MeasureBootLib: SECURITY PATCH 4117 - CVE > > + 2022-36763 > > + > > +This commit contains the patch files and tests for DxeTpm2MeasureBootLib > > +CVE 2022-36763. > > + > > +Cc: Jiewen Yao <jiewen.yao@intel.com> > > + > > +Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> > > + > > +CVE: CVE-2022-36763 > > + > > +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/224446543206450ddb5830e6abd026d61d3c7f4b] > > + > > +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> > > +--- > > + .../DxeTpm2MeasureBootLib.c | 69 ++-- > > + .../DxeTpm2MeasureBootLib.inf | 4 +- > > + .../DxeTpm2MeasureBootLibSanitization.c | 275 ++++++++++++++++ > > + .../DxeTpm2MeasureBootLibSanitization.h | 113 +++++++ > > + .../DxeTpm2MeasureBootLibSanitizationTest.c | 303 ++++++++++++++++++ > > + ...Tpm2MeasureBootLibSanitizationTestHost.inf | 28 ++ > > + SecurityPkg/SecurityPkg.ci.yaml | 1 + > > + 7 files changed, 763 insertions(+), 30 deletions(-) > > + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c > > + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h > > + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c > > + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf > > + > > +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c > > +index 36a256a7af..0475103d6e 100644 > > +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c > > ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c > > +@@ -20,6 +20,8 @@ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> > > + (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> > > + SPDX-License-Identifier: BSD-2-Clause-Patent > > + > > ++Copyright (c) Microsoft Corporation.<BR> > > ++SPDX-License-Identifier: BSD-2-Clause-Patent > > + **/ > > + > > + #include <PiDxe.h> > > +@@ -44,6 +46,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent > > + #include <Library/HobLib.h> > > + #include <Protocol/CcMeasurement.h> > > + > > ++#include "DxeTpm2MeasureBootLibSanitization.h" > > ++ > > + typedef struct { > > + EFI_TCG2_PROTOCOL *Tcg2Protocol; > > + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol; > > +@@ -144,10 +148,11 @@ Tcg2MeasureGptTable ( > > + EFI_TCG2_EVENT *Tcg2Event; > > + EFI_CC_EVENT *CcEvent; > > + EFI_GPT_DATA *GptData; > > +- UINT32 EventSize; > > ++ UINT32 TcgEventSize; > > + EFI_TCG2_PROTOCOL *Tcg2Protocol; > > + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol; > > + EFI_CC_MR_INDEX MrIndex; > > ++ UINT32 AllocSize; > > + > > + if (mTcg2MeasureGptCount > 0) { > > + return EFI_SUCCESS; > > +@@ -195,25 +200,22 @@ Tcg2MeasureGptTable ( > > + BlockIo->Media->BlockSize, > > + (UINT8 *)PrimaryHeader > > + ); > > +- if (EFI_ERROR (Status)) { > > +- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n")); > > ++ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) { > > ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n")); > > + FreePool (PrimaryHeader); > > + return EFI_DEVICE_ERROR; > > + } > > + > > + // > > +- // PrimaryHeader->SizeOfPartitionEntry should not be zero > > ++ // Read the partition entry. > > + // > > +- if (PrimaryHeader->SizeOfPartitionEntry == 0) { > > +- DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry should not be zero!\n")); > > ++ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize); > > ++ if (EFI_ERROR (Status)) { > > + FreePool (PrimaryHeader); > > + return EFI_BAD_BUFFER_SIZE; > > + } > > + > > +- // > > +- // Read the partition entry. > > +- // > > +- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry); > > ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize); > > + if (EntryPtr == NULL) { > > + FreePool (PrimaryHeader); > > + return EFI_OUT_OF_RESOURCES; > > +@@ -223,7 +225,7 @@ Tcg2MeasureGptTable ( > > + DiskIo, > > + BlockIo->Media->MediaId, > > + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), > > +- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry, > > ++ AllocSize, > > + EntryPtr > > + ); > > + if (EFI_ERROR (Status)) { > > +@@ -248,16 +250,21 @@ Tcg2MeasureGptTable ( > > + // > > + // Prepare Data for Measurement (CcProtocol and Tcg2Protocol) > > + // > > +- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) > > +- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry); > > +- EventPtr = (UINT8 *)AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)); > > ++ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &TcgEventSize); > > ++ if (EFI_ERROR (Status)) { > > ++ FreePool (PrimaryHeader); > > ++ FreePool (EntryPtr); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ EventPtr = (UINT8 *)AllocateZeroPool (TcgEventSize); > > + if (EventPtr == NULL) { > > + Status = EFI_OUT_OF_RESOURCES; > > + goto Exit; > > + } > > + > > + Tcg2Event = (EFI_TCG2_EVENT *)EventPtr; > > +- Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event); > > ++ Tcg2Event->Size = TcgEventSize; > > + Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER); > > + Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; > > + Tcg2Event->Header.PCRIndex = 5; > > +@@ -310,7 +317,7 @@ Tcg2MeasureGptTable ( > > + CcProtocol, > > + 0, > > + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData, > > +- (UINT64)EventSize, > > ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), > > + CcEvent > > + ); > > + if (!EFI_ERROR (Status)) { > > +@@ -326,7 +333,7 @@ Tcg2MeasureGptTable ( > > + Tcg2Protocol, > > + 0, > > + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData, > > +- (UINT64)EventSize, > > ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), > > + Tcg2Event > > + ); > > + if (!EFI_ERROR (Status)) { > > +@@ -443,11 +450,13 @@ Tcg2MeasurePeImage ( > > + Tcg2Event->Header.PCRIndex = 2; > > + break; > > + default: > > +- DEBUG (( > > +- DEBUG_ERROR, > > +- "Tcg2MeasurePeImage: Unknown subsystem type %d", > > +- ImageType > > +- )); > > ++ DEBUG ( > > ++ ( > > ++ DEBUG_ERROR, > > ++ "Tcg2MeasurePeImage: Unknown subsystem type %d", > > ++ ImageType > > ++ ) > > ++ ); > > + goto Finish; > > + } > > + > > +@@ -515,7 +524,7 @@ Finish: > > + > > + @param MeasureBootProtocols Pointer to the located measure boot protocol instances. > > + > > +- @retval EFI_SUCCESS Sucessfully locate the measure boot protocol instances (at least one instance). > > ++ @retval EFI_SUCCESS Successfully locate the measure boot protocol instances (at least one instance). > > + @retval EFI_UNSUPPORTED Measure boot is not supported. > > + **/ > > + EFI_STATUS > > +@@ -646,12 +655,14 @@ DxeTpm2MeasureBootHandler ( > > + return EFI_SUCCESS; > > + } > > + > > +- DEBUG (( > > +- DEBUG_INFO, > > +- "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n", > > +- MeasureBootProtocols.Tcg2Protocol, > > +- MeasureBootProtocols.CcProtocol > > +- )); > > ++ DEBUG ( > > ++ ( > > ++ DEBUG_INFO, > > ++ "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n", > > ++ MeasureBootProtocols.Tcg2Protocol, > > ++ MeasureBootProtocols.CcProtocol > > ++ ) > > ++ ); > > + > > + // > > + // Copy File Device Path > > +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf > > +index 6dca79a20c..28995f438d 100644 > > +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf > > ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf > > +@@ -37,6 +37,8 @@ > > + > > + [Sources] > > + DxeTpm2MeasureBootLib.c > > ++ DxeTpm2MeasureBootLibSanitization.c > > ++ DxeTpm2MeasureBootLibSanitization.h > > + > > + [Packages] > > + MdePkg/MdePkg.dec > > +@@ -46,6 +48,7 @@ > > + > > + [LibraryClasses] > > + BaseMemoryLib > > ++ SafeIntLib > > + DebugLib > > + MemoryAllocationLib > > + DevicePathLib > > +@@ -65,4 +68,3 @@ > > + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES > > + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES > > + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES > > +- > > +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c > > +new file mode 100644 > > +index 0000000000..e2309655d3 > > +--- /dev/null > > ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c > > +@@ -0,0 +1,275 @@ > > ++/** @file > > ++ The library instance provides security service of TPM2 measure boot and > > ++ Confidential Computing (CC) 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. > > ++ > > ++ This file will pull out the validation logic from the following functions, in an > > ++ attempt to validate the untrusted input in the form of unit tests > > ++ > > ++ These are those functions: > > ++ > > ++ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content > > ++ read is within the image buffer. > > ++ > > ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse > > ++ partition data carefully. > > ++ > > ++ Copyright (c) Microsoft Corporation.<BR> > > ++ SPDX-License-Identifier: BSD-2-Clause-Patent > > ++**/ > > ++#include <Uefi.h> > > ++#include <Uefi/UefiSpec.h> > > ++#include <Library/SafeIntLib.h> > > ++#include <Library/UefiLib.h> > > ++#include <Library/DebugLib.h> > > ++#include <Library/BaseLib.h> > > ++#include <IndustryStandard/UefiTcgPlatform.h> > > ++#include <Protocol/BlockIo.h> > > ++#include <Library/MemoryAllocationLib.h> > > ++ > > ++#include "DxeTpm2MeasureBootLibSanitization.h" > > ++ > > ++#define GPT_HEADER_REVISION_V1 0x00010000 > > ++ > > ++/** > > ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse > > ++ However this function will not attempt to verify the validity of the GPT partition > > ++ It will check the following: > > ++ - Signature > > ++ - Revision > > ++ - AlternateLBA > > ++ - FirstUsableLBA > > ++ - LastUsableLBA > > ++ - PartitionEntryLBA > > ++ - NumberOfPartitionEntries > > ++ - SizeOfPartitionEntry > > ++ - BlockIo > > ++ > > ++ @param[in] PrimaryHeader > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > ++ > > ++ @param[in] BlockIo > > ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. > > ++ > > ++ @retval EFI_SUCCESS > > ++ The EFI_PARTITION_TABLE_HEADER structure is valid. > > ++ > > ++ @retval EFI_INVALID_PARAMETER > > ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. > > ++**/ > > ++EFI_STATUS > > ++EFIAPI > > ++SanitizeEfiPartitionTableHeader ( > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo > > ++ ) > > ++{ > > ++ // > > ++ // Verify that the input parameters are safe to use > > ++ // > > ++ if (PrimaryHeader == NULL) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); > > ++ return EFI_INVALID_PARAMETER; > > ++ } > > ++ > > ++ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n")); > > ++ return EFI_INVALID_PARAMETER; > > ++ } > > ++ > > ++ // > > ++ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII) > > ++ // > > ++ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ // > > ++ // The version must be GPT_HEADER_REVISION_V1 (0x00010000) > > ++ // > > ++ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n")); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ // > > ++ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size > > ++ // > > ++ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n")); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ // > > ++ // The partition entries should all be before the first usable block > > ++ // > > ++ if (PrimaryHeader->FirstUsableLBA <= PrimaryHeader->PartitionEntryLBA) { > > ++ DEBUG ((DEBUG_ERROR, "GPT PartitionEntryLBA is not less than FirstUsableLBA!\n")); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ // > > ++ // Check that the PartitionEntryLBA greater than the Max LBA > > ++ // This will be used later for multiplication > > ++ // > > ++ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n")); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ // > > ++ // Check that the number of partition entries is greater than zero > > ++ // > > ++ if (PrimaryHeader->NumberOfPartitionEntries == 0) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ // > > ++ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory > > ++ // > > ++ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) { > > ++ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n")); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ // > > ++ // This check is to prevent overflow when calculating the allocation size for the partition entries > > ++ // This check will be used later for multiplication > > ++ // > > ++ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ return EFI_SUCCESS; > > ++} > > ++ > > ++/** > > ++ This function will validate that the allocation size from the primary header is sane > > ++ It will check the following: > > ++ - AllocationSize does not overflow > > ++ > > ++ @param[in] PrimaryHeader > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > ++ > > ++ @param[out] AllocationSize > > ++ Pointer to the allocation size. > > ++ > > ++ @retval EFI_SUCCESS > > ++ The allocation size is valid. > > ++ > > ++ @retval EFI_OUT_OF_RESOURCES > > ++ The allocation size is invalid. > > ++**/ > > ++EFI_STATUS > > ++EFIAPI > > ++SanitizePrimaryHeaderAllocationSize ( > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > ++ OUT UINT32 *AllocationSize > > ++ ) > > ++{ > > ++ EFI_STATUS Status; > > ++ > > ++ if (PrimaryHeader == NULL) { > > ++ return EFI_INVALID_PARAMETER; > > ++ } > > ++ > > ++ if (AllocationSize == NULL) { > > ++ return EFI_INVALID_PARAMETER; > > ++ } > > ++ > > ++ // > > ++ // Replacing logic: > > ++ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry; > > ++ // > > ++ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize); > > ++ if (EFI_ERROR (Status)) { > > ++ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n")); > > ++ return EFI_BAD_BUFFER_SIZE; > > ++ } > > ++ > > ++ return EFI_SUCCESS; > > ++} > > ++ > > ++/** > > ++ This function will validate that the Gpt Event Size calculated from the primary header is sane > > ++ It will check the following: > > ++ - EventSize does not overflow > > ++ > > ++ Important: This function includes the entire length of the allocated space, including > > ++ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this > > ++ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) > > ++ from the size of the buffer before hashing. > > ++ > > ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > ++ @param[in] NumberOfPartition - Number of partitions. > > ++ @param[out] EventSize - Pointer to the event size. > > ++ > > ++ @retval EFI_SUCCESS > > ++ The event size is valid. > > ++ > > ++ @retval EFI_OUT_OF_RESOURCES > > ++ Overflow would have occurred. > > ++ > > ++ @retval EFI_INVALID_PARAMETER > > ++ One of the passed parameters was invalid. > > ++**/ > > ++EFI_STATUS > > ++SanitizePrimaryHeaderGptEventSize ( > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > ++ IN UINTN NumberOfPartition, > > ++ OUT UINT32 *EventSize > > ++ ) > > ++{ > > ++ EFI_STATUS Status; > > ++ UINT32 SafeNumberOfPartitions; > > ++ > > ++ if (PrimaryHeader == NULL) { > > ++ return EFI_INVALID_PARAMETER; > > ++ } > > ++ > > ++ if (EventSize == NULL) { > > ++ return EFI_INVALID_PARAMETER; > > ++ } > > ++ > > ++ // > > ++ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32 > > ++ // > > ++ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions); > > ++ if (EFI_ERROR (Status)) { > > ++ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n")); > > ++ return EFI_INVALID_PARAMETER; > > ++ } > > ++ > > ++ // > > ++ // Replacing logic: > > ++ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry); > > ++ // > > ++ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize); > > ++ if (EFI_ERROR (Status)) { > > ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n")); > > ++ return EFI_BAD_BUFFER_SIZE; > > ++ } > > ++ > > ++ // > > ++ // Replacing logic: > > ++ // *EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event); > > ++ // > > ++ Status = SafeUint32Add ( > > ++ OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions), > > ++ *EventSize, > > ++ EventSize > > ++ ); > > ++ if (EFI_ERROR (Status)) { > > ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n")); > > ++ return EFI_BAD_BUFFER_SIZE; > > ++ } > > ++ > > ++ return EFI_SUCCESS; > > ++} > > +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h > > +new file mode 100644 > > +index 0000000000..048b738987 > > +--- /dev/null > > ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h > > +@@ -0,0 +1,113 @@ > > ++/** @file > > ++ This file includes the function prototypes for the sanitization functions. > > ++ > > ++ These are those functions: > > ++ > > ++ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content > > ++ read is within the image buffer. > > ++ > > ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse > > ++ partition data carefully. > > ++ > > ++ Copyright (c) Microsoft Corporation.<BR> > > ++ SPDX-License-Identifier: BSD-2-Clause-Patent > > ++ > > ++**/ > > ++ > > ++#ifndef DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ > > ++#define DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ > > ++ > > ++#include <Uefi.h> > > ++#include <Uefi/UefiSpec.h> > > ++#include <Protocol/BlockIo.h> > > ++#include <IndustryStandard/UefiTcgPlatform.h> > > ++#include <Protocol/Tcg2Protocol.h> > > ++ > > ++/** > > ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse > > ++ However this function will not attempt to verify the validity of the GPT partition > > ++ It will check the following: > > ++ - Signature > > ++ - Revision > > ++ - AlternateLBA > > ++ - FirstUsableLBA > > ++ - LastUsableLBA > > ++ - PartitionEntryLBA > > ++ - NumberOfPartitionEntries > > ++ - SizeOfPartitionEntry > > ++ - BlockIo > > ++ > > ++ @param[in] PrimaryHeader > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > ++ > > ++ @param[in] BlockIo > > ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. > > ++ > > ++ @retval EFI_SUCCESS > > ++ The EFI_PARTITION_TABLE_HEADER structure is valid. > > ++ > > ++ @retval EFI_INVALID_PARAMETER > > ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. > > ++**/ > > ++EFI_STATUS > > ++EFIAPI > > ++SanitizeEfiPartitionTableHeader ( > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo > > ++ ); > > ++ > > ++/** > > ++ This function will validate that the allocation size from the primary header is sane > > ++ It will check the following: > > ++ - AllocationSize does not overflow > > ++ > > ++ @param[in] PrimaryHeader > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > ++ > > ++ @param[out] AllocationSize > > ++ Pointer to the allocation size. > > ++ > > ++ @retval EFI_SUCCESS > > ++ The allocation size is valid. > > ++ > > ++ @retval EFI_OUT_OF_RESOURCES > > ++ The allocation size is invalid. > > ++**/ > > ++EFI_STATUS > > ++EFIAPI > > ++SanitizePrimaryHeaderAllocationSize ( > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > ++ OUT UINT32 *AllocationSize > > ++ ); > > ++ > > ++/** > > ++ This function will validate that the Gpt Event Size calculated from the primary header is sane > > ++ It will check the following: > > ++ - EventSize does not overflow > > ++ > > ++ Important: This function includes the entire length of the allocated space, including > > ++ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this > > ++ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) > > ++ from the size of the buffer before hashing. > > ++ > > ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > ++ @param[in] NumberOfPartition - Number of partitions. > > ++ @param[out] EventSize - Pointer to the event size. > > ++ > > ++ @retval EFI_SUCCESS > > ++ The event size is valid. > > ++ > > ++ @retval EFI_OUT_OF_RESOURCES > > ++ Overflow would have occurred. > > ++ > > ++ @retval EFI_INVALID_PARAMETER > > ++ One of the passed parameters was invalid. > > ++**/ > > ++EFI_STATUS > > ++SanitizePrimaryHeaderGptEventSize ( > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > ++ IN UINTN NumberOfPartition, > > ++ OUT UINT32 *EventSize > > ++ ); > > ++ > > ++#endif // DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ > > +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c > > +new file mode 100644 > > +index 0000000000..3eb9763e3c > > +--- /dev/null > > ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c > > +@@ -0,0 +1,303 @@ > > ++/** @file > > ++ This file includes the unit test cases for the DxeTpm2MeasureBootLibSanitizationTest.c. > > ++ > > ++ Copyright (c) Microsoft Corporation.<BR> > > ++ SPDX-License-Identifier: BSD-2-Clause-Patent > > ++**/ > > ++ > > ++#include <Uefi.h> > > ++#include <Library/UefiLib.h> > > ++#include <Library/DebugLib.h> > > ++#include <Library/UnitTestLib.h> > > ++#include <Protocol/BlockIo.h> > > ++#include <Library/MemoryAllocationLib.h> > > ++#include <Library/BaseMemoryLib.h> > > ++#include <IndustryStandard/UefiTcgPlatform.h> > > ++#include <Protocol/Tcg2Protocol.h> > > ++ > > ++#include "../DxeTpm2MeasureBootLibSanitization.h" > > ++ > > ++#define UNIT_TEST_NAME "DxeTpm2MeasureBootLibSanitizationTest" > > ++#define UNIT_TEST_VERSION "1.0" > > ++ > > ++#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000 > > ++#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1 > > ++#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128 > > ++ > > ++/** > > ++ This function tests the SanitizeEfiPartitionTableHeader function. > > ++ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER > > ++ structure will not cause undefined or unexpected behavior. > > ++ > > ++ In general the TPM should still be able to measure the data, but > > ++ be the header should be sanitized to prevent any unexpected behavior. > > ++ > > ++ @param[in] Context The unit test context. > > ++ > > ++ @retval UNIT_TEST_PASSED The test passed. > > ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. > > ++**/ > > ++UNIT_TEST_STATUS > > ++EFIAPI > > ++TestSanitizeEfiPartitionTableHeader ( > > ++ IN UNIT_TEST_CONTEXT Context > > ++ ) > > ++{ > > ++ EFI_STATUS Status; > > ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; > > ++ EFI_BLOCK_IO_PROTOCOL BlockIo; > > ++ EFI_BLOCK_IO_MEDIA BlockMedia; > > ++ > > ++ // Generate EFI_BLOCK_IO_MEDIA test data > > ++ BlockMedia.MediaId = 1; > > ++ BlockMedia.RemovableMedia = FALSE; > > ++ BlockMedia.MediaPresent = TRUE; > > ++ BlockMedia.LogicalPartition = FALSE; > > ++ BlockMedia.ReadOnly = FALSE; > > ++ BlockMedia.WriteCaching = FALSE; > > ++ BlockMedia.BlockSize = 512; > > ++ BlockMedia.IoAlign = 1; > > ++ BlockMedia.LastBlock = 0; > > ++ > > ++ // Generate EFI_BLOCK_IO_PROTOCOL test data > > ++ BlockIo.Revision = 1; > > ++ BlockIo.Media = &BlockMedia; > > ++ BlockIo.Reset = NULL; > > ++ BlockIo.ReadBlocks = NULL; > > ++ BlockIo.WriteBlocks = NULL; > > ++ BlockIo.FlushBlocks = NULL; > > ++ > > ++ // Geneate EFI_PARTITION_TABLE_HEADER test data > > ++ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID; > > ++ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION; > > ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); > > ++ PrimaryHeader.MyLBA = 1; > > ++ PrimaryHeader.AlternateLBA = 2; > > ++ PrimaryHeader.FirstUsableLBA = 3; > > ++ PrimaryHeader.LastUsableLBA = 4; > > ++ PrimaryHeader.PartitionEntryLBA = 5; > > ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES; > > ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > ++ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid > > ++ > > ++ // Calculate the CRC32 of the PrimaryHeader > > ++ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize); > > ++ > > ++ // Test that a normal PrimaryHeader passes validation > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > ++ UT_ASSERT_NOT_EFI_ERROR (Status); > > ++ > > ++ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR > > ++ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!"" > > ++ PrimaryHeader.NumberOfPartitionEntries = 0; > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); > > ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > ++ > > ++ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR > > ++ // Should print "Invalid Partition Table Header Size!" > > ++ PrimaryHeader.Header.HeaderSize = 0; > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); > > ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); > > ++ > > ++ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR > > ++ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!" > > ++ PrimaryHeader.SizeOfPartitionEntry = 1; > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); > > ++ > > ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); > > ++ > > ++ return UNIT_TEST_PASSED; > > ++} > > ++ > > ++/** > > ++ This function tests the SanitizePrimaryHeaderAllocationSize function. > > ++ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER > > ++ structure will not cause an overflow when calculating the allocation size. > > ++ > > ++ @param[in] Context The unit test context. > > ++ > > ++ @retval UNIT_TEST_PASSED The test passed. > > ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. > > ++**/ > > ++UNIT_TEST_STATUS > > ++EFIAPI > > ++TestSanitizePrimaryHeaderAllocationSize ( > > ++ IN UNIT_TEST_CONTEXT Context > > ++ ) > > ++{ > > ++ UINT32 AllocationSize; > > ++ > > ++ EFI_STATUS Status; > > ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; > > ++ > > ++ // Test that a normal PrimaryHeader passes validation > > ++ PrimaryHeader.NumberOfPartitionEntries = 5; > > ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > ++ > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > ++ UT_ASSERT_NOT_EFI_ERROR (Status); > > ++ > > ++ // Test that the allocation size is correct compared to the existing logic > > ++ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry); > > ++ > > ++ // Test that an overflow is detected > > ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; > > ++ PrimaryHeader.SizeOfPartitionEntry = 5; > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > ++ > > ++ // Test the inverse > > ++ PrimaryHeader.NumberOfPartitionEntries = 5; > > ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > ++ > > ++ // Test the worst case scenario > > ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; > > ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > ++ > > ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); > > ++ > > ++ return UNIT_TEST_PASSED; > > ++} > > ++ > > ++/** > > ++ This function tests the SanitizePrimaryHeaderGptEventSize function. > > ++ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure > > ++ will not cause an overflow when calculating the event size. > > ++ > > ++ @param[in] Context The unit test context. > > ++ > > ++ @retval UNIT_TEST_PASSED The test passed. > > ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. > > ++**/ > > ++UNIT_TEST_STATUS > > ++EFIAPI > > ++TestSanitizePrimaryHeaderGptEventSize ( > > ++ IN UNIT_TEST_CONTEXT Context > > ++ ) > > ++{ > > ++ UINT32 EventSize; > > ++ UINT32 ExistingLogicEventSize; > > ++ EFI_STATUS Status; > > ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; > > ++ UINTN NumberOfPartition; > > ++ EFI_GPT_DATA *GptData; > > ++ EFI_TCG2_EVENT *Tcg2Event; > > ++ > > ++ Tcg2Event = NULL; > > ++ GptData = NULL; > > ++ > > ++ // Test that a normal PrimaryHeader passes validation > > ++ PrimaryHeader.NumberOfPartitionEntries = 5; > > ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > ++ > > ++ // set the number of partitions > > ++ NumberOfPartition = 13; > > ++ > > ++ // that the primary event size is correct > > ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); > > ++ UT_ASSERT_NOT_EFI_ERROR (Status); > > ++ > > ++ // Calculate the existing logic event size > > ++ ExistingLogicEventSize = (UINT32)(OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions) > > ++ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry); > > ++ > > ++ // Check that the event size is correct > > ++ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize); > > ++ > > ++ // Tests that the primary event size may not overflow > > ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize); > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > ++ > > ++ // Test that the size of partition entries may not overflow > > ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; > > ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > ++ > > ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); > > ++ > > ++ return UNIT_TEST_PASSED; > > ++} > > ++ > > ++// *--------------------------------------------------------------------* > > ++// * Unit Test Code Main Function > > ++// *--------------------------------------------------------------------* > > ++ > > ++/** > > ++ This function acts as the entry point for the unit tests. > > ++ > > ++ @retval UNIT_TEST_PASSED The test passed. > > ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. > > ++ @retval others The test failed. > > ++**/ > > ++EFI_STATUS > > ++EFIAPI > > ++UefiTestMain ( > > ++ VOID > > ++ ) > > ++{ > > ++ EFI_STATUS Status; > > ++ UNIT_TEST_FRAMEWORK_HANDLE Framework; > > ++ UNIT_TEST_SUITE_HANDLE Tcg2MeasureBootLibValidationTestSuite; > > ++ > > ++ Framework = NULL; > > ++ > > ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME)); > > ++ > > ++ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION); > > ++ if (EFI_ERROR (Status)) { > > ++ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status)); > > ++ goto EXIT; > > ++ } > > ++ > > ++ Status = CreateUnitTestSuite (&Tcg2MeasureBootLibValidationTestSuite, Framework, "Tcg2MeasureBootLibValidationTestSuite", "Common.Tcg2MeasureBootLibValidation", NULL, NULL); > > ++ if (EFI_ERROR (Status)) { > > ++ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for Tcg2MeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME)); > > ++ Status = EFI_OUT_OF_RESOURCES; > > ++ goto EXIT; > > ++ } > > ++ > > ++ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context > > ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.Tcg2MeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL); > > ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL); > > ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL); > > ++ > > ++ Status = RunAllTestSuites (Framework); > > ++ > > ++EXIT: > > ++ if (Framework != NULL) { > > ++ FreeUnitTestFramework (Framework); > > ++ } > > ++ > > ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME)); > > ++ return Status; > > ++} > > ++ > > ++/// > > ++/// Avoid ECC error for function name that starts with lower case letter > > ++/// > > ++#define DxeTpm2MeasureBootLibUnitTestMain main > > ++ > > ++/** > > ++ Standard POSIX C entry point for host based unit test execution. > > ++ > > ++ @param[in] Argc Number of arguments > > ++ @param[in] Argv Array of pointers to arguments > > ++ > > ++ @retval 0 Success > > ++ @retval other Error > > ++**/ > > ++INT32 > > ++DxeTpm2MeasureBootLibUnitTestMain ( > > ++ IN INT32 Argc, > > ++ IN CHAR8 *Argv[] > > ++ ) > > ++{ > > ++ return (INT32)UefiTestMain (); > > ++} > > +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf > > +new file mode 100644 > > +index 0000000000..2999aa2a44 > > +--- /dev/null > > ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf > > +@@ -0,0 +1,28 @@ > > ++## @file > > ++# This file builds the unit tests for DxeTpm2MeasureBootLib > > ++# > > ++# Copyright (C) Microsoft Corporation.<BR> > > ++# SPDX-License-Identifier: BSD-2-Clause-Patent > > ++## > > ++ > > ++[Defines] > > ++ INF_VERSION = 0x00010006 > > ++ BASE_NAME = DxeTpm2MeasuredBootLibTest > > ++ FILE_GUID = 144d757f-d423-484e-9309-a23695fad5bd > > ++ MODULE_TYPE = HOST_APPLICATION > > ++ VERSION_STRING = 1.0 > > ++ ENTRY_POINT = main > > ++ > > ++[Sources] > > ++ DxeTpm2MeasureBootLibSanitizationTest.c > > ++ ../DxeTpm2MeasureBootLibSanitization.c > > ++ > > ++[Packages] > > ++ MdePkg/MdePkg.dec > > ++ > > ++[LibraryClasses] > > ++ BaseLib > > ++ DebugLib > > ++ UnitTestLib > > ++ PrintLib > > ++ SafeIntLib > > +diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml > > +index 7912142398..da811fdf93 100644 > > +--- a/SecurityPkg/SecurityPkg.ci.yaml > > ++++ b/SecurityPkg/SecurityPkg.ci.yaml > > +@@ -15,6 +15,7 @@ > > + ## "<ErrorID>", "<KeyWord>" > > + ## ] > > + "ExceptionList": [ > > ++ "8001", "DxeTpm2MeasureBootLibUnitTestMain", > > + ], > > + ## Both file path and directory path are accepted. > > + "IgnoreFiles": [ > > +-- > > +2.40.0 > > + > > diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch > > new file mode 100644 > > index 0000000000..6c20cc305e > > --- /dev/null > > +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch > > @@ -0,0 +1,889 @@ > > +From 4776a1b39ee08fc45c70c1eab5a0195f325000d3 Mon Sep 17 00:00:00 2001 > > +From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com> > > +Date: Fri, 12 Jan 2024 02:16:02 +0800 > > +Subject: [PATCH] SecurityPkg: DxeTpmMeasureBootLib: SECURITY PATCH 4117 - CVE > > + 2022-36763 > > + > > +This commit contains the patch files and tests for DxeTpmMeasureBootLib > > +CVE 2022-36763. > > + > > +Cc: Jiewen Yao <jiewen.yao@intel.com> > > + > > +Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> > > +Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> > > + > > +CVE: CVE-2022-36763 > > + > > +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/4776a1b39ee08fc45c70c1eab5a0195f325000d3] > > + > > +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> > > +--- > > + .../DxeTpmMeasureBootLib.c | 40 ++- > > + .../DxeTpmMeasureBootLib.inf | 4 +- > > + .../DxeTpmMeasureBootLibSanitization.c | 241 ++++++++++++++ > > + .../DxeTpmMeasureBootLibSanitization.h | 114 +++++++ > > + .../DxeTpmMeasureBootLibSanitizationTest.c | 301 ++++++++++++++++++ > > + ...eTpmMeasureBootLibSanitizationTestHost.inf | 28 ++ > > + SecurityPkg/SecurityPkg.ci.yaml | 1 + > > + 7 files changed, 715 insertions(+), 14 deletions(-) > > + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c > > + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h > > + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c > > + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf > > + > > +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c > > +index 220393dd2b..669ab19134 100644 > > +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c > > ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c > > +@@ -18,6 +18,8 @@ > > + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> > > + SPDX-License-Identifier: BSD-2-Clause-Patent > > + > > ++Copyright (c) Microsoft Corporation.<BR> > > ++SPDX-License-Identifier: BSD-2-Clause-Patent > > + **/ > > + > > + #include <PiDxe.h> > > +@@ -40,6 +42,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent > > + #include <Library/SecurityManagementLib.h> > > + #include <Library/HobLib.h> > > + > > ++#include "DxeTpmMeasureBootLibSanitization.h" > > ++ > > + // > > + // Flag to check GPT partition. It only need be measured once. > > + // > > +@@ -136,6 +140,9 @@ TcgMeasureGptTable ( > > + UINT32 EventSize; > > + UINT32 EventNumber; > > + EFI_PHYSICAL_ADDRESS EventLogLastEntry; > > ++ UINT32 AllocSize; > > ++ > > ++ GptData = NULL; > > + > > + if (mMeasureGptCount > 0) { > > + return EFI_SUCCESS; > > +@@ -166,8 +173,8 @@ TcgMeasureGptTable ( > > + BlockIo->Media->BlockSize, > > + (UINT8 *)PrimaryHeader > > + ); > > +- if (EFI_ERROR (Status)) { > > +- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n")); > > ++ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) { > > ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n")); > > + FreePool (PrimaryHeader); > > + return EFI_DEVICE_ERROR; > > + } > > +@@ -175,7 +182,13 @@ TcgMeasureGptTable ( > > + // > > + // Read the partition entry. > > + // > > +- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry); > > ++ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize); > > ++ if (EFI_ERROR (Status)) { > > ++ FreePool (PrimaryHeader); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize); > > + if (EntryPtr == NULL) { > > + FreePool (PrimaryHeader); > > + return EFI_OUT_OF_RESOURCES; > > +@@ -185,7 +198,7 @@ TcgMeasureGptTable ( > > + DiskIo, > > + BlockIo->Media->MediaId, > > + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), > > +- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry, > > ++ AllocSize, > > + EntryPtr > > + ); > > + if (EFI_ERROR (Status)) { > > +@@ -210,9 +223,8 @@ TcgMeasureGptTable ( > > + // > > + // Prepare Data for Measurement > > + // > > +- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) > > +- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry); > > +- TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT_HDR)); > > ++ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &EventSize); > > ++ TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize); > > + if (TcgEvent == NULL) { > > + FreePool (PrimaryHeader); > > + FreePool (EntryPtr); > > +@@ -221,7 +233,7 @@ TcgMeasureGptTable ( > > + > > + TcgEvent->PCRIndex = 5; > > + TcgEvent->EventType = EV_EFI_GPT_EVENT; > > +- TcgEvent->EventSize = EventSize; > > ++ TcgEvent->EventSize = EventSize - sizeof (TCG_PCR_EVENT_HDR); > > + GptData = (EFI_GPT_DATA *)TcgEvent->Event; > > + > > + // > > +@@ -361,11 +373,13 @@ TcgMeasurePeImage ( > > + TcgEvent->PCRIndex = 2; > > + break; > > + default: > > +- DEBUG (( > > +- DEBUG_ERROR, > > +- "TcgMeasurePeImage: Unknown subsystem type %d", > > +- ImageType > > +- )); > > ++ DEBUG ( > > ++ ( > > ++ DEBUG_ERROR, > > ++ "TcgMeasurePeImage: Unknown subsystem type %d", > > ++ ImageType > > ++ ) > > ++ ); > > + goto Finish; > > + } > > + > > +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf > > +index ebab6f7c1e..414c654d15 100644 > > +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf > > ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf > > +@@ -32,6 +32,8 @@ > > + > > + [Sources] > > + DxeTpmMeasureBootLib.c > > ++ DxeTpmMeasureBootLibSanitization.c > > ++ DxeTpmMeasureBootLibSanitization.h > > + > > + [Packages] > > + MdePkg/MdePkg.dec > > +@@ -41,6 +43,7 @@ > > + > > + [LibraryClasses] > > + BaseMemoryLib > > ++ SafeIntLib > > + DebugLib > > + MemoryAllocationLib > > + DevicePathLib > > +@@ -59,4 +62,3 @@ > > + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES > > + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES > > + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES > > +- > > +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c > > +new file mode 100644 > > +index 0000000000..a3fa46f5e6 > > +--- /dev/null > > ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c > > +@@ -0,0 +1,241 @@ > > ++/** @file > > ++ The library instance provides security service of TPM2 measure boot and > > ++ Confidential Computing (CC) 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. > > ++ > > ++ This file will pull out the validation logic from the following functions, in an > > ++ attempt to validate the untrusted input in the form of unit tests > > ++ > > ++ These are those functions: > > ++ > > ++ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content > > ++ read is within the image buffer. > > ++ > > ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse > > ++ partition data carefully. > > ++ > > ++ Copyright (c) Microsoft Corporation.<BR> > > ++ SPDX-License-Identifier: BSD-2-Clause-Patent > > ++**/ > > ++#include <Uefi.h> > > ++#include <Uefi/UefiSpec.h> > > ++#include <Library/SafeIntLib.h> > > ++#include <Library/UefiLib.h> > > ++#include <Library/DebugLib.h> > > ++#include <Library/BaseLib.h> > > ++#include <IndustryStandard/UefiTcgPlatform.h> > > ++#include <Protocol/BlockIo.h> > > ++#include <Library/MemoryAllocationLib.h> > > ++ > > ++#include "DxeTpmMeasureBootLibSanitization.h" > > ++ > > ++#define GPT_HEADER_REVISION_V1 0x00010000 > > ++ > > ++/** > > ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse > > ++ However this function will not attempt to verify the validity of the GPT partition > > ++ It will check the following: > > ++ - Signature > > ++ - Revision > > ++ - AlternateLBA > > ++ - FirstUsableLBA > > ++ - LastUsableLBA > > ++ - PartitionEntryLBA > > ++ - NumberOfPartitionEntries > > ++ - SizeOfPartitionEntry > > ++ - BlockIo > > ++ > > ++ @param[in] PrimaryHeader > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > ++ > > ++ @param[in] BlockIo > > ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. > > ++ > > ++ @retval EFI_SUCCESS > > ++ The EFI_PARTITION_TABLE_HEADER structure is valid. > > ++ > > ++ @retval EFI_INVALID_PARAMETER > > ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. > > ++**/ > > ++EFI_STATUS > > ++EFIAPI > > ++SanitizeEfiPartitionTableHeader ( > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo > > ++ ) > > ++{ > > ++ // Verify that the input parameters are safe to use > > ++ if (PrimaryHeader == NULL) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); > > ++ return EFI_INVALID_PARAMETER; > > ++ } > > ++ > > ++ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n")); > > ++ return EFI_INVALID_PARAMETER; > > ++ } > > ++ > > ++ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII) > > ++ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ // The version must be GPT_HEADER_REVISION_V1 (0x00010000) > > ++ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n")); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size > > ++ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n")); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ // check that the PartitionEntryLBA greater than the Max LBA > > ++ // This will be used later for multiplication > > ++ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n")); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ // Check that the number of partition entries is greater than zero > > ++ if (PrimaryHeader->NumberOfPartitionEntries == 0) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory > > ++ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) { > > ++ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n")); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ // This check is to prevent overflow when calculating the allocation size for the partition entries > > ++ // This check will be used later for multiplication > > ++ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) { > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); > > ++ return EFI_DEVICE_ERROR; > > ++ } > > ++ > > ++ return EFI_SUCCESS; > > ++} > > ++ > > ++/** > > ++ This function will validate that the allocation size from the primary header is sane > > ++ It will check the following: > > ++ - AllocationSize does not overflow > > ++ > > ++ @param[in] PrimaryHeader > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > ++ > > ++ @param[out] AllocationSize > > ++ Pointer to the allocation size. > > ++ > > ++ @retval EFI_SUCCESS > > ++ The allocation size is valid. > > ++ > > ++ @retval EFI_OUT_OF_RESOURCES > > ++ The allocation size is invalid. > > ++**/ > > ++EFI_STATUS > > ++EFIAPI > > ++SanitizePrimaryHeaderAllocationSize ( > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > ++ OUT UINT32 *AllocationSize > > ++ ) > > ++{ > > ++ EFI_STATUS Status; > > ++ > > ++ if (PrimaryHeader == NULL) { > > ++ return EFI_INVALID_PARAMETER; > > ++ } > > ++ > > ++ if (AllocationSize == NULL) { > > ++ return EFI_INVALID_PARAMETER; > > ++ } > > ++ > > ++ // Replacing logic: > > ++ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry; > > ++ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize); > > ++ if (EFI_ERROR (Status)) { > > ++ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n")); > > ++ return EFI_BAD_BUFFER_SIZE; > > ++ } > > ++ > > ++ return EFI_SUCCESS; > > ++} > > ++ > > ++/** > > ++ This function will validate that the Gpt Event Size calculated from the primary header is sane > > ++ It will check the following: > > ++ - EventSize does not overflow > > ++ > > ++ Important: This function includes the entire length of the allocated space, including the > > ++ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract > > ++ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing. > > ++ > > ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > ++ @param[in] NumberOfPartition - Number of partitions. > > ++ @param[out] EventSize - Pointer to the event size. > > ++ > > ++ @retval EFI_SUCCESS > > ++ The event size is valid. > > ++ > > ++ @retval EFI_OUT_OF_RESOURCES > > ++ Overflow would have occurred. > > ++ > > ++ @retval EFI_INVALID_PARAMETER > > ++ One of the passed parameters was invalid. > > ++**/ > > ++EFI_STATUS > > ++SanitizePrimaryHeaderGptEventSize ( > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > ++ IN UINTN NumberOfPartition, > > ++ OUT UINT32 *EventSize > > ++ ) > > ++{ > > ++ EFI_STATUS Status; > > ++ UINT32 SafeNumberOfPartitions; > > ++ > > ++ if (PrimaryHeader == NULL) { > > ++ return EFI_INVALID_PARAMETER; > > ++ } > > ++ > > ++ if (EventSize == NULL) { > > ++ return EFI_INVALID_PARAMETER; > > ++ } > > ++ > > ++ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32 > > ++ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions); > > ++ if (EFI_ERROR (Status)) { > > ++ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n")); > > ++ return EFI_INVALID_PARAMETER; > > ++ } > > ++ > > ++ // Replacing logic: > > ++ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry + sizeof (TCG_PCR_EVENT_HDR)); > > ++ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize); > > ++ if (EFI_ERROR (Status)) { > > ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n")); > > ++ return EFI_BAD_BUFFER_SIZE; > > ++ } > > ++ > > ++ Status = SafeUint32Add ( > > ++ sizeof (TCG_PCR_EVENT_HDR) + > > ++ OFFSET_OF (EFI_GPT_DATA, Partitions), > > ++ *EventSize, > > ++ EventSize > > ++ ); > > ++ if (EFI_ERROR (Status)) { > > ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n")); > > ++ return EFI_BAD_BUFFER_SIZE; > > ++ } > > ++ > > ++ return EFI_SUCCESS; > > ++} > > +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h > > +new file mode 100644 > > +index 0000000000..0d9d00c281 > > +--- /dev/null > > ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h > > +@@ -0,0 +1,114 @@ > > ++/** @file > > ++ This file includes the function prototypes for the sanitization functions. > > ++ > > ++ These are those functions: > > ++ > > ++ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content > > ++ read is within the image buffer. > > ++ > > ++ TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its > > ++ data structure within this image buffer before use. > > ++ > > ++ TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse > > ++ partition data carefully. > > ++ > > ++ Copyright (c) Microsoft Corporation.<BR> > > ++ SPDX-License-Identifier: BSD-2-Clause-Patent > > ++ > > ++**/ > > ++ > > ++#ifndef DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ > > ++#define DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ > > ++ > > ++#include <Uefi.h> > > ++#include <Uefi/UefiSpec.h> > > ++#include <Protocol/BlockIo.h> > > ++#include <IndustryStandard/UefiTcgPlatform.h> > > ++ > > ++/** > > ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse > > ++ However this function will not attempt to verify the validity of the GPT partition > > ++ It will check the following: > > ++ - Signature > > ++ - Revision > > ++ - AlternateLBA > > ++ - FirstUsableLBA > > ++ - LastUsableLBA > > ++ - PartitionEntryLBA > > ++ - NumberOfPartitionEntries > > ++ - SizeOfPartitionEntry > > ++ - BlockIo > > ++ > > ++ @param[in] PrimaryHeader > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > ++ > > ++ @param[in] BlockIo > > ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. > > ++ > > ++ @retval EFI_SUCCESS > > ++ The EFI_PARTITION_TABLE_HEADER structure is valid. > > ++ > > ++ @retval EFI_INVALID_PARAMETER > > ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. > > ++**/ > > ++EFI_STATUS > > ++EFIAPI > > ++SanitizeEfiPartitionTableHeader ( > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo > > ++ ); > > ++ > > ++/** > > ++ This function will validate that the allocation size from the primary header is sane > > ++ It will check the following: > > ++ - AllocationSize does not overflow > > ++ > > ++ @param[in] PrimaryHeader > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > ++ > > ++ @param[out] AllocationSize > > ++ Pointer to the allocation size. > > ++ > > ++ @retval EFI_SUCCESS > > ++ The allocation size is valid. > > ++ > > ++ @retval EFI_OUT_OF_RESOURCES > > ++ The allocation size is invalid. > > ++**/ > > ++EFI_STATUS > > ++EFIAPI > > ++SanitizePrimaryHeaderAllocationSize ( > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > ++ OUT UINT32 *AllocationSize > > ++ ); > > ++ > > ++/** > > ++ This function will validate that the Gpt Event Size calculated from the primary header is sane > > ++ It will check the following: > > ++ - EventSize does not overflow > > ++ > > ++ Important: This function includes the entire length of the allocated space, including the > > ++ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract > > ++ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing. > > ++ > > ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > ++ @param[in] NumberOfPartition - Number of partitions. > > ++ @param[out] EventSize - Pointer to the event size. > > ++ > > ++ @retval EFI_SUCCESS > > ++ The event size is valid. > > ++ > > ++ @retval EFI_OUT_OF_RESOURCES > > ++ Overflow would have occurred. > > ++ > > ++ @retval EFI_INVALID_PARAMETER > > ++ One of the passed parameters was invalid. > > ++**/ > > ++EFI_STATUS > > ++SanitizePrimaryHeaderGptEventSize ( > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > ++ IN UINTN NumberOfPartition, > > ++ OUT UINT32 *EventSize > > ++ ); > > ++ > > ++#endif // DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ > > +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c > > +new file mode 100644 > > +index 0000000000..eeb928cdb0 > > +--- /dev/null > > ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c > > +@@ -0,0 +1,301 @@ > > ++/** @file > > ++This file includes the unit test cases for the DxeTpmMeasureBootLibSanitizationTest.c. > > ++ > > ++Copyright (c) Microsoft Corporation.<BR> > > ++SPDX-License-Identifier: BSD-2-Clause-Patent > > ++**/ > > ++ > > ++#include <Uefi.h> > > ++#include <Library/UefiLib.h> > > ++#include <Library/DebugLib.h> > > ++#include <Library/UnitTestLib.h> > > ++#include <Protocol/BlockIo.h> > > ++#include <Library/MemoryAllocationLib.h> > > ++#include <Library/BaseMemoryLib.h> > > ++#include <IndustryStandard/UefiTcgPlatform.h> > > ++ > > ++#include "../DxeTpmMeasureBootLibSanitization.h" > > ++ > > ++#define UNIT_TEST_NAME "DxeTpmMeasureBootLibSanitizationTest" > > ++#define UNIT_TEST_VERSION "1.0" > > ++ > > ++#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000 > > ++#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1 > > ++#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128 > > ++ > > ++/** > > ++ This function tests the SanitizeEfiPartitionTableHeader function. > > ++ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER > > ++ structure will not cause undefined or unexpected behavior. > > ++ > > ++ In general the TPM should still be able to measure the data, but > > ++ be the header should be sanitized to prevent any unexpected behavior. > > ++ > > ++ @param[in] Context The unit test context. > > ++ > > ++ @retval UNIT_TEST_PASSED The test passed. > > ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. > > ++**/ > > ++UNIT_TEST_STATUS > > ++EFIAPI > > ++TestSanitizeEfiPartitionTableHeader ( > > ++ IN UNIT_TEST_CONTEXT Context > > ++ ) > > ++{ > > ++ EFI_STATUS Status; > > ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; > > ++ EFI_BLOCK_IO_PROTOCOL BlockIo; > > ++ EFI_BLOCK_IO_MEDIA BlockMedia; > > ++ > > ++ // Generate EFI_BLOCK_IO_MEDIA test data > > ++ BlockMedia.MediaId = 1; > > ++ BlockMedia.RemovableMedia = FALSE; > > ++ BlockMedia.MediaPresent = TRUE; > > ++ BlockMedia.LogicalPartition = FALSE; > > ++ BlockMedia.ReadOnly = FALSE; > > ++ BlockMedia.WriteCaching = FALSE; > > ++ BlockMedia.BlockSize = 512; > > ++ BlockMedia.IoAlign = 1; > > ++ BlockMedia.LastBlock = 0; > > ++ > > ++ // Generate EFI_BLOCK_IO_PROTOCOL test data > > ++ BlockIo.Revision = 1; > > ++ BlockIo.Media = &BlockMedia; > > ++ BlockIo.Reset = NULL; > > ++ BlockIo.ReadBlocks = NULL; > > ++ BlockIo.WriteBlocks = NULL; > > ++ BlockIo.FlushBlocks = NULL; > > ++ > > ++ // Geneate EFI_PARTITION_TABLE_HEADER test data > > ++ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID; > > ++ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION; > > ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); > > ++ PrimaryHeader.MyLBA = 1; > > ++ PrimaryHeader.AlternateLBA = 2; > > ++ PrimaryHeader.FirstUsableLBA = 3; > > ++ PrimaryHeader.LastUsableLBA = 4; > > ++ PrimaryHeader.PartitionEntryLBA = 5; > > ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES; > > ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > ++ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid > > ++ > > ++ // Calculate the CRC32 of the PrimaryHeader > > ++ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize); > > ++ > > ++ // Test that a normal PrimaryHeader passes validation > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > ++ UT_ASSERT_NOT_EFI_ERROR (Status); > > ++ > > ++ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR > > ++ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!"" > > ++ PrimaryHeader.NumberOfPartitionEntries = 0; > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); > > ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > ++ > > ++ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR > > ++ // Should print "Invalid Partition Table Header Size!" > > ++ PrimaryHeader.Header.HeaderSize = 0; > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); > > ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); > > ++ > > ++ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR > > ++ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!" > > ++ PrimaryHeader.SizeOfPartitionEntry = 1; > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); > > ++ > > ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); > > ++ > > ++ return UNIT_TEST_PASSED; > > ++} > > ++ > > ++/** > > ++ This function tests the SanitizePrimaryHeaderAllocationSize function. > > ++ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER > > ++ structure will not cause an overflow when calculating the allocation size. > > ++ > > ++ @param[in] Context The unit test context. > > ++ > > ++ @retval UNIT_TEST_PASSED The test passed. > > ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. > > ++**/ > > ++UNIT_TEST_STATUS > > ++EFIAPI > > ++TestSanitizePrimaryHeaderAllocationSize ( > > ++ IN UNIT_TEST_CONTEXT Context > > ++ ) > > ++{ > > ++ UINT32 AllocationSize; > > ++ > > ++ EFI_STATUS Status; > > ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; > > ++ > > ++ // Test that a normal PrimaryHeader passes validation > > ++ PrimaryHeader.NumberOfPartitionEntries = 5; > > ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > ++ > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > ++ UT_ASSERT_NOT_EFI_ERROR (Status); > > ++ > > ++ // Test that the allocation size is correct compared to the existing logic > > ++ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry); > > ++ > > ++ // Test that an overflow is detected > > ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; > > ++ PrimaryHeader.SizeOfPartitionEntry = 5; > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > ++ > > ++ // Test the inverse > > ++ PrimaryHeader.NumberOfPartitionEntries = 5; > > ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > ++ > > ++ // Test the worst case scenario > > ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; > > ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > ++ > > ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); > > ++ > > ++ return UNIT_TEST_PASSED; > > ++} > > ++ > > ++/** > > ++ This function tests the SanitizePrimaryHeaderGptEventSize function. > > ++ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure > > ++ will not cause an overflow when calculating the event size. > > ++ > > ++ @param[in] Context The unit test context. > > ++ > > ++ @retval UNIT_TEST_PASSED The test passed. > > ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. > > ++**/ > > ++UNIT_TEST_STATUS > > ++EFIAPI > > ++TestSanitizePrimaryHeaderGptEventSize ( > > ++ IN UNIT_TEST_CONTEXT Context > > ++ ) > > ++{ > > ++ UINT32 EventSize; > > ++ UINT32 ExistingLogicEventSize; > > ++ EFI_STATUS Status; > > ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; > > ++ UINTN NumberOfPartition; > > ++ EFI_GPT_DATA *GptData; > > ++ > > ++ GptData = NULL; > > ++ > > ++ // Test that a normal PrimaryHeader passes validation > > ++ PrimaryHeader.NumberOfPartitionEntries = 5; > > ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > ++ > > ++ // set the number of partitions > > ++ NumberOfPartition = 13; > > ++ > > ++ // that the primary event size is correct > > ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); > > ++ UT_ASSERT_NOT_EFI_ERROR (Status); > > ++ > > ++ // Calculate the existing logic event size > > ++ ExistingLogicEventSize = (UINT32)(sizeof (TCG_PCR_EVENT_HDR) + OFFSET_OF (EFI_GPT_DATA, Partitions) > > ++ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry); > > ++ > > ++ // Check that the event size is correct > > ++ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize); > > ++ > > ++ // Tests that the primary event size may not overflow > > ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize); > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > ++ > > ++ // Test that the size of partition entries may not overflow > > ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; > > ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > ++ > > ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); > > ++ > > ++ return UNIT_TEST_PASSED; > > ++} > > ++ > > ++// *--------------------------------------------------------------------* > > ++// * Unit Test Code Main Function > > ++// *--------------------------------------------------------------------* > > ++ > > ++/** > > ++ This function acts as the entry point for the unit tests. > > ++ > > ++ @param argc - The number of command line arguments > > ++ @param argv - The command line arguments > > ++ > > ++ @return int - The status of the test > > ++**/ > > ++EFI_STATUS > > ++EFIAPI > > ++UefiTestMain ( > > ++ VOID > > ++ ) > > ++{ > > ++ EFI_STATUS Status; > > ++ UNIT_TEST_FRAMEWORK_HANDLE Framework; > > ++ UNIT_TEST_SUITE_HANDLE TcgMeasureBootLibValidationTestSuite; > > ++ > > ++ Framework = NULL; > > ++ > > ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME)); > > ++ > > ++ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION); > > ++ if (EFI_ERROR (Status)) { > > ++ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status)); > > ++ goto EXIT; > > ++ } > > ++ > > ++ Status = CreateUnitTestSuite (&TcgMeasureBootLibValidationTestSuite, Framework, "TcgMeasureBootLibValidationTestSuite", "Common.TcgMeasureBootLibValidation", NULL, NULL); > > ++ if (EFI_ERROR (Status)) { > > ++ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for TcgMeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME)); > > ++ Status = EFI_OUT_OF_RESOURCES; > > ++ goto EXIT; > > ++ } > > ++ > > ++ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context > > ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.TcgMeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL); > > ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL); > > ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL); > > ++ > > ++ Status = RunAllTestSuites (Framework); > > ++ > > ++EXIT: > > ++ if (Framework != NULL) { > > ++ FreeUnitTestFramework (Framework); > > ++ } > > ++ > > ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME)); > > ++ return Status; > > ++} > > ++ > > ++/// > > ++/// Avoid ECC error for function name that starts with lower case letter > > ++/// > > ++#define DxeTpmMeasureBootLibUnitTestMain main > > ++ > > ++/** > > ++ Standard POSIX C entry point for host based unit test execution. > > ++ > > ++ @param[in] Argc Number of arguments > > ++ @param[in] Argv Array of pointers to arguments > > ++ > > ++ @retval 0 Success > > ++ @retval other Error > > ++**/ > > ++INT32 > > ++DxeTpmMeasureBootLibUnitTestMain ( > > ++ IN INT32 Argc, > > ++ IN CHAR8 *Argv[] > > ++ ) > > ++{ > > ++ return (INT32)UefiTestMain (); > > ++} > > +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf > > +new file mode 100644 > > +index 0000000000..47b0811b00 > > +--- /dev/null > > ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf > > +@@ -0,0 +1,28 @@ > > ++## @file > > ++# This file builds the unit tests for DxeTpmMeasureBootLib > > ++# > > ++# Copyright (C) Microsoft Corporation.<BR> > > ++# SPDX-License-Identifier: BSD-2-Clause-Patent > > ++## > > ++ > > ++[Defines] > > ++ INF_VERSION = 0x00010006 > > ++ BASE_NAME = DxeTpmMeasuredBootLibTest > > ++ FILE_GUID = eb01bc38-309c-4d3e-967e-9f078c90772f > > ++ MODULE_TYPE = HOST_APPLICATION > > ++ VERSION_STRING = 1.0 > > ++ ENTRY_POINT = main > > ++ > > ++[Sources] > > ++ DxeTpmMeasureBootLibSanitizationTest.c > > ++ ../DxeTpmMeasureBootLibSanitization.c > > ++ > > ++[Packages] > > ++ MdePkg/MdePkg.dec > > ++ > > ++[LibraryClasses] > > ++ BaseLib > > ++ DebugLib > > ++ UnitTestLib > > ++ PrintLib > > ++ SafeIntLib > > +diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml > > +index da811fdf93..0e40eaa0fe 100644 > > +--- a/SecurityPkg/SecurityPkg.ci.yaml > > ++++ b/SecurityPkg/SecurityPkg.ci.yaml > > +@@ -16,6 +16,7 @@ > > + ## ] > > + "ExceptionList": [ > > + "8001", "DxeTpm2MeasureBootLibUnitTestMain", > > ++ "8001", "DxeTpmMeasureBootLibUnitTestMain" > > + ], > > + ## Both file path and directory path are accepted. > > + "IgnoreFiles": [ > > +-- > > +2.40.0 > > + > > diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch > > new file mode 100644 > > index 0000000000..59bd5c4910 > > --- /dev/null > > +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch > > @@ -0,0 +1,55 @@ > > +From 1ddcb9fc6b4164e882687b031e8beacfcf7df29e Mon Sep 17 00:00:00 2001 > > +From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com> > > +Date: Fri, 12 Jan 2024 02:16:03 +0800 > > +Subject: [PATCH] SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml > > + > > +This creates / adds a security file that tracks the security fixes > > +found in this package and can be used to find the fixes that were > > +applied. > > + > > +Cc: Jiewen Yao <jiewen.yao@intel.com> > > + > > +Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> > > +Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> > > + > > +CVE: CVE-2022-36763 > > + > > +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1ddcb9fc6b4164e882687b031e8beacfcf7df29e] > > + > > +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> > > +--- > > + SecurityPkg/SecurityFixes.yaml | 22 ++++++++++++++++++++++ > > + 1 file changed, 22 insertions(+) > > + create mode 100644 SecurityPkg/SecurityFixes.yaml > > + > > +diff --git a/SecurityPkg/SecurityFixes.yaml b/SecurityPkg/SecurityFixes.yaml > > +new file mode 100644 > > +index 0000000000..f9e3e7be74 > > +--- /dev/null > > ++++ b/SecurityPkg/SecurityFixes.yaml > > +@@ -0,0 +1,22 @@ > > ++## @file > > ++# Security Fixes for SecurityPkg > > ++# > > ++# Copyright (c) Microsoft Corporation > > ++# SPDX-License-Identifier: BSD-2-Clause-Patent > > ++## > > ++CVE_2022_36763: > > ++ commit_titles: > > ++ - "SecurityPkg: DxeTpm2Measurement: SECURITY PATCH 4117 - CVE 2022-36763" > > ++ - "SecurityPkg: DxeTpmMeasurement: SECURITY PATCH 4117 - CVE 2022-36763" > > ++ - "SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml" > > ++ cve: CVE-2022-36763 > > ++ date_reported: 2022-10-25 11:31 UTC > > ++ description: (CVE-2022-36763) - Heap Buffer Overflow in Tcg2MeasureGptTable() > > ++ note: This patch is related to and supersedes TCBZ2168 > > ++ files_impacted: > > ++ - Library\DxeTpm2MeasureBootLib\DxeTpm2MeasureBootLib.c > > ++ - Library\DxeTpmMeasureBootLib\DxeTpmMeasureBootLib.c > > ++ links: > > ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4117 > > ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=2168 > > ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=1990 > > +-- > > +2.40.0 > > + > > diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb > > index 84e3360a3a..78d86ad879 100644 > > --- a/meta/recipes-core/ovmf/ovmf_git.bb > > +++ b/meta/recipes-core/ovmf/ovmf_git.bb > > @@ -27,6 +27,9 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ > > file://0006-reproducible.patch \ > > file://0001-BaseTools-fix-gcc12-warning.patch \ > > file://0001-BaseTools-fix-gcc12-warning-1.patch \ > > + file://CVE-2022-36763-0001.patch \ > > + file://CVE-2022-36763-0002.patch \ > > + file://CVE-2022-36763-0003.patch \ > > " > > > > PV = "edk2-stable202202" > > -- > > 2.25.1 > >
On Mon, Dec 2, 2024 at 8:09 AM Steve Sakoman via lists.openembedded.org <steve=sakoman.com@lists.openembedded.org> wrote: > > On Thu, Nov 28, 2024 at 12:15 AM Jia, Hongxu <Hongxu.Jia@windriver.com> wrote: > > > > Hi Steve, > > > > I am afraid the issue was caused by CR("^M") in ovmf source code > > > > The source of ovmf use CR (^M) as new line, we should use 'git am --keep-cr xxxx.patch' to apply the patch, > > otherwise do_patch failed > > > > But I do not know how you apply the patch to your build or via patchtest automatically, do you use git am with option --keep-cr? > > I download the patch from patchworks using the "mbox" button and the > apply it like this: > > $ git am --keep-cr ~/Downloads/kirkstone-V2-01-13-ovmf-Fix-CVE-2022-36763.patch > Applying: ovmf: Fix CVE-2022-36763 > .git/rebase-apply/patch:56: trailing whitespace. > .git/rebase-apply/patch:60: trailing whitespace. > .git/rebase-apply/patch:65: trailing whitespace. > .git/rebase-apply/patch:81: trailing whitespace. > .git/rebase-apply/patch:95: trailing whitespace. > warning: squelched 27 whitespace errors > warning: 32 lines add whitespace errors. > > $ bitbake ovmf > Loading cache: 100% | > > > > | ETA: --:--:-- > <snip> > NOTE: Executing Tasks > > ERROR: ovmf-edk2-stable202202-r0 do_patch: Applying patch > 'CVE-2022-36763-0001.patch' on target directory > '/home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/git' > CmdError('quilt --quiltrc > /home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/recipe-sysroot-native/etc/quiltrc > push', 0, 'stdout: Applying patch CVE-2022-36763-0001.patch > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c > Hunk #1 FAILED at 20 (different line endings). > Hunk #2 FAILED at 44 (different line endings). > Hunk #3 FAILED at 144 (different line endings). > Hunk #4 FAILED at 195 (different line endings). > Hunk #5 FAILED at 223 (different line endings). > Hunk #6 FAILED at 248 (different line endings). > Hunk #7 FAILED at 310 (different line endings). > Hunk #8 FAILED at 326 (different line endings). > Hunk #9 FAILED at 443 (different line endings). > Hunk #10 FAILED at 515 (different line endings). > Hunk #11 FAILED at 646 (different line endings). > 11 out of 11 hunks FAILED -- rejects in file > SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf > Hunk #1 FAILED at 37 (different line endings). > Hunk #2 FAILED at 46 (different line endings). > Hunk #3 FAILED at 65 (different line endings). > 3 out of 3 hunks FAILED -- rejects in file > SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf > patching file SecurityPkg/SecurityPkg.ci.yaml > Hunk #1 FAILED at 15 (different line endings). > 1 out of 1 hunk FAILED -- rejects in file SecurityPkg/SecurityPkg.ci.yaml > Patch CVE-2022-36763-0001.patch does not apply (enforce with -f) > > stderr: ') > ERROR: Logfile of failure stored in: > /home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/temp/log.do_patch.2851600 > ERROR: Task (/home/steve/builds/poky-contrib-kirkstone/meta/recipes-core/ovmf/ovmf_git.bb:do_patch) > failed with exit code '1' > NOTE: Tasks Summary: Attempted 1094 tasks of which 1085 didn't need to > be rerun and 1 failed. > Complete CVE report summary created at: > /home/steve/builds/poky-contrib-kirkstone/build/tmp/log/cve/cve-summary > NOTE: Generating JSON CVE summary > Complete CVE JSON report summary created at: > /home/steve/builds/poky-contrib-kirkstone/build/tmp/log/cve/cve-summary.json > > Summary: 1 task failed: > /home/steve/builds/poky-contrib-kirkstone/meta/recipes-core/ovmf/ovmf_git.bb:do_patch > Summary: There was 1 ERROR message, returning a non-zero exit code. > > Any suggestions? If you have a public git repo perhaps I could pull the patches directly from there? Steve > > Steve > > > ________________________________ > > From: Steve Sakoman <steve@sakoman.com> > > Sent: Wednesday, November 27, 2024 10:50 PM > > To: Jia, Hongxu <Hongxu.Jia@windriver.com> > > Cc: openembedded-core@lists.openembedded.org <openembedded-core@lists.openembedded.org> > > Subject: Re: [kirkstone][PATCH V2 01/13] ovmf: Fix CVE-2022-36763 > > > > CAUTION: This email comes from a non Wind River email account! > > Do not click links or open attachments unless you recognize the sender and know the content is safe. > > > > I am getting build time errors with this patch: > > > > ERROR: ovmf-edk2-stable202202-r0 do_patch: Applying patch > > 'CVE-2022-36763-0001.patch' on target directory > > '/home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/git' > > CmdError('quilt --quiltrc > > /home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/recipe-sysroot-native/etc/quiltrc > > push', 0, 'stdout: Applying patch CVE-2022-36763-0001.patch > > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c > > Hunk #1 FAILED at 20 (different line endings). > > Hunk #2 FAILED at 44 (different line endings). > > Hunk #3 FAILED at 144 (different line endings). > > Hunk #4 FAILED at 195 (different line endings). > > Hunk #5 FAILED at 223 (different line endings). > > Hunk #6 FAILED at 248 (different line endings). > > Hunk #7 FAILED at 310 (different line endings). > > Hunk #8 FAILED at 326 (different line endings). > > Hunk #9 FAILED at 443 (different line endings). > > Hunk #10 FAILED at 515 (different line endings). > > Hunk #11 FAILED at 646 (different line endings). > > 11 out of 11 hunks FAILED -- rejects in file > > SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c > > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf > > Hunk #1 FAILED at 37 (different line endings). > > Hunk #2 FAILED at 46 (different line endings). > > Hunk #3 FAILED at 65 (different line endings). > > 3 out of 3 hunks FAILED -- rejects in file > > SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf > > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c > > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h > > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c > > patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf > > patching file SecurityPkg/SecurityPkg.ci.yaml > > Hunk #1 FAILED at 15 (different line endings). > > 1 out of 1 hunk FAILED -- rejects in file SecurityPkg/SecurityPkg.ci.yaml > > Patch CVE-2022-36763-0001.patch does not apply (enforce with -f) > > > > Please submit a V2 of this series with the line ending issues fixed. > > > > Thanks! > > > > Steve > > > > On Mon, Nov 25, 2024 at 6:25 PM Hongxu Jia <hongxu.jia@windriver.com> wrote: > > > > > > From: Soumya Sambu <soumya.sambu@windriver.com> > > > > > > EDK2 is susceptible to a vulnerability in the Tcg2MeasureGptTable() > > > function, allowing a user to trigger a heap buffer overflow via a local > > > network. Successful exploitation of this vulnerability may result in a > > > compromise of confidentiality, integrity, and/or availability. > > > > > > References: > > > https://nvd.nist.gov/vuln/detail/CVE-2022-36763 > > > > > > Upstream-patches: > > > https://github.com/tianocore/edk2/commit/224446543206450ddb5830e6abd026d61d3c7f4b > > > https://github.com/tianocore/edk2/commit/4776a1b39ee08fc45c70c1eab5a0195f325000d3 > > > https://github.com/tianocore/edk2/commit/1ddcb9fc6b4164e882687b031e8beacfcf7df29e > > > > > > Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> > > > --- > > > .../ovmf/ovmf/CVE-2022-36763-0001.patch | 985 ++++++++++++++++++ > > > .../ovmf/ovmf/CVE-2022-36763-0002.patch | 889 ++++++++++++++++ > > > .../ovmf/ovmf/CVE-2022-36763-0003.patch | 55 + > > > meta/recipes-core/ovmf/ovmf_git.bb | 3 + > > > 4 files changed, 1932 insertions(+) > > > create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch > > > create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch > > > create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch > > > > > > diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch > > > new file mode 100644 > > > index 0000000000..93cefe7740 > > > --- /dev/null > > > +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch > > > @@ -0,0 +1,985 @@ > > > +From 224446543206450ddb5830e6abd026d61d3c7f4b Mon Sep 17 00:00:00 2001 > > > +From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com> > > > +Date: Fri, 12 Jan 2024 02:16:01 +0800 > > > +Subject: [PATCH] SecurityPkg: DxeTpm2MeasureBootLib: SECURITY PATCH 4117 - CVE > > > + 2022-36763 > > > + > > > +This commit contains the patch files and tests for DxeTpm2MeasureBootLib > > > +CVE 2022-36763. > > > + > > > +Cc: Jiewen Yao <jiewen.yao@intel.com> > > > + > > > +Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> > > > + > > > +CVE: CVE-2022-36763 > > > + > > > +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/224446543206450ddb5830e6abd026d61d3c7f4b] > > > + > > > +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> > > > +--- > > > + .../DxeTpm2MeasureBootLib.c | 69 ++-- > > > + .../DxeTpm2MeasureBootLib.inf | 4 +- > > > + .../DxeTpm2MeasureBootLibSanitization.c | 275 ++++++++++++++++ > > > + .../DxeTpm2MeasureBootLibSanitization.h | 113 +++++++ > > > + .../DxeTpm2MeasureBootLibSanitizationTest.c | 303 ++++++++++++++++++ > > > + ...Tpm2MeasureBootLibSanitizationTestHost.inf | 28 ++ > > > + SecurityPkg/SecurityPkg.ci.yaml | 1 + > > > + 7 files changed, 763 insertions(+), 30 deletions(-) > > > + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c > > > + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h > > > + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c > > > + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf > > > + > > > +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c > > > +index 36a256a7af..0475103d6e 100644 > > > +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c > > > ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c > > > +@@ -20,6 +20,8 @@ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> > > > + (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> > > > + SPDX-License-Identifier: BSD-2-Clause-Patent > > > + > > > ++Copyright (c) Microsoft Corporation.<BR> > > > ++SPDX-License-Identifier: BSD-2-Clause-Patent > > > + **/ > > > + > > > + #include <PiDxe.h> > > > +@@ -44,6 +46,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent > > > + #include <Library/HobLib.h> > > > + #include <Protocol/CcMeasurement.h> > > > + > > > ++#include "DxeTpm2MeasureBootLibSanitization.h" > > > ++ > > > + typedef struct { > > > + EFI_TCG2_PROTOCOL *Tcg2Protocol; > > > + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol; > > > +@@ -144,10 +148,11 @@ Tcg2MeasureGptTable ( > > > + EFI_TCG2_EVENT *Tcg2Event; > > > + EFI_CC_EVENT *CcEvent; > > > + EFI_GPT_DATA *GptData; > > > +- UINT32 EventSize; > > > ++ UINT32 TcgEventSize; > > > + EFI_TCG2_PROTOCOL *Tcg2Protocol; > > > + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol; > > > + EFI_CC_MR_INDEX MrIndex; > > > ++ UINT32 AllocSize; > > > + > > > + if (mTcg2MeasureGptCount > 0) { > > > + return EFI_SUCCESS; > > > +@@ -195,25 +200,22 @@ Tcg2MeasureGptTable ( > > > + BlockIo->Media->BlockSize, > > > + (UINT8 *)PrimaryHeader > > > + ); > > > +- if (EFI_ERROR (Status)) { > > > +- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n")); > > > ++ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) { > > > ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n")); > > > + FreePool (PrimaryHeader); > > > + return EFI_DEVICE_ERROR; > > > + } > > > + > > > + // > > > +- // PrimaryHeader->SizeOfPartitionEntry should not be zero > > > ++ // Read the partition entry. > > > + // > > > +- if (PrimaryHeader->SizeOfPartitionEntry == 0) { > > > +- DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry should not be zero!\n")); > > > ++ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize); > > > ++ if (EFI_ERROR (Status)) { > > > + FreePool (PrimaryHeader); > > > + return EFI_BAD_BUFFER_SIZE; > > > + } > > > + > > > +- // > > > +- // Read the partition entry. > > > +- // > > > +- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry); > > > ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize); > > > + if (EntryPtr == NULL) { > > > + FreePool (PrimaryHeader); > > > + return EFI_OUT_OF_RESOURCES; > > > +@@ -223,7 +225,7 @@ Tcg2MeasureGptTable ( > > > + DiskIo, > > > + BlockIo->Media->MediaId, > > > + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), > > > +- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry, > > > ++ AllocSize, > > > + EntryPtr > > > + ); > > > + if (EFI_ERROR (Status)) { > > > +@@ -248,16 +250,21 @@ Tcg2MeasureGptTable ( > > > + // > > > + // Prepare Data for Measurement (CcProtocol and Tcg2Protocol) > > > + // > > > +- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) > > > +- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry); > > > +- EventPtr = (UINT8 *)AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)); > > > ++ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &TcgEventSize); > > > ++ if (EFI_ERROR (Status)) { > > > ++ FreePool (PrimaryHeader); > > > ++ FreePool (EntryPtr); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ EventPtr = (UINT8 *)AllocateZeroPool (TcgEventSize); > > > + if (EventPtr == NULL) { > > > + Status = EFI_OUT_OF_RESOURCES; > > > + goto Exit; > > > + } > > > + > > > + Tcg2Event = (EFI_TCG2_EVENT *)EventPtr; > > > +- Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event); > > > ++ Tcg2Event->Size = TcgEventSize; > > > + Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER); > > > + Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; > > > + Tcg2Event->Header.PCRIndex = 5; > > > +@@ -310,7 +317,7 @@ Tcg2MeasureGptTable ( > > > + CcProtocol, > > > + 0, > > > + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData, > > > +- (UINT64)EventSize, > > > ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), > > > + CcEvent > > > + ); > > > + if (!EFI_ERROR (Status)) { > > > +@@ -326,7 +333,7 @@ Tcg2MeasureGptTable ( > > > + Tcg2Protocol, > > > + 0, > > > + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData, > > > +- (UINT64)EventSize, > > > ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), > > > + Tcg2Event > > > + ); > > > + if (!EFI_ERROR (Status)) { > > > +@@ -443,11 +450,13 @@ Tcg2MeasurePeImage ( > > > + Tcg2Event->Header.PCRIndex = 2; > > > + break; > > > + default: > > > +- DEBUG (( > > > +- DEBUG_ERROR, > > > +- "Tcg2MeasurePeImage: Unknown subsystem type %d", > > > +- ImageType > > > +- )); > > > ++ DEBUG ( > > > ++ ( > > > ++ DEBUG_ERROR, > > > ++ "Tcg2MeasurePeImage: Unknown subsystem type %d", > > > ++ ImageType > > > ++ ) > > > ++ ); > > > + goto Finish; > > > + } > > > + > > > +@@ -515,7 +524,7 @@ Finish: > > > + > > > + @param MeasureBootProtocols Pointer to the located measure boot protocol instances. > > > + > > > +- @retval EFI_SUCCESS Sucessfully locate the measure boot protocol instances (at least one instance). > > > ++ @retval EFI_SUCCESS Successfully locate the measure boot protocol instances (at least one instance). > > > + @retval EFI_UNSUPPORTED Measure boot is not supported. > > > + **/ > > > + EFI_STATUS > > > +@@ -646,12 +655,14 @@ DxeTpm2MeasureBootHandler ( > > > + return EFI_SUCCESS; > > > + } > > > + > > > +- DEBUG (( > > > +- DEBUG_INFO, > > > +- "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n", > > > +- MeasureBootProtocols.Tcg2Protocol, > > > +- MeasureBootProtocols.CcProtocol > > > +- )); > > > ++ DEBUG ( > > > ++ ( > > > ++ DEBUG_INFO, > > > ++ "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n", > > > ++ MeasureBootProtocols.Tcg2Protocol, > > > ++ MeasureBootProtocols.CcProtocol > > > ++ ) > > > ++ ); > > > + > > > + // > > > + // Copy File Device Path > > > +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf > > > +index 6dca79a20c..28995f438d 100644 > > > +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf > > > ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf > > > +@@ -37,6 +37,8 @@ > > > + > > > + [Sources] > > > + DxeTpm2MeasureBootLib.c > > > ++ DxeTpm2MeasureBootLibSanitization.c > > > ++ DxeTpm2MeasureBootLibSanitization.h > > > + > > > + [Packages] > > > + MdePkg/MdePkg.dec > > > +@@ -46,6 +48,7 @@ > > > + > > > + [LibraryClasses] > > > + BaseMemoryLib > > > ++ SafeIntLib > > > + DebugLib > > > + MemoryAllocationLib > > > + DevicePathLib > > > +@@ -65,4 +68,3 @@ > > > + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES > > > + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES > > > + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES > > > +- > > > +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c > > > +new file mode 100644 > > > +index 0000000000..e2309655d3 > > > +--- /dev/null > > > ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c > > > +@@ -0,0 +1,275 @@ > > > ++/** @file > > > ++ The library instance provides security service of TPM2 measure boot and > > > ++ Confidential Computing (CC) 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. > > > ++ > > > ++ This file will pull out the validation logic from the following functions, in an > > > ++ attempt to validate the untrusted input in the form of unit tests > > > ++ > > > ++ These are those functions: > > > ++ > > > ++ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content > > > ++ read is within the image buffer. > > > ++ > > > ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse > > > ++ partition data carefully. > > > ++ > > > ++ Copyright (c) Microsoft Corporation.<BR> > > > ++ SPDX-License-Identifier: BSD-2-Clause-Patent > > > ++**/ > > > ++#include <Uefi.h> > > > ++#include <Uefi/UefiSpec.h> > > > ++#include <Library/SafeIntLib.h> > > > ++#include <Library/UefiLib.h> > > > ++#include <Library/DebugLib.h> > > > ++#include <Library/BaseLib.h> > > > ++#include <IndustryStandard/UefiTcgPlatform.h> > > > ++#include <Protocol/BlockIo.h> > > > ++#include <Library/MemoryAllocationLib.h> > > > ++ > > > ++#include "DxeTpm2MeasureBootLibSanitization.h" > > > ++ > > > ++#define GPT_HEADER_REVISION_V1 0x00010000 > > > ++ > > > ++/** > > > ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse > > > ++ However this function will not attempt to verify the validity of the GPT partition > > > ++ It will check the following: > > > ++ - Signature > > > ++ - Revision > > > ++ - AlternateLBA > > > ++ - FirstUsableLBA > > > ++ - LastUsableLBA > > > ++ - PartitionEntryLBA > > > ++ - NumberOfPartitionEntries > > > ++ - SizeOfPartitionEntry > > > ++ - BlockIo > > > ++ > > > ++ @param[in] PrimaryHeader > > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > > ++ > > > ++ @param[in] BlockIo > > > ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. > > > ++ > > > ++ @retval EFI_SUCCESS > > > ++ The EFI_PARTITION_TABLE_HEADER structure is valid. > > > ++ > > > ++ @retval EFI_INVALID_PARAMETER > > > ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. > > > ++**/ > > > ++EFI_STATUS > > > ++EFIAPI > > > ++SanitizeEfiPartitionTableHeader ( > > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > > ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo > > > ++ ) > > > ++{ > > > ++ // > > > ++ // Verify that the input parameters are safe to use > > > ++ // > > > ++ if (PrimaryHeader == NULL) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); > > > ++ return EFI_INVALID_PARAMETER; > > > ++ } > > > ++ > > > ++ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n")); > > > ++ return EFI_INVALID_PARAMETER; > > > ++ } > > > ++ > > > ++ // > > > ++ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII) > > > ++ // > > > ++ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ // > > > ++ // The version must be GPT_HEADER_REVISION_V1 (0x00010000) > > > ++ // > > > ++ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n")); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ // > > > ++ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size > > > ++ // > > > ++ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n")); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ // > > > ++ // The partition entries should all be before the first usable block > > > ++ // > > > ++ if (PrimaryHeader->FirstUsableLBA <= PrimaryHeader->PartitionEntryLBA) { > > > ++ DEBUG ((DEBUG_ERROR, "GPT PartitionEntryLBA is not less than FirstUsableLBA!\n")); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ // > > > ++ // Check that the PartitionEntryLBA greater than the Max LBA > > > ++ // This will be used later for multiplication > > > ++ // > > > ++ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n")); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ // > > > ++ // Check that the number of partition entries is greater than zero > > > ++ // > > > ++ if (PrimaryHeader->NumberOfPartitionEntries == 0) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ // > > > ++ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory > > > ++ // > > > ++ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) { > > > ++ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n")); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ // > > > ++ // This check is to prevent overflow when calculating the allocation size for the partition entries > > > ++ // This check will be used later for multiplication > > > ++ // > > > ++ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ return EFI_SUCCESS; > > > ++} > > > ++ > > > ++/** > > > ++ This function will validate that the allocation size from the primary header is sane > > > ++ It will check the following: > > > ++ - AllocationSize does not overflow > > > ++ > > > ++ @param[in] PrimaryHeader > > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > > ++ > > > ++ @param[out] AllocationSize > > > ++ Pointer to the allocation size. > > > ++ > > > ++ @retval EFI_SUCCESS > > > ++ The allocation size is valid. > > > ++ > > > ++ @retval EFI_OUT_OF_RESOURCES > > > ++ The allocation size is invalid. > > > ++**/ > > > ++EFI_STATUS > > > ++EFIAPI > > > ++SanitizePrimaryHeaderAllocationSize ( > > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > > ++ OUT UINT32 *AllocationSize > > > ++ ) > > > ++{ > > > ++ EFI_STATUS Status; > > > ++ > > > ++ if (PrimaryHeader == NULL) { > > > ++ return EFI_INVALID_PARAMETER; > > > ++ } > > > ++ > > > ++ if (AllocationSize == NULL) { > > > ++ return EFI_INVALID_PARAMETER; > > > ++ } > > > ++ > > > ++ // > > > ++ // Replacing logic: > > > ++ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry; > > > ++ // > > > ++ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize); > > > ++ if (EFI_ERROR (Status)) { > > > ++ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n")); > > > ++ return EFI_BAD_BUFFER_SIZE; > > > ++ } > > > ++ > > > ++ return EFI_SUCCESS; > > > ++} > > > ++ > > > ++/** > > > ++ This function will validate that the Gpt Event Size calculated from the primary header is sane > > > ++ It will check the following: > > > ++ - EventSize does not overflow > > > ++ > > > ++ Important: This function includes the entire length of the allocated space, including > > > ++ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this > > > ++ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) > > > ++ from the size of the buffer before hashing. > > > ++ > > > ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > > ++ @param[in] NumberOfPartition - Number of partitions. > > > ++ @param[out] EventSize - Pointer to the event size. > > > ++ > > > ++ @retval EFI_SUCCESS > > > ++ The event size is valid. > > > ++ > > > ++ @retval EFI_OUT_OF_RESOURCES > > > ++ Overflow would have occurred. > > > ++ > > > ++ @retval EFI_INVALID_PARAMETER > > > ++ One of the passed parameters was invalid. > > > ++**/ > > > ++EFI_STATUS > > > ++SanitizePrimaryHeaderGptEventSize ( > > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > > ++ IN UINTN NumberOfPartition, > > > ++ OUT UINT32 *EventSize > > > ++ ) > > > ++{ > > > ++ EFI_STATUS Status; > > > ++ UINT32 SafeNumberOfPartitions; > > > ++ > > > ++ if (PrimaryHeader == NULL) { > > > ++ return EFI_INVALID_PARAMETER; > > > ++ } > > > ++ > > > ++ if (EventSize == NULL) { > > > ++ return EFI_INVALID_PARAMETER; > > > ++ } > > > ++ > > > ++ // > > > ++ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32 > > > ++ // > > > ++ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions); > > > ++ if (EFI_ERROR (Status)) { > > > ++ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n")); > > > ++ return EFI_INVALID_PARAMETER; > > > ++ } > > > ++ > > > ++ // > > > ++ // Replacing logic: > > > ++ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry); > > > ++ // > > > ++ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize); > > > ++ if (EFI_ERROR (Status)) { > > > ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n")); > > > ++ return EFI_BAD_BUFFER_SIZE; > > > ++ } > > > ++ > > > ++ // > > > ++ // Replacing logic: > > > ++ // *EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event); > > > ++ // > > > ++ Status = SafeUint32Add ( > > > ++ OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions), > > > ++ *EventSize, > > > ++ EventSize > > > ++ ); > > > ++ if (EFI_ERROR (Status)) { > > > ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n")); > > > ++ return EFI_BAD_BUFFER_SIZE; > > > ++ } > > > ++ > > > ++ return EFI_SUCCESS; > > > ++} > > > +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h > > > +new file mode 100644 > > > +index 0000000000..048b738987 > > > +--- /dev/null > > > ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h > > > +@@ -0,0 +1,113 @@ > > > ++/** @file > > > ++ This file includes the function prototypes for the sanitization functions. > > > ++ > > > ++ These are those functions: > > > ++ > > > ++ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content > > > ++ read is within the image buffer. > > > ++ > > > ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse > > > ++ partition data carefully. > > > ++ > > > ++ Copyright (c) Microsoft Corporation.<BR> > > > ++ SPDX-License-Identifier: BSD-2-Clause-Patent > > > ++ > > > ++**/ > > > ++ > > > ++#ifndef DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ > > > ++#define DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ > > > ++ > > > ++#include <Uefi.h> > > > ++#include <Uefi/UefiSpec.h> > > > ++#include <Protocol/BlockIo.h> > > > ++#include <IndustryStandard/UefiTcgPlatform.h> > > > ++#include <Protocol/Tcg2Protocol.h> > > > ++ > > > ++/** > > > ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse > > > ++ However this function will not attempt to verify the validity of the GPT partition > > > ++ It will check the following: > > > ++ - Signature > > > ++ - Revision > > > ++ - AlternateLBA > > > ++ - FirstUsableLBA > > > ++ - LastUsableLBA > > > ++ - PartitionEntryLBA > > > ++ - NumberOfPartitionEntries > > > ++ - SizeOfPartitionEntry > > > ++ - BlockIo > > > ++ > > > ++ @param[in] PrimaryHeader > > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > > ++ > > > ++ @param[in] BlockIo > > > ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. > > > ++ > > > ++ @retval EFI_SUCCESS > > > ++ The EFI_PARTITION_TABLE_HEADER structure is valid. > > > ++ > > > ++ @retval EFI_INVALID_PARAMETER > > > ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. > > > ++**/ > > > ++EFI_STATUS > > > ++EFIAPI > > > ++SanitizeEfiPartitionTableHeader ( > > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > > ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo > > > ++ ); > > > ++ > > > ++/** > > > ++ This function will validate that the allocation size from the primary header is sane > > > ++ It will check the following: > > > ++ - AllocationSize does not overflow > > > ++ > > > ++ @param[in] PrimaryHeader > > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > > ++ > > > ++ @param[out] AllocationSize > > > ++ Pointer to the allocation size. > > > ++ > > > ++ @retval EFI_SUCCESS > > > ++ The allocation size is valid. > > > ++ > > > ++ @retval EFI_OUT_OF_RESOURCES > > > ++ The allocation size is invalid. > > > ++**/ > > > ++EFI_STATUS > > > ++EFIAPI > > > ++SanitizePrimaryHeaderAllocationSize ( > > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > > ++ OUT UINT32 *AllocationSize > > > ++ ); > > > ++ > > > ++/** > > > ++ This function will validate that the Gpt Event Size calculated from the primary header is sane > > > ++ It will check the following: > > > ++ - EventSize does not overflow > > > ++ > > > ++ Important: This function includes the entire length of the allocated space, including > > > ++ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this > > > ++ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) > > > ++ from the size of the buffer before hashing. > > > ++ > > > ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > > ++ @param[in] NumberOfPartition - Number of partitions. > > > ++ @param[out] EventSize - Pointer to the event size. > > > ++ > > > ++ @retval EFI_SUCCESS > > > ++ The event size is valid. > > > ++ > > > ++ @retval EFI_OUT_OF_RESOURCES > > > ++ Overflow would have occurred. > > > ++ > > > ++ @retval EFI_INVALID_PARAMETER > > > ++ One of the passed parameters was invalid. > > > ++**/ > > > ++EFI_STATUS > > > ++SanitizePrimaryHeaderGptEventSize ( > > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > > ++ IN UINTN NumberOfPartition, > > > ++ OUT UINT32 *EventSize > > > ++ ); > > > ++ > > > ++#endif // DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ > > > +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c > > > +new file mode 100644 > > > +index 0000000000..3eb9763e3c > > > +--- /dev/null > > > ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c > > > +@@ -0,0 +1,303 @@ > > > ++/** @file > > > ++ This file includes the unit test cases for the DxeTpm2MeasureBootLibSanitizationTest.c. > > > ++ > > > ++ Copyright (c) Microsoft Corporation.<BR> > > > ++ SPDX-License-Identifier: BSD-2-Clause-Patent > > > ++**/ > > > ++ > > > ++#include <Uefi.h> > > > ++#include <Library/UefiLib.h> > > > ++#include <Library/DebugLib.h> > > > ++#include <Library/UnitTestLib.h> > > > ++#include <Protocol/BlockIo.h> > > > ++#include <Library/MemoryAllocationLib.h> > > > ++#include <Library/BaseMemoryLib.h> > > > ++#include <IndustryStandard/UefiTcgPlatform.h> > > > ++#include <Protocol/Tcg2Protocol.h> > > > ++ > > > ++#include "../DxeTpm2MeasureBootLibSanitization.h" > > > ++ > > > ++#define UNIT_TEST_NAME "DxeTpm2MeasureBootLibSanitizationTest" > > > ++#define UNIT_TEST_VERSION "1.0" > > > ++ > > > ++#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000 > > > ++#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1 > > > ++#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128 > > > ++ > > > ++/** > > > ++ This function tests the SanitizeEfiPartitionTableHeader function. > > > ++ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER > > > ++ structure will not cause undefined or unexpected behavior. > > > ++ > > > ++ In general the TPM should still be able to measure the data, but > > > ++ be the header should be sanitized to prevent any unexpected behavior. > > > ++ > > > ++ @param[in] Context The unit test context. > > > ++ > > > ++ @retval UNIT_TEST_PASSED The test passed. > > > ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. > > > ++**/ > > > ++UNIT_TEST_STATUS > > > ++EFIAPI > > > ++TestSanitizeEfiPartitionTableHeader ( > > > ++ IN UNIT_TEST_CONTEXT Context > > > ++ ) > > > ++{ > > > ++ EFI_STATUS Status; > > > ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; > > > ++ EFI_BLOCK_IO_PROTOCOL BlockIo; > > > ++ EFI_BLOCK_IO_MEDIA BlockMedia; > > > ++ > > > ++ // Generate EFI_BLOCK_IO_MEDIA test data > > > ++ BlockMedia.MediaId = 1; > > > ++ BlockMedia.RemovableMedia = FALSE; > > > ++ BlockMedia.MediaPresent = TRUE; > > > ++ BlockMedia.LogicalPartition = FALSE; > > > ++ BlockMedia.ReadOnly = FALSE; > > > ++ BlockMedia.WriteCaching = FALSE; > > > ++ BlockMedia.BlockSize = 512; > > > ++ BlockMedia.IoAlign = 1; > > > ++ BlockMedia.LastBlock = 0; > > > ++ > > > ++ // Generate EFI_BLOCK_IO_PROTOCOL test data > > > ++ BlockIo.Revision = 1; > > > ++ BlockIo.Media = &BlockMedia; > > > ++ BlockIo.Reset = NULL; > > > ++ BlockIo.ReadBlocks = NULL; > > > ++ BlockIo.WriteBlocks = NULL; > > > ++ BlockIo.FlushBlocks = NULL; > > > ++ > > > ++ // Geneate EFI_PARTITION_TABLE_HEADER test data > > > ++ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID; > > > ++ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION; > > > ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); > > > ++ PrimaryHeader.MyLBA = 1; > > > ++ PrimaryHeader.AlternateLBA = 2; > > > ++ PrimaryHeader.FirstUsableLBA = 3; > > > ++ PrimaryHeader.LastUsableLBA = 4; > > > ++ PrimaryHeader.PartitionEntryLBA = 5; > > > ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES; > > > ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > > ++ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid > > > ++ > > > ++ // Calculate the CRC32 of the PrimaryHeader > > > ++ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize); > > > ++ > > > ++ // Test that a normal PrimaryHeader passes validation > > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > > ++ UT_ASSERT_NOT_EFI_ERROR (Status); > > > ++ > > > ++ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR > > > ++ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!"" > > > ++ PrimaryHeader.NumberOfPartitionEntries = 0; > > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > > ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); > > > ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > > ++ > > > ++ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR > > > ++ // Should print "Invalid Partition Table Header Size!" > > > ++ PrimaryHeader.Header.HeaderSize = 0; > > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > > ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); > > > ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); > > > ++ > > > ++ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR > > > ++ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!" > > > ++ PrimaryHeader.SizeOfPartitionEntry = 1; > > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > > ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); > > > ++ > > > ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); > > > ++ > > > ++ return UNIT_TEST_PASSED; > > > ++} > > > ++ > > > ++/** > > > ++ This function tests the SanitizePrimaryHeaderAllocationSize function. > > > ++ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER > > > ++ structure will not cause an overflow when calculating the allocation size. > > > ++ > > > ++ @param[in] Context The unit test context. > > > ++ > > > ++ @retval UNIT_TEST_PASSED The test passed. > > > ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. > > > ++**/ > > > ++UNIT_TEST_STATUS > > > ++EFIAPI > > > ++TestSanitizePrimaryHeaderAllocationSize ( > > > ++ IN UNIT_TEST_CONTEXT Context > > > ++ ) > > > ++{ > > > ++ UINT32 AllocationSize; > > > ++ > > > ++ EFI_STATUS Status; > > > ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; > > > ++ > > > ++ // Test that a normal PrimaryHeader passes validation > > > ++ PrimaryHeader.NumberOfPartitionEntries = 5; > > > ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > > ++ > > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > > ++ UT_ASSERT_NOT_EFI_ERROR (Status); > > > ++ > > > ++ // Test that the allocation size is correct compared to the existing logic > > > ++ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry); > > > ++ > > > ++ // Test that an overflow is detected > > > ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; > > > ++ PrimaryHeader.SizeOfPartitionEntry = 5; > > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > > ++ > > > ++ // Test the inverse > > > ++ PrimaryHeader.NumberOfPartitionEntries = 5; > > > ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; > > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > > ++ > > > ++ // Test the worst case scenario > > > ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; > > > ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; > > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > > ++ > > > ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); > > > ++ > > > ++ return UNIT_TEST_PASSED; > > > ++} > > > ++ > > > ++/** > > > ++ This function tests the SanitizePrimaryHeaderGptEventSize function. > > > ++ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure > > > ++ will not cause an overflow when calculating the event size. > > > ++ > > > ++ @param[in] Context The unit test context. > > > ++ > > > ++ @retval UNIT_TEST_PASSED The test passed. > > > ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. > > > ++**/ > > > ++UNIT_TEST_STATUS > > > ++EFIAPI > > > ++TestSanitizePrimaryHeaderGptEventSize ( > > > ++ IN UNIT_TEST_CONTEXT Context > > > ++ ) > > > ++{ > > > ++ UINT32 EventSize; > > > ++ UINT32 ExistingLogicEventSize; > > > ++ EFI_STATUS Status; > > > ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; > > > ++ UINTN NumberOfPartition; > > > ++ EFI_GPT_DATA *GptData; > > > ++ EFI_TCG2_EVENT *Tcg2Event; > > > ++ > > > ++ Tcg2Event = NULL; > > > ++ GptData = NULL; > > > ++ > > > ++ // Test that a normal PrimaryHeader passes validation > > > ++ PrimaryHeader.NumberOfPartitionEntries = 5; > > > ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > > ++ > > > ++ // set the number of partitions > > > ++ NumberOfPartition = 13; > > > ++ > > > ++ // that the primary event size is correct > > > ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); > > > ++ UT_ASSERT_NOT_EFI_ERROR (Status); > > > ++ > > > ++ // Calculate the existing logic event size > > > ++ ExistingLogicEventSize = (UINT32)(OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions) > > > ++ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry); > > > ++ > > > ++ // Check that the event size is correct > > > ++ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize); > > > ++ > > > ++ // Tests that the primary event size may not overflow > > > ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize); > > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > > ++ > > > ++ // Test that the size of partition entries may not overflow > > > ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; > > > ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); > > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > > ++ > > > ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); > > > ++ > > > ++ return UNIT_TEST_PASSED; > > > ++} > > > ++ > > > ++// *--------------------------------------------------------------------* > > > ++// * Unit Test Code Main Function > > > ++// *--------------------------------------------------------------------* > > > ++ > > > ++/** > > > ++ This function acts as the entry point for the unit tests. > > > ++ > > > ++ @retval UNIT_TEST_PASSED The test passed. > > > ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. > > > ++ @retval others The test failed. > > > ++**/ > > > ++EFI_STATUS > > > ++EFIAPI > > > ++UefiTestMain ( > > > ++ VOID > > > ++ ) > > > ++{ > > > ++ EFI_STATUS Status; > > > ++ UNIT_TEST_FRAMEWORK_HANDLE Framework; > > > ++ UNIT_TEST_SUITE_HANDLE Tcg2MeasureBootLibValidationTestSuite; > > > ++ > > > ++ Framework = NULL; > > > ++ > > > ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME)); > > > ++ > > > ++ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION); > > > ++ if (EFI_ERROR (Status)) { > > > ++ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status)); > > > ++ goto EXIT; > > > ++ } > > > ++ > > > ++ Status = CreateUnitTestSuite (&Tcg2MeasureBootLibValidationTestSuite, Framework, "Tcg2MeasureBootLibValidationTestSuite", "Common.Tcg2MeasureBootLibValidation", NULL, NULL); > > > ++ if (EFI_ERROR (Status)) { > > > ++ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for Tcg2MeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME)); > > > ++ Status = EFI_OUT_OF_RESOURCES; > > > ++ goto EXIT; > > > ++ } > > > ++ > > > ++ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context > > > ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.Tcg2MeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL); > > > ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL); > > > ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL); > > > ++ > > > ++ Status = RunAllTestSuites (Framework); > > > ++ > > > ++EXIT: > > > ++ if (Framework != NULL) { > > > ++ FreeUnitTestFramework (Framework); > > > ++ } > > > ++ > > > ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME)); > > > ++ return Status; > > > ++} > > > ++ > > > ++/// > > > ++/// Avoid ECC error for function name that starts with lower case letter > > > ++/// > > > ++#define DxeTpm2MeasureBootLibUnitTestMain main > > > ++ > > > ++/** > > > ++ Standard POSIX C entry point for host based unit test execution. > > > ++ > > > ++ @param[in] Argc Number of arguments > > > ++ @param[in] Argv Array of pointers to arguments > > > ++ > > > ++ @retval 0 Success > > > ++ @retval other Error > > > ++**/ > > > ++INT32 > > > ++DxeTpm2MeasureBootLibUnitTestMain ( > > > ++ IN INT32 Argc, > > > ++ IN CHAR8 *Argv[] > > > ++ ) > > > ++{ > > > ++ return (INT32)UefiTestMain (); > > > ++} > > > +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf > > > +new file mode 100644 > > > +index 0000000000..2999aa2a44 > > > +--- /dev/null > > > ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf > > > +@@ -0,0 +1,28 @@ > > > ++## @file > > > ++# This file builds the unit tests for DxeTpm2MeasureBootLib > > > ++# > > > ++# Copyright (C) Microsoft Corporation.<BR> > > > ++# SPDX-License-Identifier: BSD-2-Clause-Patent > > > ++## > > > ++ > > > ++[Defines] > > > ++ INF_VERSION = 0x00010006 > > > ++ BASE_NAME = DxeTpm2MeasuredBootLibTest > > > ++ FILE_GUID = 144d757f-d423-484e-9309-a23695fad5bd > > > ++ MODULE_TYPE = HOST_APPLICATION > > > ++ VERSION_STRING = 1.0 > > > ++ ENTRY_POINT = main > > > ++ > > > ++[Sources] > > > ++ DxeTpm2MeasureBootLibSanitizationTest.c > > > ++ ../DxeTpm2MeasureBootLibSanitization.c > > > ++ > > > ++[Packages] > > > ++ MdePkg/MdePkg.dec > > > ++ > > > ++[LibraryClasses] > > > ++ BaseLib > > > ++ DebugLib > > > ++ UnitTestLib > > > ++ PrintLib > > > ++ SafeIntLib > > > +diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml > > > +index 7912142398..da811fdf93 100644 > > > +--- a/SecurityPkg/SecurityPkg.ci.yaml > > > ++++ b/SecurityPkg/SecurityPkg.ci.yaml > > > +@@ -15,6 +15,7 @@ > > > + ## "<ErrorID>", "<KeyWord>" > > > + ## ] > > > + "ExceptionList": [ > > > ++ "8001", "DxeTpm2MeasureBootLibUnitTestMain", > > > + ], > > > + ## Both file path and directory path are accepted. > > > + "IgnoreFiles": [ > > > +-- > > > +2.40.0 > > > + > > > diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch > > > new file mode 100644 > > > index 0000000000..6c20cc305e > > > --- /dev/null > > > +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch > > > @@ -0,0 +1,889 @@ > > > +From 4776a1b39ee08fc45c70c1eab5a0195f325000d3 Mon Sep 17 00:00:00 2001 > > > +From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com> > > > +Date: Fri, 12 Jan 2024 02:16:02 +0800 > > > +Subject: [PATCH] SecurityPkg: DxeTpmMeasureBootLib: SECURITY PATCH 4117 - CVE > > > + 2022-36763 > > > + > > > +This commit contains the patch files and tests for DxeTpmMeasureBootLib > > > +CVE 2022-36763. > > > + > > > +Cc: Jiewen Yao <jiewen.yao@intel.com> > > > + > > > +Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> > > > +Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> > > > + > > > +CVE: CVE-2022-36763 > > > + > > > +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/4776a1b39ee08fc45c70c1eab5a0195f325000d3] > > > + > > > +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> > > > +--- > > > + .../DxeTpmMeasureBootLib.c | 40 ++- > > > + .../DxeTpmMeasureBootLib.inf | 4 +- > > > + .../DxeTpmMeasureBootLibSanitization.c | 241 ++++++++++++++ > > > + .../DxeTpmMeasureBootLibSanitization.h | 114 +++++++ > > > + .../DxeTpmMeasureBootLibSanitizationTest.c | 301 ++++++++++++++++++ > > > + ...eTpmMeasureBootLibSanitizationTestHost.inf | 28 ++ > > > + SecurityPkg/SecurityPkg.ci.yaml | 1 + > > > + 7 files changed, 715 insertions(+), 14 deletions(-) > > > + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c > > > + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h > > > + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c > > > + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf > > > + > > > +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c > > > +index 220393dd2b..669ab19134 100644 > > > +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c > > > ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c > > > +@@ -18,6 +18,8 @@ > > > + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> > > > + SPDX-License-Identifier: BSD-2-Clause-Patent > > > + > > > ++Copyright (c) Microsoft Corporation.<BR> > > > ++SPDX-License-Identifier: BSD-2-Clause-Patent > > > + **/ > > > + > > > + #include <PiDxe.h> > > > +@@ -40,6 +42,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent > > > + #include <Library/SecurityManagementLib.h> > > > + #include <Library/HobLib.h> > > > + > > > ++#include "DxeTpmMeasureBootLibSanitization.h" > > > ++ > > > + // > > > + // Flag to check GPT partition. It only need be measured once. > > > + // > > > +@@ -136,6 +140,9 @@ TcgMeasureGptTable ( > > > + UINT32 EventSize; > > > + UINT32 EventNumber; > > > + EFI_PHYSICAL_ADDRESS EventLogLastEntry; > > > ++ UINT32 AllocSize; > > > ++ > > > ++ GptData = NULL; > > > + > > > + if (mMeasureGptCount > 0) { > > > + return EFI_SUCCESS; > > > +@@ -166,8 +173,8 @@ TcgMeasureGptTable ( > > > + BlockIo->Media->BlockSize, > > > + (UINT8 *)PrimaryHeader > > > + ); > > > +- if (EFI_ERROR (Status)) { > > > +- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n")); > > > ++ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) { > > > ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n")); > > > + FreePool (PrimaryHeader); > > > + return EFI_DEVICE_ERROR; > > > + } > > > +@@ -175,7 +182,13 @@ TcgMeasureGptTable ( > > > + // > > > + // Read the partition entry. > > > + // > > > +- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry); > > > ++ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize); > > > ++ if (EFI_ERROR (Status)) { > > > ++ FreePool (PrimaryHeader); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize); > > > + if (EntryPtr == NULL) { > > > + FreePool (PrimaryHeader); > > > + return EFI_OUT_OF_RESOURCES; > > > +@@ -185,7 +198,7 @@ TcgMeasureGptTable ( > > > + DiskIo, > > > + BlockIo->Media->MediaId, > > > + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), > > > +- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry, > > > ++ AllocSize, > > > + EntryPtr > > > + ); > > > + if (EFI_ERROR (Status)) { > > > +@@ -210,9 +223,8 @@ TcgMeasureGptTable ( > > > + // > > > + // Prepare Data for Measurement > > > + // > > > +- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) > > > +- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry); > > > +- TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT_HDR)); > > > ++ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &EventSize); > > > ++ TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize); > > > + if (TcgEvent == NULL) { > > > + FreePool (PrimaryHeader); > > > + FreePool (EntryPtr); > > > +@@ -221,7 +233,7 @@ TcgMeasureGptTable ( > > > + > > > + TcgEvent->PCRIndex = 5; > > > + TcgEvent->EventType = EV_EFI_GPT_EVENT; > > > +- TcgEvent->EventSize = EventSize; > > > ++ TcgEvent->EventSize = EventSize - sizeof (TCG_PCR_EVENT_HDR); > > > + GptData = (EFI_GPT_DATA *)TcgEvent->Event; > > > + > > > + // > > > +@@ -361,11 +373,13 @@ TcgMeasurePeImage ( > > > + TcgEvent->PCRIndex = 2; > > > + break; > > > + default: > > > +- DEBUG (( > > > +- DEBUG_ERROR, > > > +- "TcgMeasurePeImage: Unknown subsystem type %d", > > > +- ImageType > > > +- )); > > > ++ DEBUG ( > > > ++ ( > > > ++ DEBUG_ERROR, > > > ++ "TcgMeasurePeImage: Unknown subsystem type %d", > > > ++ ImageType > > > ++ ) > > > ++ ); > > > + goto Finish; > > > + } > > > + > > > +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf > > > +index ebab6f7c1e..414c654d15 100644 > > > +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf > > > ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf > > > +@@ -32,6 +32,8 @@ > > > + > > > + [Sources] > > > + DxeTpmMeasureBootLib.c > > > ++ DxeTpmMeasureBootLibSanitization.c > > > ++ DxeTpmMeasureBootLibSanitization.h > > > + > > > + [Packages] > > > + MdePkg/MdePkg.dec > > > +@@ -41,6 +43,7 @@ > > > + > > > + [LibraryClasses] > > > + BaseMemoryLib > > > ++ SafeIntLib > > > + DebugLib > > > + MemoryAllocationLib > > > + DevicePathLib > > > +@@ -59,4 +62,3 @@ > > > + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES > > > + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES > > > + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES > > > +- > > > +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c > > > +new file mode 100644 > > > +index 0000000000..a3fa46f5e6 > > > +--- /dev/null > > > ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c > > > +@@ -0,0 +1,241 @@ > > > ++/** @file > > > ++ The library instance provides security service of TPM2 measure boot and > > > ++ Confidential Computing (CC) 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. > > > ++ > > > ++ This file will pull out the validation logic from the following functions, in an > > > ++ attempt to validate the untrusted input in the form of unit tests > > > ++ > > > ++ These are those functions: > > > ++ > > > ++ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content > > > ++ read is within the image buffer. > > > ++ > > > ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse > > > ++ partition data carefully. > > > ++ > > > ++ Copyright (c) Microsoft Corporation.<BR> > > > ++ SPDX-License-Identifier: BSD-2-Clause-Patent > > > ++**/ > > > ++#include <Uefi.h> > > > ++#include <Uefi/UefiSpec.h> > > > ++#include <Library/SafeIntLib.h> > > > ++#include <Library/UefiLib.h> > > > ++#include <Library/DebugLib.h> > > > ++#include <Library/BaseLib.h> > > > ++#include <IndustryStandard/UefiTcgPlatform.h> > > > ++#include <Protocol/BlockIo.h> > > > ++#include <Library/MemoryAllocationLib.h> > > > ++ > > > ++#include "DxeTpmMeasureBootLibSanitization.h" > > > ++ > > > ++#define GPT_HEADER_REVISION_V1 0x00010000 > > > ++ > > > ++/** > > > ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse > > > ++ However this function will not attempt to verify the validity of the GPT partition > > > ++ It will check the following: > > > ++ - Signature > > > ++ - Revision > > > ++ - AlternateLBA > > > ++ - FirstUsableLBA > > > ++ - LastUsableLBA > > > ++ - PartitionEntryLBA > > > ++ - NumberOfPartitionEntries > > > ++ - SizeOfPartitionEntry > > > ++ - BlockIo > > > ++ > > > ++ @param[in] PrimaryHeader > > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > > ++ > > > ++ @param[in] BlockIo > > > ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. > > > ++ > > > ++ @retval EFI_SUCCESS > > > ++ The EFI_PARTITION_TABLE_HEADER structure is valid. > > > ++ > > > ++ @retval EFI_INVALID_PARAMETER > > > ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. > > > ++**/ > > > ++EFI_STATUS > > > ++EFIAPI > > > ++SanitizeEfiPartitionTableHeader ( > > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > > ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo > > > ++ ) > > > ++{ > > > ++ // Verify that the input parameters are safe to use > > > ++ if (PrimaryHeader == NULL) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); > > > ++ return EFI_INVALID_PARAMETER; > > > ++ } > > > ++ > > > ++ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n")); > > > ++ return EFI_INVALID_PARAMETER; > > > ++ } > > > ++ > > > ++ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII) > > > ++ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ // The version must be GPT_HEADER_REVISION_V1 (0x00010000) > > > ++ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n")); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size > > > ++ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n")); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ // check that the PartitionEntryLBA greater than the Max LBA > > > ++ // This will be used later for multiplication > > > ++ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n")); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ // Check that the number of partition entries is greater than zero > > > ++ if (PrimaryHeader->NumberOfPartitionEntries == 0) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory > > > ++ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) { > > > ++ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n")); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ // This check is to prevent overflow when calculating the allocation size for the partition entries > > > ++ // This check will be used later for multiplication > > > ++ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) { > > > ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); > > > ++ return EFI_DEVICE_ERROR; > > > ++ } > > > ++ > > > ++ return EFI_SUCCESS; > > > ++} > > > ++ > > > ++/** > > > ++ This function will validate that the allocation size from the primary header is sane > > > ++ It will check the following: > > > ++ - AllocationSize does not overflow > > > ++ > > > ++ @param[in] PrimaryHeader > > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > > ++ > > > ++ @param[out] AllocationSize > > > ++ Pointer to the allocation size. > > > ++ > > > ++ @retval EFI_SUCCESS > > > ++ The allocation size is valid. > > > ++ > > > ++ @retval EFI_OUT_OF_RESOURCES > > > ++ The allocation size is invalid. > > > ++**/ > > > ++EFI_STATUS > > > ++EFIAPI > > > ++SanitizePrimaryHeaderAllocationSize ( > > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > > ++ OUT UINT32 *AllocationSize > > > ++ ) > > > ++{ > > > ++ EFI_STATUS Status; > > > ++ > > > ++ if (PrimaryHeader == NULL) { > > > ++ return EFI_INVALID_PARAMETER; > > > ++ } > > > ++ > > > ++ if (AllocationSize == NULL) { > > > ++ return EFI_INVALID_PARAMETER; > > > ++ } > > > ++ > > > ++ // Replacing logic: > > > ++ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry; > > > ++ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize); > > > ++ if (EFI_ERROR (Status)) { > > > ++ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n")); > > > ++ return EFI_BAD_BUFFER_SIZE; > > > ++ } > > > ++ > > > ++ return EFI_SUCCESS; > > > ++} > > > ++ > > > ++/** > > > ++ This function will validate that the Gpt Event Size calculated from the primary header is sane > > > ++ It will check the following: > > > ++ - EventSize does not overflow > > > ++ > > > ++ Important: This function includes the entire length of the allocated space, including the > > > ++ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract > > > ++ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing. > > > ++ > > > ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > > ++ @param[in] NumberOfPartition - Number of partitions. > > > ++ @param[out] EventSize - Pointer to the event size. > > > ++ > > > ++ @retval EFI_SUCCESS > > > ++ The event size is valid. > > > ++ > > > ++ @retval EFI_OUT_OF_RESOURCES > > > ++ Overflow would have occurred. > > > ++ > > > ++ @retval EFI_INVALID_PARAMETER > > > ++ One of the passed parameters was invalid. > > > ++**/ > > > ++EFI_STATUS > > > ++SanitizePrimaryHeaderGptEventSize ( > > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > > ++ IN UINTN NumberOfPartition, > > > ++ OUT UINT32 *EventSize > > > ++ ) > > > ++{ > > > ++ EFI_STATUS Status; > > > ++ UINT32 SafeNumberOfPartitions; > > > ++ > > > ++ if (PrimaryHeader == NULL) { > > > ++ return EFI_INVALID_PARAMETER; > > > ++ } > > > ++ > > > ++ if (EventSize == NULL) { > > > ++ return EFI_INVALID_PARAMETER; > > > ++ } > > > ++ > > > ++ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32 > > > ++ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions); > > > ++ if (EFI_ERROR (Status)) { > > > ++ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n")); > > > ++ return EFI_INVALID_PARAMETER; > > > ++ } > > > ++ > > > ++ // Replacing logic: > > > ++ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry + sizeof (TCG_PCR_EVENT_HDR)); > > > ++ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize); > > > ++ if (EFI_ERROR (Status)) { > > > ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n")); > > > ++ return EFI_BAD_BUFFER_SIZE; > > > ++ } > > > ++ > > > ++ Status = SafeUint32Add ( > > > ++ sizeof (TCG_PCR_EVENT_HDR) + > > > ++ OFFSET_OF (EFI_GPT_DATA, Partitions), > > > ++ *EventSize, > > > ++ EventSize > > > ++ ); > > > ++ if (EFI_ERROR (Status)) { > > > ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n")); > > > ++ return EFI_BAD_BUFFER_SIZE; > > > ++ } > > > ++ > > > ++ return EFI_SUCCESS; > > > ++} > > > +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h > > > +new file mode 100644 > > > +index 0000000000..0d9d00c281 > > > +--- /dev/null > > > ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h > > > +@@ -0,0 +1,114 @@ > > > ++/** @file > > > ++ This file includes the function prototypes for the sanitization functions. > > > ++ > > > ++ These are those functions: > > > ++ > > > ++ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content > > > ++ read is within the image buffer. > > > ++ > > > ++ TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its > > > ++ data structure within this image buffer before use. > > > ++ > > > ++ TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse > > > ++ partition data carefully. > > > ++ > > > ++ Copyright (c) Microsoft Corporation.<BR> > > > ++ SPDX-License-Identifier: BSD-2-Clause-Patent > > > ++ > > > ++**/ > > > ++ > > > ++#ifndef DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ > > > ++#define DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ > > > ++ > > > ++#include <Uefi.h> > > > ++#include <Uefi/UefiSpec.h> > > > ++#include <Protocol/BlockIo.h> > > > ++#include <IndustryStandard/UefiTcgPlatform.h> > > > ++ > > > ++/** > > > ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse > > > ++ However this function will not attempt to verify the validity of the GPT partition > > > ++ It will check the following: > > > ++ - Signature > > > ++ - Revision > > > ++ - AlternateLBA > > > ++ - FirstUsableLBA > > > ++ - LastUsableLBA > > > ++ - PartitionEntryLBA > > > ++ - NumberOfPartitionEntries > > > ++ - SizeOfPartitionEntry > > > ++ - BlockIo > > > ++ > > > ++ @param[in] PrimaryHeader > > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > > ++ > > > ++ @param[in] BlockIo > > > ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. > > > ++ > > > ++ @retval EFI_SUCCESS > > > ++ The EFI_PARTITION_TABLE_HEADER structure is valid. > > > ++ > > > ++ @retval EFI_INVALID_PARAMETER > > > ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. > > > ++**/ > > > ++EFI_STATUS > > > ++EFIAPI > > > ++SanitizeEfiPartitionTableHeader ( > > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > > ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo > > > ++ ); > > > ++ > > > ++/** > > > ++ This function will validate that the allocation size from the primary header is sane > > > ++ It will check the following: > > > ++ - AllocationSize does not overflow > > > ++ > > > ++ @param[in] PrimaryHeader > > > ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > > ++ > > > ++ @param[out] AllocationSize > > > ++ Pointer to the allocation size. > > > ++ > > > ++ @retval EFI_SUCCESS > > > ++ The allocation size is valid. > > > ++ > > > ++ @retval EFI_OUT_OF_RESOURCES > > > ++ The allocation size is invalid. > > > ++**/ > > > ++EFI_STATUS > > > ++EFIAPI > > > ++SanitizePrimaryHeaderAllocationSize ( > > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > > ++ OUT UINT32 *AllocationSize > > > ++ ); > > > ++ > > > ++/** > > > ++ This function will validate that the Gpt Event Size calculated from the primary header is sane > > > ++ It will check the following: > > > ++ - EventSize does not overflow > > > ++ > > > ++ Important: This function includes the entire length of the allocated space, including the > > > ++ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract > > > ++ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing. > > > ++ > > > ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. > > > ++ @param[in] NumberOfPartition - Number of partitions. > > > ++ @param[out] EventSize - Pointer to the event size. > > > ++ > > > ++ @retval EFI_SUCCESS > > > ++ The event size is valid. > > > ++ > > > ++ @retval EFI_OUT_OF_RESOURCES > > > ++ Overflow would have occurred. > > > ++ > > > ++ @retval EFI_INVALID_PARAMETER > > > ++ One of the passed parameters was invalid. > > > ++**/ > > > ++EFI_STATUS > > > ++SanitizePrimaryHeaderGptEventSize ( > > > ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, > > > ++ IN UINTN NumberOfPartition, > > > ++ OUT UINT32 *EventSize > > > ++ ); > > > ++ > > > ++#endif // DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ > > > +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c > > > +new file mode 100644 > > > +index 0000000000..eeb928cdb0 > > > +--- /dev/null > > > ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c > > > +@@ -0,0 +1,301 @@ > > > ++/** @file > > > ++This file includes the unit test cases for the DxeTpmMeasureBootLibSanitizationTest.c. > > > ++ > > > ++Copyright (c) Microsoft Corporation.<BR> > > > ++SPDX-License-Identifier: BSD-2-Clause-Patent > > > ++**/ > > > ++ > > > ++#include <Uefi.h> > > > ++#include <Library/UefiLib.h> > > > ++#include <Library/DebugLib.h> > > > ++#include <Library/UnitTestLib.h> > > > ++#include <Protocol/BlockIo.h> > > > ++#include <Library/MemoryAllocationLib.h> > > > ++#include <Library/BaseMemoryLib.h> > > > ++#include <IndustryStandard/UefiTcgPlatform.h> > > > ++ > > > ++#include "../DxeTpmMeasureBootLibSanitization.h" > > > ++ > > > ++#define UNIT_TEST_NAME "DxeTpmMeasureBootLibSanitizationTest" > > > ++#define UNIT_TEST_VERSION "1.0" > > > ++ > > > ++#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000 > > > ++#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1 > > > ++#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128 > > > ++ > > > ++/** > > > ++ This function tests the SanitizeEfiPartitionTableHeader function. > > > ++ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER > > > ++ structure will not cause undefined or unexpected behavior. > > > ++ > > > ++ In general the TPM should still be able to measure the data, but > > > ++ be the header should be sanitized to prevent any unexpected behavior. > > > ++ > > > ++ @param[in] Context The unit test context. > > > ++ > > > ++ @retval UNIT_TEST_PASSED The test passed. > > > ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. > > > ++**/ > > > ++UNIT_TEST_STATUS > > > ++EFIAPI > > > ++TestSanitizeEfiPartitionTableHeader ( > > > ++ IN UNIT_TEST_CONTEXT Context > > > ++ ) > > > ++{ > > > ++ EFI_STATUS Status; > > > ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; > > > ++ EFI_BLOCK_IO_PROTOCOL BlockIo; > > > ++ EFI_BLOCK_IO_MEDIA BlockMedia; > > > ++ > > > ++ // Generate EFI_BLOCK_IO_MEDIA test data > > > ++ BlockMedia.MediaId = 1; > > > ++ BlockMedia.RemovableMedia = FALSE; > > > ++ BlockMedia.MediaPresent = TRUE; > > > ++ BlockMedia.LogicalPartition = FALSE; > > > ++ BlockMedia.ReadOnly = FALSE; > > > ++ BlockMedia.WriteCaching = FALSE; > > > ++ BlockMedia.BlockSize = 512; > > > ++ BlockMedia.IoAlign = 1; > > > ++ BlockMedia.LastBlock = 0; > > > ++ > > > ++ // Generate EFI_BLOCK_IO_PROTOCOL test data > > > ++ BlockIo.Revision = 1; > > > ++ BlockIo.Media = &BlockMedia; > > > ++ BlockIo.Reset = NULL; > > > ++ BlockIo.ReadBlocks = NULL; > > > ++ BlockIo.WriteBlocks = NULL; > > > ++ BlockIo.FlushBlocks = NULL; > > > ++ > > > ++ // Geneate EFI_PARTITION_TABLE_HEADER test data > > > ++ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID; > > > ++ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION; > > > ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); > > > ++ PrimaryHeader.MyLBA = 1; > > > ++ PrimaryHeader.AlternateLBA = 2; > > > ++ PrimaryHeader.FirstUsableLBA = 3; > > > ++ PrimaryHeader.LastUsableLBA = 4; > > > ++ PrimaryHeader.PartitionEntryLBA = 5; > > > ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES; > > > ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > > ++ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid > > > ++ > > > ++ // Calculate the CRC32 of the PrimaryHeader > > > ++ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize); > > > ++ > > > ++ // Test that a normal PrimaryHeader passes validation > > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > > ++ UT_ASSERT_NOT_EFI_ERROR (Status); > > > ++ > > > ++ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR > > > ++ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!"" > > > ++ PrimaryHeader.NumberOfPartitionEntries = 0; > > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > > ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); > > > ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > > ++ > > > ++ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR > > > ++ // Should print "Invalid Partition Table Header Size!" > > > ++ PrimaryHeader.Header.HeaderSize = 0; > > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > > ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); > > > ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); > > > ++ > > > ++ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR > > > ++ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!" > > > ++ PrimaryHeader.SizeOfPartitionEntry = 1; > > > ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); > > > ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); > > > ++ > > > ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); > > > ++ > > > ++ return UNIT_TEST_PASSED; > > > ++} > > > ++ > > > ++/** > > > ++ This function tests the SanitizePrimaryHeaderAllocationSize function. > > > ++ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER > > > ++ structure will not cause an overflow when calculating the allocation size. > > > ++ > > > ++ @param[in] Context The unit test context. > > > ++ > > > ++ @retval UNIT_TEST_PASSED The test passed. > > > ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. > > > ++**/ > > > ++UNIT_TEST_STATUS > > > ++EFIAPI > > > ++TestSanitizePrimaryHeaderAllocationSize ( > > > ++ IN UNIT_TEST_CONTEXT Context > > > ++ ) > > > ++{ > > > ++ UINT32 AllocationSize; > > > ++ > > > ++ EFI_STATUS Status; > > > ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; > > > ++ > > > ++ // Test that a normal PrimaryHeader passes validation > > > ++ PrimaryHeader.NumberOfPartitionEntries = 5; > > > ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > > ++ > > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > > ++ UT_ASSERT_NOT_EFI_ERROR (Status); > > > ++ > > > ++ // Test that the allocation size is correct compared to the existing logic > > > ++ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry); > > > ++ > > > ++ // Test that an overflow is detected > > > ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; > > > ++ PrimaryHeader.SizeOfPartitionEntry = 5; > > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > > ++ > > > ++ // Test the inverse > > > ++ PrimaryHeader.NumberOfPartitionEntries = 5; > > > ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; > > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > > ++ > > > ++ // Test the worst case scenario > > > ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; > > > ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; > > > ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); > > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > > ++ > > > ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); > > > ++ > > > ++ return UNIT_TEST_PASSED; > > > ++} > > > ++ > > > ++/** > > > ++ This function tests the SanitizePrimaryHeaderGptEventSize function. > > > ++ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure > > > ++ will not cause an overflow when calculating the event size. > > > ++ > > > ++ @param[in] Context The unit test context. > > > ++ > > > ++ @retval UNIT_TEST_PASSED The test passed. > > > ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. > > > ++**/ > > > ++UNIT_TEST_STATUS > > > ++EFIAPI > > > ++TestSanitizePrimaryHeaderGptEventSize ( > > > ++ IN UNIT_TEST_CONTEXT Context > > > ++ ) > > > ++{ > > > ++ UINT32 EventSize; > > > ++ UINT32 ExistingLogicEventSize; > > > ++ EFI_STATUS Status; > > > ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; > > > ++ UINTN NumberOfPartition; > > > ++ EFI_GPT_DATA *GptData; > > > ++ > > > ++ GptData = NULL; > > > ++ > > > ++ // Test that a normal PrimaryHeader passes validation > > > ++ PrimaryHeader.NumberOfPartitionEntries = 5; > > > ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; > > > ++ > > > ++ // set the number of partitions > > > ++ NumberOfPartition = 13; > > > ++ > > > ++ // that the primary event size is correct > > > ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); > > > ++ UT_ASSERT_NOT_EFI_ERROR (Status); > > > ++ > > > ++ // Calculate the existing logic event size > > > ++ ExistingLogicEventSize = (UINT32)(sizeof (TCG_PCR_EVENT_HDR) + OFFSET_OF (EFI_GPT_DATA, Partitions) > > > ++ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry); > > > ++ > > > ++ // Check that the event size is correct > > > ++ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize); > > > ++ > > > ++ // Tests that the primary event size may not overflow > > > ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize); > > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > > ++ > > > ++ // Test that the size of partition entries may not overflow > > > ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; > > > ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); > > > ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); > > > ++ > > > ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); > > > ++ > > > ++ return UNIT_TEST_PASSED; > > > ++} > > > ++ > > > ++// *--------------------------------------------------------------------* > > > ++// * Unit Test Code Main Function > > > ++// *--------------------------------------------------------------------* > > > ++ > > > ++/** > > > ++ This function acts as the entry point for the unit tests. > > > ++ > > > ++ @param argc - The number of command line arguments > > > ++ @param argv - The command line arguments > > > ++ > > > ++ @return int - The status of the test > > > ++**/ > > > ++EFI_STATUS > > > ++EFIAPI > > > ++UefiTestMain ( > > > ++ VOID > > > ++ ) > > > ++{ > > > ++ EFI_STATUS Status; > > > ++ UNIT_TEST_FRAMEWORK_HANDLE Framework; > > > ++ UNIT_TEST_SUITE_HANDLE TcgMeasureBootLibValidationTestSuite; > > > ++ > > > ++ Framework = NULL; > > > ++ > > > ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME)); > > > ++ > > > ++ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION); > > > ++ if (EFI_ERROR (Status)) { > > > ++ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status)); > > > ++ goto EXIT; > > > ++ } > > > ++ > > > ++ Status = CreateUnitTestSuite (&TcgMeasureBootLibValidationTestSuite, Framework, "TcgMeasureBootLibValidationTestSuite", "Common.TcgMeasureBootLibValidation", NULL, NULL); > > > ++ if (EFI_ERROR (Status)) { > > > ++ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for TcgMeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME)); > > > ++ Status = EFI_OUT_OF_RESOURCES; > > > ++ goto EXIT; > > > ++ } > > > ++ > > > ++ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context > > > ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.TcgMeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL); > > > ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL); > > > ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL); > > > ++ > > > ++ Status = RunAllTestSuites (Framework); > > > ++ > > > ++EXIT: > > > ++ if (Framework != NULL) { > > > ++ FreeUnitTestFramework (Framework); > > > ++ } > > > ++ > > > ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME)); > > > ++ return Status; > > > ++} > > > ++ > > > ++/// > > > ++/// Avoid ECC error for function name that starts with lower case letter > > > ++/// > > > ++#define DxeTpmMeasureBootLibUnitTestMain main > > > ++ > > > ++/** > > > ++ Standard POSIX C entry point for host based unit test execution. > > > ++ > > > ++ @param[in] Argc Number of arguments > > > ++ @param[in] Argv Array of pointers to arguments > > > ++ > > > ++ @retval 0 Success > > > ++ @retval other Error > > > ++**/ > > > ++INT32 > > > ++DxeTpmMeasureBootLibUnitTestMain ( > > > ++ IN INT32 Argc, > > > ++ IN CHAR8 *Argv[] > > > ++ ) > > > ++{ > > > ++ return (INT32)UefiTestMain (); > > > ++} > > > +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf > > > +new file mode 100644 > > > +index 0000000000..47b0811b00 > > > +--- /dev/null > > > ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf > > > +@@ -0,0 +1,28 @@ > > > ++## @file > > > ++# This file builds the unit tests for DxeTpmMeasureBootLib > > > ++# > > > ++# Copyright (C) Microsoft Corporation.<BR> > > > ++# SPDX-License-Identifier: BSD-2-Clause-Patent > > > ++## > > > ++ > > > ++[Defines] > > > ++ INF_VERSION = 0x00010006 > > > ++ BASE_NAME = DxeTpmMeasuredBootLibTest > > > ++ FILE_GUID = eb01bc38-309c-4d3e-967e-9f078c90772f > > > ++ MODULE_TYPE = HOST_APPLICATION > > > ++ VERSION_STRING = 1.0 > > > ++ ENTRY_POINT = main > > > ++ > > > ++[Sources] > > > ++ DxeTpmMeasureBootLibSanitizationTest.c > > > ++ ../DxeTpmMeasureBootLibSanitization.c > > > ++ > > > ++[Packages] > > > ++ MdePkg/MdePkg.dec > > > ++ > > > ++[LibraryClasses] > > > ++ BaseLib > > > ++ DebugLib > > > ++ UnitTestLib > > > ++ PrintLib > > > ++ SafeIntLib > > > +diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml > > > +index da811fdf93..0e40eaa0fe 100644 > > > +--- a/SecurityPkg/SecurityPkg.ci.yaml > > > ++++ b/SecurityPkg/SecurityPkg.ci.yaml > > > +@@ -16,6 +16,7 @@ > > > + ## ] > > > + "ExceptionList": [ > > > + "8001", "DxeTpm2MeasureBootLibUnitTestMain", > > > ++ "8001", "DxeTpmMeasureBootLibUnitTestMain" > > > + ], > > > + ## Both file path and directory path are accepted. > > > + "IgnoreFiles": [ > > > +-- > > > +2.40.0 > > > + > > > diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch > > > new file mode 100644 > > > index 0000000000..59bd5c4910 > > > --- /dev/null > > > +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch > > > @@ -0,0 +1,55 @@ > > > +From 1ddcb9fc6b4164e882687b031e8beacfcf7df29e Mon Sep 17 00:00:00 2001 > > > +From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com> > > > +Date: Fri, 12 Jan 2024 02:16:03 +0800 > > > +Subject: [PATCH] SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml > > > + > > > +This creates / adds a security file that tracks the security fixes > > > +found in this package and can be used to find the fixes that were > > > +applied. > > > + > > > +Cc: Jiewen Yao <jiewen.yao@intel.com> > > > + > > > +Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> > > > +Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> > > > + > > > +CVE: CVE-2022-36763 > > > + > > > +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1ddcb9fc6b4164e882687b031e8beacfcf7df29e] > > > + > > > +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> > > > +--- > > > + SecurityPkg/SecurityFixes.yaml | 22 ++++++++++++++++++++++ > > > + 1 file changed, 22 insertions(+) > > > + create mode 100644 SecurityPkg/SecurityFixes.yaml > > > + > > > +diff --git a/SecurityPkg/SecurityFixes.yaml b/SecurityPkg/SecurityFixes.yaml > > > +new file mode 100644 > > > +index 0000000000..f9e3e7be74 > > > +--- /dev/null > > > ++++ b/SecurityPkg/SecurityFixes.yaml > > > +@@ -0,0 +1,22 @@ > > > ++## @file > > > ++# Security Fixes for SecurityPkg > > > ++# > > > ++# Copyright (c) Microsoft Corporation > > > ++# SPDX-License-Identifier: BSD-2-Clause-Patent > > > ++## > > > ++CVE_2022_36763: > > > ++ commit_titles: > > > ++ - "SecurityPkg: DxeTpm2Measurement: SECURITY PATCH 4117 - CVE 2022-36763" > > > ++ - "SecurityPkg: DxeTpmMeasurement: SECURITY PATCH 4117 - CVE 2022-36763" > > > ++ - "SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml" > > > ++ cve: CVE-2022-36763 > > > ++ date_reported: 2022-10-25 11:31 UTC > > > ++ description: (CVE-2022-36763) - Heap Buffer Overflow in Tcg2MeasureGptTable() > > > ++ note: This patch is related to and supersedes TCBZ2168 > > > ++ files_impacted: > > > ++ - Library\DxeTpm2MeasureBootLib\DxeTpm2MeasureBootLib.c > > > ++ - Library\DxeTpmMeasureBootLib\DxeTpmMeasureBootLib.c > > > ++ links: > > > ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4117 > > > ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=2168 > > > ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=1990 > > > +-- > > > +2.40.0 > > > + > > > diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb > > > index 84e3360a3a..78d86ad879 100644 > > > --- a/meta/recipes-core/ovmf/ovmf_git.bb > > > +++ b/meta/recipes-core/ovmf/ovmf_git.bb > > > @@ -27,6 +27,9 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ > > > file://0006-reproducible.patch \ > > > file://0001-BaseTools-fix-gcc12-warning.patch \ > > > file://0001-BaseTools-fix-gcc12-warning-1.patch \ > > > + file://CVE-2022-36763-0001.patch \ > > > + file://CVE-2022-36763-0002.patch \ > > > + file://CVE-2022-36763-0003.patch \ > > > " > > > > > > PV = "edk2-stable202202" > > > -- > > > 2.25.1 > > > > > -=-=-=-=-=-=-=-=-=-=-=- > Links: You receive all messages sent to this group. > View/Reply Online (#208147): https://lists.openembedded.org/g/openembedded-core/message/208147 > Mute This Topic: https://lists.openembedded.org/mt/109784095/3620601 > Group Owner: openembedded-core+owner@lists.openembedded.org > Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [steve@sakoman.com] > -=-=-=-=-=-=-=-=-=-=-=- >
On 12/3/24 05:02, Steve Sakoman wrote: > CAUTION: This email comes from a non Wind River email account! > Do not click links or open attachments unless you recognize the sender and know the content is safe. > > On Mon, Dec 2, 2024 at 8:09 AM Steve Sakoman via > lists.openembedded.org<steve=sakoman.com@lists.openembedded.org> > wrote: >> On Thu, Nov 28, 2024 at 12:15 AM Jia, Hongxu<Hongxu.Jia@windriver.com> wrote: >>> Hi Steve, >>> >>> I am afraid the issue was caused by CR("^M") in ovmf source code >>> >>> The source of ovmf use CR (^M) as new line, we should use 'git am --keep-cr xxxx.patch' to apply the patch, >>> otherwise do_patch failed >>> >>> But I do not know how you apply the patch to your build or via patchtest automatically, do you use git am with option --keep-cr? >> I download the patch from patchworks using the "mbox" button and the >> apply it like this: >> >> $ git am --keep-cr ~/Downloads/kirkstone-V2-01-13-ovmf-Fix-CVE-2022-36763.patch >> Applying: ovmf: Fix CVE-2022-36763 >> .git/rebase-apply/patch:56: trailing whitespace. >> .git/rebase-apply/patch:60: trailing whitespace. >> .git/rebase-apply/patch:65: trailing whitespace. >> .git/rebase-apply/patch:81: trailing whitespace. >> .git/rebase-apply/patch:95: trailing whitespace. >> warning: squelched 27 whitespace errors >> warning: 32 lines add whitespace errors. >> >> $ bitbake ovmf >> Loading cache: 100% | >> >> >> >> | ETA: --:--:-- >> <snip> >> NOTE: Executing Tasks >> >> ERROR: ovmf-edk2-stable202202-r0 do_patch: Applying patch >> 'CVE-2022-36763-0001.patch' on target directory >> '/home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/git' >> CmdError('quilt --quiltrc >> /home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/recipe-sysroot-native/etc/quiltrc >> push', 0, 'stdout: Applying patch CVE-2022-36763-0001.patch >> patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c >> Hunk #1 FAILED at 20 (different line endings). >> Hunk #2 FAILED at 44 (different line endings). >> Hunk #3 FAILED at 144 (different line endings). >> Hunk #4 FAILED at 195 (different line endings). >> Hunk #5 FAILED at 223 (different line endings). >> Hunk #6 FAILED at 248 (different line endings). >> Hunk #7 FAILED at 310 (different line endings). >> Hunk #8 FAILED at 326 (different line endings). >> Hunk #9 FAILED at 443 (different line endings). >> Hunk #10 FAILED at 515 (different line endings). >> Hunk #11 FAILED at 646 (different line endings). >> 11 out of 11 hunks FAILED -- rejects in file >> SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c >> patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf >> Hunk #1 FAILED at 37 (different line endings). >> Hunk #2 FAILED at 46 (different line endings). >> Hunk #3 FAILED at 65 (different line endings). >> 3 out of 3 hunks FAILED -- rejects in file >> SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf >> patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c >> patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h >> patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c >> patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf >> patching file SecurityPkg/SecurityPkg.ci.yaml >> Hunk #1 FAILED at 15 (different line endings). >> 1 out of 1 hunk FAILED -- rejects in file SecurityPkg/SecurityPkg.ci.yaml >> Patch CVE-2022-36763-0001.patch does not apply (enforce with -f) >> >> stderr: ') >> ERROR: Logfile of failure stored in: >> /home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/temp/log.do_patch.2851600 >> ERROR: Task (/home/steve/builds/poky-contrib-kirkstone/meta/recipes-core/ovmf/ovmf_git.bb:do_patch) >> failed with exit code '1' >> NOTE: Tasks Summary: Attempted 1094 tasks of which 1085 didn't need to >> be rerun and 1 failed. >> Complete CVE report summary created at: >> /home/steve/builds/poky-contrib-kirkstone/build/tmp/log/cve/cve-summary >> NOTE: Generating JSON CVE summary >> Complete CVE JSON report summary created at: >> /home/steve/builds/poky-contrib-kirkstone/build/tmp/log/cve/cve-summary.json >> >> Summary: 1 task failed: >> /home/steve/builds/poky-contrib-kirkstone/meta/recipes-core/ovmf/ovmf_git.bb:do_patch >> Summary: There was 1 ERROR message, returning a non-zero exit code. >> >> Any suggestions? > If you have a public git repo perhaps I could pull the patches > directly from there? Hi Steve, Submit patches to github: For kirkstone, 13 ovmf CVE patches: https://github.com/hongxu-jia/openembedded-core/tree/kirkstone https://github.com/openembedded/openembedded-core/pull/101 For scarthgap, 2 ovmf CVE patches https://github.com/hongxu-jia/openembedded-core/tree/scarthgap https://github.com/openembedded/openembedded-core/pull/102 //Hongxu > Steve > >> Steve >> >>> ________________________________ >>> From: Steve Sakoman<steve@sakoman.com> >>> Sent: Wednesday, November 27, 2024 10:50 PM >>> To: Jia, Hongxu<Hongxu.Jia@windriver.com> >>> Cc:openembedded-core@lists.openembedded.org <openembedded-core@lists.openembedded.org> >>> Subject: Re: [kirkstone][PATCH V2 01/13] ovmf: Fix CVE-2022-36763 >>> >>> CAUTION: This email comes from a non Wind River email account! >>> Do not click links or open attachments unless you recognize the sender and know the content is safe. >>> >>> I am getting build time errors with this patch: >>> >>> ERROR: ovmf-edk2-stable202202-r0 do_patch: Applying patch >>> 'CVE-2022-36763-0001.patch' on target directory >>> '/home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/git' >>> CmdError('quilt --quiltrc >>> /home/steve/builds/poky-contrib-kirkstone/build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202202-r0/recipe-sysroot-native/etc/quiltrc >>> push', 0, 'stdout: Applying patch CVE-2022-36763-0001.patch >>> patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c >>> Hunk #1 FAILED at 20 (different line endings). >>> Hunk #2 FAILED at 44 (different line endings). >>> Hunk #3 FAILED at 144 (different line endings). >>> Hunk #4 FAILED at 195 (different line endings). >>> Hunk #5 FAILED at 223 (different line endings). >>> Hunk #6 FAILED at 248 (different line endings). >>> Hunk #7 FAILED at 310 (different line endings). >>> Hunk #8 FAILED at 326 (different line endings). >>> Hunk #9 FAILED at 443 (different line endings). >>> Hunk #10 FAILED at 515 (different line endings). >>> Hunk #11 FAILED at 646 (different line endings). >>> 11 out of 11 hunks FAILED -- rejects in file >>> SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c >>> patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf >>> Hunk #1 FAILED at 37 (different line endings). >>> Hunk #2 FAILED at 46 (different line endings). >>> Hunk #3 FAILED at 65 (different line endings). >>> 3 out of 3 hunks FAILED -- rejects in file >>> SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf >>> patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c >>> patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h >>> patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c >>> patching file SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf >>> patching file SecurityPkg/SecurityPkg.ci.yaml >>> Hunk #1 FAILED at 15 (different line endings). >>> 1 out of 1 hunk FAILED -- rejects in file SecurityPkg/SecurityPkg.ci.yaml >>> Patch CVE-2022-36763-0001.patch does not apply (enforce with -f) >>> >>> Please submit a V2 of this series with the line ending issues fixed. >>> >>> Thanks! >>> >>> Steve >>> >>> On Mon, Nov 25, 2024 at 6:25 PM Hongxu Jia<hongxu.jia@windriver.com> wrote: >>>> From: Soumya Sambu<soumya.sambu@windriver.com> >>>> >>>> EDK2 is susceptible to a vulnerability in the Tcg2MeasureGptTable() >>>> function, allowing a user to trigger a heap buffer overflow via a local >>>> network. Successful exploitation of this vulnerability may result in a >>>> compromise of confidentiality, integrity, and/or availability. >>>> >>>> References: >>>> https://nvd.nist.gov/vuln/detail/CVE-2022-36763 >>>> >>>> Upstream-patches: >>>> https://github.com/tianocore/edk2/commit/224446543206450ddb5830e6abd026d61d3c7f4b >>>> https://github.com/tianocore/edk2/commit/4776a1b39ee08fc45c70c1eab5a0195f325000d3 >>>> https://github.com/tianocore/edk2/commit/1ddcb9fc6b4164e882687b031e8beacfcf7df29e >>>> >>>> Signed-off-by: Soumya Sambu<soumya.sambu@windriver.com> >>>> --- >>>> .../ovmf/ovmf/CVE-2022-36763-0001.patch | 985 ++++++++++++++++++ >>>> .../ovmf/ovmf/CVE-2022-36763-0002.patch | 889 ++++++++++++++++ >>>> .../ovmf/ovmf/CVE-2022-36763-0003.patch | 55 + >>>> meta/recipes-core/ovmf/ovmf_git.bb | 3 + >>>> 4 files changed, 1932 insertions(+) >>>> create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch >>>> create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch >>>> create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch >>>> >>>> diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch >>>> new file mode 100644 >>>> index 0000000000..93cefe7740 >>>> --- /dev/null >>>> +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch >>>> @@ -0,0 +1,985 @@ >>>> +From 224446543206450ddb5830e6abd026d61d3c7f4b Mon Sep 17 00:00:00 2001 >>>> +From: "Douglas Flick [MSFT]"<doug.edk2@gmail.com> >>>> +Date: Fri, 12 Jan 2024 02:16:01 +0800 >>>> +Subject: [PATCH] SecurityPkg: DxeTpm2MeasureBootLib: SECURITY PATCH 4117 - CVE >>>> + 2022-36763 >>>> + >>>> +This commit contains the patch files and tests for DxeTpm2MeasureBootLib >>>> +CVE 2022-36763. >>>> + >>>> +Cc: Jiewen Yao<jiewen.yao@intel.com> >>>> + >>>> +Signed-off-by: Doug Flick [MSFT]<doug.edk2@gmail.com> >>>> + >>>> +CVE: CVE-2022-36763 >>>> + >>>> +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/224446543206450ddb5830e6abd026d61d3c7f4b] >>>> + >>>> +Signed-off-by: Soumya Sambu<soumya.sambu@windriver.com> >>>> +--- >>>> + .../DxeTpm2MeasureBootLib.c | 69 ++-- >>>> + .../DxeTpm2MeasureBootLib.inf | 4 +- >>>> + .../DxeTpm2MeasureBootLibSanitization.c | 275 ++++++++++++++++ >>>> + .../DxeTpm2MeasureBootLibSanitization.h | 113 +++++++ >>>> + .../DxeTpm2MeasureBootLibSanitizationTest.c | 303 ++++++++++++++++++ >>>> + ...Tpm2MeasureBootLibSanitizationTestHost.inf | 28 ++ >>>> + SecurityPkg/SecurityPkg.ci.yaml | 1 + >>>> + 7 files changed, 763 insertions(+), 30 deletions(-) >>>> + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c >>>> + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h >>>> + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c >>>> + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf >>>> + >>>> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c >>>> +index 36a256a7af..0475103d6e 100644 >>>> +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c >>>> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c >>>> +@@ -20,6 +20,8 @@ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> >>>> + (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> >>>> + SPDX-License-Identifier: BSD-2-Clause-Patent >>>> + >>>> ++Copyright (c) Microsoft Corporation.<BR> >>>> ++SPDX-License-Identifier: BSD-2-Clause-Patent >>>> + **/ >>>> + >>>> + #include <PiDxe.h> >>>> +@@ -44,6 +46,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent >>>> + #include <Library/HobLib.h> >>>> + #include <Protocol/CcMeasurement.h> >>>> + >>>> ++#include "DxeTpm2MeasureBootLibSanitization.h" >>>> ++ >>>> + typedef struct { >>>> + EFI_TCG2_PROTOCOL *Tcg2Protocol; >>>> + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol; >>>> +@@ -144,10 +148,11 @@ Tcg2MeasureGptTable ( >>>> + EFI_TCG2_EVENT *Tcg2Event; >>>> + EFI_CC_EVENT *CcEvent; >>>> + EFI_GPT_DATA *GptData; >>>> +- UINT32 EventSize; >>>> ++ UINT32 TcgEventSize; >>>> + EFI_TCG2_PROTOCOL *Tcg2Protocol; >>>> + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol; >>>> + EFI_CC_MR_INDEX MrIndex; >>>> ++ UINT32 AllocSize; >>>> + >>>> + if (mTcg2MeasureGptCount > 0) { >>>> + return EFI_SUCCESS; >>>> +@@ -195,25 +200,22 @@ Tcg2MeasureGptTable ( >>>> + BlockIo->Media->BlockSize, >>>> + (UINT8 *)PrimaryHeader >>>> + ); >>>> +- if (EFI_ERROR (Status)) { >>>> +- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n")); >>>> ++ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) { >>>> ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n")); >>>> + FreePool (PrimaryHeader); >>>> + return EFI_DEVICE_ERROR; >>>> + } >>>> + >>>> + // >>>> +- // PrimaryHeader->SizeOfPartitionEntry should not be zero >>>> ++ // Read the partition entry. >>>> + // >>>> +- if (PrimaryHeader->SizeOfPartitionEntry == 0) { >>>> +- DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry should not be zero!\n")); >>>> ++ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize); >>>> ++ if (EFI_ERROR (Status)) { >>>> + FreePool (PrimaryHeader); >>>> + return EFI_BAD_BUFFER_SIZE; >>>> + } >>>> + >>>> +- // >>>> +- // Read the partition entry. >>>> +- // >>>> +- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry); >>>> ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize); >>>> + if (EntryPtr == NULL) { >>>> + FreePool (PrimaryHeader); >>>> + return EFI_OUT_OF_RESOURCES; >>>> +@@ -223,7 +225,7 @@ Tcg2MeasureGptTable ( >>>> + DiskIo, >>>> + BlockIo->Media->MediaId, >>>> + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), >>>> +- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry, >>>> ++ AllocSize, >>>> + EntryPtr >>>> + ); >>>> + if (EFI_ERROR (Status)) { >>>> +@@ -248,16 +250,21 @@ Tcg2MeasureGptTable ( >>>> + // >>>> + // Prepare Data for Measurement (CcProtocol and Tcg2Protocol) >>>> + // >>>> +- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) >>>> +- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry); >>>> +- EventPtr = (UINT8 *)AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)); >>>> ++ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &TcgEventSize); >>>> ++ if (EFI_ERROR (Status)) { >>>> ++ FreePool (PrimaryHeader); >>>> ++ FreePool (EntryPtr); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ EventPtr = (UINT8 *)AllocateZeroPool (TcgEventSize); >>>> + if (EventPtr == NULL) { >>>> + Status = EFI_OUT_OF_RESOURCES; >>>> + goto Exit; >>>> + } >>>> + >>>> + Tcg2Event = (EFI_TCG2_EVENT *)EventPtr; >>>> +- Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event); >>>> ++ Tcg2Event->Size = TcgEventSize; >>>> + Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER); >>>> + Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; >>>> + Tcg2Event->Header.PCRIndex = 5; >>>> +@@ -310,7 +317,7 @@ Tcg2MeasureGptTable ( >>>> + CcProtocol, >>>> + 0, >>>> + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData, >>>> +- (UINT64)EventSize, >>>> ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), >>>> + CcEvent >>>> + ); >>>> + if (!EFI_ERROR (Status)) { >>>> +@@ -326,7 +333,7 @@ Tcg2MeasureGptTable ( >>>> + Tcg2Protocol, >>>> + 0, >>>> + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData, >>>> +- (UINT64)EventSize, >>>> ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), >>>> + Tcg2Event >>>> + ); >>>> + if (!EFI_ERROR (Status)) { >>>> +@@ -443,11 +450,13 @@ Tcg2MeasurePeImage ( >>>> + Tcg2Event->Header.PCRIndex = 2; >>>> + break; >>>> + default: >>>> +- DEBUG (( >>>> +- DEBUG_ERROR, >>>> +- "Tcg2MeasurePeImage: Unknown subsystem type %d", >>>> +- ImageType >>>> +- )); >>>> ++ DEBUG ( >>>> ++ ( >>>> ++ DEBUG_ERROR, >>>> ++ "Tcg2MeasurePeImage: Unknown subsystem type %d", >>>> ++ ImageType >>>> ++ ) >>>> ++ ); >>>> + goto Finish; >>>> + } >>>> + >>>> +@@ -515,7 +524,7 @@ Finish: >>>> + >>>> + @param MeasureBootProtocols Pointer to the located measure boot protocol instances. >>>> + >>>> +- @retval EFI_SUCCESS Sucessfully locate the measure boot protocol instances (at least one instance). >>>> ++ @retval EFI_SUCCESS Successfully locate the measure boot protocol instances (at least one instance). >>>> + @retval EFI_UNSUPPORTED Measure boot is not supported. >>>> + **/ >>>> + EFI_STATUS >>>> +@@ -646,12 +655,14 @@ DxeTpm2MeasureBootHandler ( >>>> + return EFI_SUCCESS; >>>> + } >>>> + >>>> +- DEBUG (( >>>> +- DEBUG_INFO, >>>> +- "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n", >>>> +- MeasureBootProtocols.Tcg2Protocol, >>>> +- MeasureBootProtocols.CcProtocol >>>> +- )); >>>> ++ DEBUG ( >>>> ++ ( >>>> ++ DEBUG_INFO, >>>> ++ "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n", >>>> ++ MeasureBootProtocols.Tcg2Protocol, >>>> ++ MeasureBootProtocols.CcProtocol >>>> ++ ) >>>> ++ ); >>>> + >>>> + // >>>> + // Copy File Device Path >>>> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf >>>> +index 6dca79a20c..28995f438d 100644 >>>> +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf >>>> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf >>>> +@@ -37,6 +37,8 @@ >>>> + >>>> + [Sources] >>>> + DxeTpm2MeasureBootLib.c >>>> ++ DxeTpm2MeasureBootLibSanitization.c >>>> ++ DxeTpm2MeasureBootLibSanitization.h >>>> + >>>> + [Packages] >>>> + MdePkg/MdePkg.dec >>>> +@@ -46,6 +48,7 @@ >>>> + >>>> + [LibraryClasses] >>>> + BaseMemoryLib >>>> ++ SafeIntLib >>>> + DebugLib >>>> + MemoryAllocationLib >>>> + DevicePathLib >>>> +@@ -65,4 +68,3 @@ >>>> + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES >>>> + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES >>>> + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES >>>> +- >>>> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c >>>> +new file mode 100644 >>>> +index 0000000000..e2309655d3 >>>> +--- /dev/null >>>> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c >>>> +@@ -0,0 +1,275 @@ >>>> ++/** @file >>>> ++ The library instance provides security service of TPM2 measure boot and >>>> ++ Confidential Computing (CC) 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. >>>> ++ >>>> ++ This file will pull out the validation logic from the following functions, in an >>>> ++ attempt to validate the untrusted input in the form of unit tests >>>> ++ >>>> ++ These are those functions: >>>> ++ >>>> ++ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content >>>> ++ read is within the image buffer. >>>> ++ >>>> ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse >>>> ++ partition data carefully. >>>> ++ >>>> ++ Copyright (c) Microsoft Corporation.<BR> >>>> ++ SPDX-License-Identifier: BSD-2-Clause-Patent >>>> ++**/ >>>> ++#include <Uefi.h> >>>> ++#include <Uefi/UefiSpec.h> >>>> ++#include <Library/SafeIntLib.h> >>>> ++#include <Library/UefiLib.h> >>>> ++#include <Library/DebugLib.h> >>>> ++#include <Library/BaseLib.h> >>>> ++#include <IndustryStandard/UefiTcgPlatform.h> >>>> ++#include <Protocol/BlockIo.h> >>>> ++#include <Library/MemoryAllocationLib.h> >>>> ++ >>>> ++#include "DxeTpm2MeasureBootLibSanitization.h" >>>> ++ >>>> ++#define GPT_HEADER_REVISION_V1 0x00010000 >>>> ++ >>>> ++/** >>>> ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse >>>> ++ However this function will not attempt to verify the validity of the GPT partition >>>> ++ It will check the following: >>>> ++ - Signature >>>> ++ - Revision >>>> ++ - AlternateLBA >>>> ++ - FirstUsableLBA >>>> ++ - LastUsableLBA >>>> ++ - PartitionEntryLBA >>>> ++ - NumberOfPartitionEntries >>>> ++ - SizeOfPartitionEntry >>>> ++ - BlockIo >>>> ++ >>>> ++ @param[in] PrimaryHeader >>>> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. >>>> ++ >>>> ++ @param[in] BlockIo >>>> ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. >>>> ++ >>>> ++ @retval EFI_SUCCESS >>>> ++ The EFI_PARTITION_TABLE_HEADER structure is valid. >>>> ++ >>>> ++ @retval EFI_INVALID_PARAMETER >>>> ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. >>>> ++**/ >>>> ++EFI_STATUS >>>> ++EFIAPI >>>> ++SanitizeEfiPartitionTableHeader ( >>>> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, >>>> ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo >>>> ++ ) >>>> ++{ >>>> ++ // >>>> ++ // Verify that the input parameters are safe to use >>>> ++ // >>>> ++ if (PrimaryHeader == NULL) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); >>>> ++ return EFI_INVALID_PARAMETER; >>>> ++ } >>>> ++ >>>> ++ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n")); >>>> ++ return EFI_INVALID_PARAMETER; >>>> ++ } >>>> ++ >>>> ++ // >>>> ++ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII) >>>> ++ // >>>> ++ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ // >>>> ++ // The version must be GPT_HEADER_REVISION_V1 (0x00010000) >>>> ++ // >>>> ++ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n")); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ // >>>> ++ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size >>>> ++ // >>>> ++ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n")); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ // >>>> ++ // The partition entries should all be before the first usable block >>>> ++ // >>>> ++ if (PrimaryHeader->FirstUsableLBA <= PrimaryHeader->PartitionEntryLBA) { >>>> ++ DEBUG ((DEBUG_ERROR, "GPT PartitionEntryLBA is not less than FirstUsableLBA!\n")); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ // >>>> ++ // Check that the PartitionEntryLBA greater than the Max LBA >>>> ++ // This will be used later for multiplication >>>> ++ // >>>> ++ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n")); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ // >>>> ++ // Check that the number of partition entries is greater than zero >>>> ++ // >>>> ++ if (PrimaryHeader->NumberOfPartitionEntries == 0) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ // >>>> ++ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory >>>> ++ // >>>> ++ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) { >>>> ++ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n")); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ // >>>> ++ // This check is to prevent overflow when calculating the allocation size for the partition entries >>>> ++ // This check will be used later for multiplication >>>> ++ // >>>> ++ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ return EFI_SUCCESS; >>>> ++} >>>> ++ >>>> ++/** >>>> ++ This function will validate that the allocation size from the primary header is sane >>>> ++ It will check the following: >>>> ++ - AllocationSize does not overflow >>>> ++ >>>> ++ @param[in] PrimaryHeader >>>> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. >>>> ++ >>>> ++ @param[out] AllocationSize >>>> ++ Pointer to the allocation size. >>>> ++ >>>> ++ @retval EFI_SUCCESS >>>> ++ The allocation size is valid. >>>> ++ >>>> ++ @retval EFI_OUT_OF_RESOURCES >>>> ++ The allocation size is invalid. >>>> ++**/ >>>> ++EFI_STATUS >>>> ++EFIAPI >>>> ++SanitizePrimaryHeaderAllocationSize ( >>>> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, >>>> ++ OUT UINT32 *AllocationSize >>>> ++ ) >>>> ++{ >>>> ++ EFI_STATUS Status; >>>> ++ >>>> ++ if (PrimaryHeader == NULL) { >>>> ++ return EFI_INVALID_PARAMETER; >>>> ++ } >>>> ++ >>>> ++ if (AllocationSize == NULL) { >>>> ++ return EFI_INVALID_PARAMETER; >>>> ++ } >>>> ++ >>>> ++ // >>>> ++ // Replacing logic: >>>> ++ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry; >>>> ++ // >>>> ++ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize); >>>> ++ if (EFI_ERROR (Status)) { >>>> ++ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n")); >>>> ++ return EFI_BAD_BUFFER_SIZE; >>>> ++ } >>>> ++ >>>> ++ return EFI_SUCCESS; >>>> ++} >>>> ++ >>>> ++/** >>>> ++ This function will validate that the Gpt Event Size calculated from the primary header is sane >>>> ++ It will check the following: >>>> ++ - EventSize does not overflow >>>> ++ >>>> ++ Important: This function includes the entire length of the allocated space, including >>>> ++ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this >>>> ++ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) >>>> ++ from the size of the buffer before hashing. >>>> ++ >>>> ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. >>>> ++ @param[in] NumberOfPartition - Number of partitions. >>>> ++ @param[out] EventSize - Pointer to the event size. >>>> ++ >>>> ++ @retval EFI_SUCCESS >>>> ++ The event size is valid. >>>> ++ >>>> ++ @retval EFI_OUT_OF_RESOURCES >>>> ++ Overflow would have occurred. >>>> ++ >>>> ++ @retval EFI_INVALID_PARAMETER >>>> ++ One of the passed parameters was invalid. >>>> ++**/ >>>> ++EFI_STATUS >>>> ++SanitizePrimaryHeaderGptEventSize ( >>>> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, >>>> ++ IN UINTN NumberOfPartition, >>>> ++ OUT UINT32 *EventSize >>>> ++ ) >>>> ++{ >>>> ++ EFI_STATUS Status; >>>> ++ UINT32 SafeNumberOfPartitions; >>>> ++ >>>> ++ if (PrimaryHeader == NULL) { >>>> ++ return EFI_INVALID_PARAMETER; >>>> ++ } >>>> ++ >>>> ++ if (EventSize == NULL) { >>>> ++ return EFI_INVALID_PARAMETER; >>>> ++ } >>>> ++ >>>> ++ // >>>> ++ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32 >>>> ++ // >>>> ++ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions); >>>> ++ if (EFI_ERROR (Status)) { >>>> ++ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n")); >>>> ++ return EFI_INVALID_PARAMETER; >>>> ++ } >>>> ++ >>>> ++ // >>>> ++ // Replacing logic: >>>> ++ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry); >>>> ++ // >>>> ++ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize); >>>> ++ if (EFI_ERROR (Status)) { >>>> ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n")); >>>> ++ return EFI_BAD_BUFFER_SIZE; >>>> ++ } >>>> ++ >>>> ++ // >>>> ++ // Replacing logic: >>>> ++ // *EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event); >>>> ++ // >>>> ++ Status = SafeUint32Add ( >>>> ++ OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions), >>>> ++ *EventSize, >>>> ++ EventSize >>>> ++ ); >>>> ++ if (EFI_ERROR (Status)) { >>>> ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n")); >>>> ++ return EFI_BAD_BUFFER_SIZE; >>>> ++ } >>>> ++ >>>> ++ return EFI_SUCCESS; >>>> ++} >>>> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h >>>> +new file mode 100644 >>>> +index 0000000000..048b738987 >>>> +--- /dev/null >>>> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h >>>> +@@ -0,0 +1,113 @@ >>>> ++/** @file >>>> ++ This file includes the function prototypes for the sanitization functions. >>>> ++ >>>> ++ These are those functions: >>>> ++ >>>> ++ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content >>>> ++ read is within the image buffer. >>>> ++ >>>> ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse >>>> ++ partition data carefully. >>>> ++ >>>> ++ Copyright (c) Microsoft Corporation.<BR> >>>> ++ SPDX-License-Identifier: BSD-2-Clause-Patent >>>> ++ >>>> ++**/ >>>> ++ >>>> ++#ifndef DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ >>>> ++#define DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ >>>> ++ >>>> ++#include <Uefi.h> >>>> ++#include <Uefi/UefiSpec.h> >>>> ++#include <Protocol/BlockIo.h> >>>> ++#include <IndustryStandard/UefiTcgPlatform.h> >>>> ++#include <Protocol/Tcg2Protocol.h> >>>> ++ >>>> ++/** >>>> ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse >>>> ++ However this function will not attempt to verify the validity of the GPT partition >>>> ++ It will check the following: >>>> ++ - Signature >>>> ++ - Revision >>>> ++ - AlternateLBA >>>> ++ - FirstUsableLBA >>>> ++ - LastUsableLBA >>>> ++ - PartitionEntryLBA >>>> ++ - NumberOfPartitionEntries >>>> ++ - SizeOfPartitionEntry >>>> ++ - BlockIo >>>> ++ >>>> ++ @param[in] PrimaryHeader >>>> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. >>>> ++ >>>> ++ @param[in] BlockIo >>>> ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. >>>> ++ >>>> ++ @retval EFI_SUCCESS >>>> ++ The EFI_PARTITION_TABLE_HEADER structure is valid. >>>> ++ >>>> ++ @retval EFI_INVALID_PARAMETER >>>> ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. >>>> ++**/ >>>> ++EFI_STATUS >>>> ++EFIAPI >>>> ++SanitizeEfiPartitionTableHeader ( >>>> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, >>>> ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo >>>> ++ ); >>>> ++ >>>> ++/** >>>> ++ This function will validate that the allocation size from the primary header is sane >>>> ++ It will check the following: >>>> ++ - AllocationSize does not overflow >>>> ++ >>>> ++ @param[in] PrimaryHeader >>>> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. >>>> ++ >>>> ++ @param[out] AllocationSize >>>> ++ Pointer to the allocation size. >>>> ++ >>>> ++ @retval EFI_SUCCESS >>>> ++ The allocation size is valid. >>>> ++ >>>> ++ @retval EFI_OUT_OF_RESOURCES >>>> ++ The allocation size is invalid. >>>> ++**/ >>>> ++EFI_STATUS >>>> ++EFIAPI >>>> ++SanitizePrimaryHeaderAllocationSize ( >>>> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, >>>> ++ OUT UINT32 *AllocationSize >>>> ++ ); >>>> ++ >>>> ++/** >>>> ++ This function will validate that the Gpt Event Size calculated from the primary header is sane >>>> ++ It will check the following: >>>> ++ - EventSize does not overflow >>>> ++ >>>> ++ Important: This function includes the entire length of the allocated space, including >>>> ++ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this >>>> ++ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) >>>> ++ from the size of the buffer before hashing. >>>> ++ >>>> ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. >>>> ++ @param[in] NumberOfPartition - Number of partitions. >>>> ++ @param[out] EventSize - Pointer to the event size. >>>> ++ >>>> ++ @retval EFI_SUCCESS >>>> ++ The event size is valid. >>>> ++ >>>> ++ @retval EFI_OUT_OF_RESOURCES >>>> ++ Overflow would have occurred. >>>> ++ >>>> ++ @retval EFI_INVALID_PARAMETER >>>> ++ One of the passed parameters was invalid. >>>> ++**/ >>>> ++EFI_STATUS >>>> ++SanitizePrimaryHeaderGptEventSize ( >>>> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, >>>> ++ IN UINTN NumberOfPartition, >>>> ++ OUT UINT32 *EventSize >>>> ++ ); >>>> ++ >>>> ++#endif // DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ >>>> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c >>>> +new file mode 100644 >>>> +index 0000000000..3eb9763e3c >>>> +--- /dev/null >>>> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c >>>> +@@ -0,0 +1,303 @@ >>>> ++/** @file >>>> ++ This file includes the unit test cases for the DxeTpm2MeasureBootLibSanitizationTest.c. >>>> ++ >>>> ++ Copyright (c) Microsoft Corporation.<BR> >>>> ++ SPDX-License-Identifier: BSD-2-Clause-Patent >>>> ++**/ >>>> ++ >>>> ++#include <Uefi.h> >>>> ++#include <Library/UefiLib.h> >>>> ++#include <Library/DebugLib.h> >>>> ++#include <Library/UnitTestLib.h> >>>> ++#include <Protocol/BlockIo.h> >>>> ++#include <Library/MemoryAllocationLib.h> >>>> ++#include <Library/BaseMemoryLib.h> >>>> ++#include <IndustryStandard/UefiTcgPlatform.h> >>>> ++#include <Protocol/Tcg2Protocol.h> >>>> ++ >>>> ++#include "../DxeTpm2MeasureBootLibSanitization.h" >>>> ++ >>>> ++#define UNIT_TEST_NAME "DxeTpm2MeasureBootLibSanitizationTest" >>>> ++#define UNIT_TEST_VERSION "1.0" >>>> ++ >>>> ++#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000 >>>> ++#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1 >>>> ++#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128 >>>> ++ >>>> ++/** >>>> ++ This function tests the SanitizeEfiPartitionTableHeader function. >>>> ++ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER >>>> ++ structure will not cause undefined or unexpected behavior. >>>> ++ >>>> ++ In general the TPM should still be able to measure the data, but >>>> ++ be the header should be sanitized to prevent any unexpected behavior. >>>> ++ >>>> ++ @param[in] Context The unit test context. >>>> ++ >>>> ++ @retval UNIT_TEST_PASSED The test passed. >>>> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. >>>> ++**/ >>>> ++UNIT_TEST_STATUS >>>> ++EFIAPI >>>> ++TestSanitizeEfiPartitionTableHeader ( >>>> ++ IN UNIT_TEST_CONTEXT Context >>>> ++ ) >>>> ++{ >>>> ++ EFI_STATUS Status; >>>> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; >>>> ++ EFI_BLOCK_IO_PROTOCOL BlockIo; >>>> ++ EFI_BLOCK_IO_MEDIA BlockMedia; >>>> ++ >>>> ++ // Generate EFI_BLOCK_IO_MEDIA test data >>>> ++ BlockMedia.MediaId = 1; >>>> ++ BlockMedia.RemovableMedia = FALSE; >>>> ++ BlockMedia.MediaPresent = TRUE; >>>> ++ BlockMedia.LogicalPartition = FALSE; >>>> ++ BlockMedia.ReadOnly = FALSE; >>>> ++ BlockMedia.WriteCaching = FALSE; >>>> ++ BlockMedia.BlockSize = 512; >>>> ++ BlockMedia.IoAlign = 1; >>>> ++ BlockMedia.LastBlock = 0; >>>> ++ >>>> ++ // Generate EFI_BLOCK_IO_PROTOCOL test data >>>> ++ BlockIo.Revision = 1; >>>> ++ BlockIo.Media = &BlockMedia; >>>> ++ BlockIo.Reset = NULL; >>>> ++ BlockIo.ReadBlocks = NULL; >>>> ++ BlockIo.WriteBlocks = NULL; >>>> ++ BlockIo.FlushBlocks = NULL; >>>> ++ >>>> ++ // Geneate EFI_PARTITION_TABLE_HEADER test data >>>> ++ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID; >>>> ++ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION; >>>> ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); >>>> ++ PrimaryHeader.MyLBA = 1; >>>> ++ PrimaryHeader.AlternateLBA = 2; >>>> ++ PrimaryHeader.FirstUsableLBA = 3; >>>> ++ PrimaryHeader.LastUsableLBA = 4; >>>> ++ PrimaryHeader.PartitionEntryLBA = 5; >>>> ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES; >>>> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; >>>> ++ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid >>>> ++ >>>> ++ // Calculate the CRC32 of the PrimaryHeader >>>> ++ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize); >>>> ++ >>>> ++ // Test that a normal PrimaryHeader passes validation >>>> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); >>>> ++ UT_ASSERT_NOT_EFI_ERROR (Status); >>>> ++ >>>> ++ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR >>>> ++ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!"" >>>> ++ PrimaryHeader.NumberOfPartitionEntries = 0; >>>> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); >>>> ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; >>>> ++ >>>> ++ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR >>>> ++ // Should print "Invalid Partition Table Header Size!" >>>> ++ PrimaryHeader.Header.HeaderSize = 0; >>>> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); >>>> ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); >>>> ++ >>>> ++ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR >>>> ++ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!" >>>> ++ PrimaryHeader.SizeOfPartitionEntry = 1; >>>> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); >>>> ++ >>>> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); >>>> ++ >>>> ++ return UNIT_TEST_PASSED; >>>> ++} >>>> ++ >>>> ++/** >>>> ++ This function tests the SanitizePrimaryHeaderAllocationSize function. >>>> ++ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER >>>> ++ structure will not cause an overflow when calculating the allocation size. >>>> ++ >>>> ++ @param[in] Context The unit test context. >>>> ++ >>>> ++ @retval UNIT_TEST_PASSED The test passed. >>>> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. >>>> ++**/ >>>> ++UNIT_TEST_STATUS >>>> ++EFIAPI >>>> ++TestSanitizePrimaryHeaderAllocationSize ( >>>> ++ IN UNIT_TEST_CONTEXT Context >>>> ++ ) >>>> ++{ >>>> ++ UINT32 AllocationSize; >>>> ++ >>>> ++ EFI_STATUS Status; >>>> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; >>>> ++ >>>> ++ // Test that a normal PrimaryHeader passes validation >>>> ++ PrimaryHeader.NumberOfPartitionEntries = 5; >>>> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; >>>> ++ >>>> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); >>>> ++ UT_ASSERT_NOT_EFI_ERROR (Status); >>>> ++ >>>> ++ // Test that the allocation size is correct compared to the existing logic >>>> ++ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry); >>>> ++ >>>> ++ // Test that an overflow is detected >>>> ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; >>>> ++ PrimaryHeader.SizeOfPartitionEntry = 5; >>>> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); >>>> ++ >>>> ++ // Test the inverse >>>> ++ PrimaryHeader.NumberOfPartitionEntries = 5; >>>> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; >>>> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); >>>> ++ >>>> ++ // Test the worst case scenario >>>> ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; >>>> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; >>>> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); >>>> ++ >>>> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); >>>> ++ >>>> ++ return UNIT_TEST_PASSED; >>>> ++} >>>> ++ >>>> ++/** >>>> ++ This function tests the SanitizePrimaryHeaderGptEventSize function. >>>> ++ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure >>>> ++ will not cause an overflow when calculating the event size. >>>> ++ >>>> ++ @param[in] Context The unit test context. >>>> ++ >>>> ++ @retval UNIT_TEST_PASSED The test passed. >>>> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. >>>> ++**/ >>>> ++UNIT_TEST_STATUS >>>> ++EFIAPI >>>> ++TestSanitizePrimaryHeaderGptEventSize ( >>>> ++ IN UNIT_TEST_CONTEXT Context >>>> ++ ) >>>> ++{ >>>> ++ UINT32 EventSize; >>>> ++ UINT32 ExistingLogicEventSize; >>>> ++ EFI_STATUS Status; >>>> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; >>>> ++ UINTN NumberOfPartition; >>>> ++ EFI_GPT_DATA *GptData; >>>> ++ EFI_TCG2_EVENT *Tcg2Event; >>>> ++ >>>> ++ Tcg2Event = NULL; >>>> ++ GptData = NULL; >>>> ++ >>>> ++ // Test that a normal PrimaryHeader passes validation >>>> ++ PrimaryHeader.NumberOfPartitionEntries = 5; >>>> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; >>>> ++ >>>> ++ // set the number of partitions >>>> ++ NumberOfPartition = 13; >>>> ++ >>>> ++ // that the primary event size is correct >>>> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); >>>> ++ UT_ASSERT_NOT_EFI_ERROR (Status); >>>> ++ >>>> ++ // Calculate the existing logic event size >>>> ++ ExistingLogicEventSize = (UINT32)(OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions) >>>> ++ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry); >>>> ++ >>>> ++ // Check that the event size is correct >>>> ++ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize); >>>> ++ >>>> ++ // Tests that the primary event size may not overflow >>>> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); >>>> ++ >>>> ++ // Test that the size of partition entries may not overflow >>>> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; >>>> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); >>>> ++ >>>> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); >>>> ++ >>>> ++ return UNIT_TEST_PASSED; >>>> ++} >>>> ++ >>>> ++// *--------------------------------------------------------------------* >>>> ++// * Unit Test Code Main Function >>>> ++// *--------------------------------------------------------------------* >>>> ++ >>>> ++/** >>>> ++ This function acts as the entry point for the unit tests. >>>> ++ >>>> ++ @retval UNIT_TEST_PASSED The test passed. >>>> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. >>>> ++ @retval others The test failed. >>>> ++**/ >>>> ++EFI_STATUS >>>> ++EFIAPI >>>> ++UefiTestMain ( >>>> ++ VOID >>>> ++ ) >>>> ++{ >>>> ++ EFI_STATUS Status; >>>> ++ UNIT_TEST_FRAMEWORK_HANDLE Framework; >>>> ++ UNIT_TEST_SUITE_HANDLE Tcg2MeasureBootLibValidationTestSuite; >>>> ++ >>>> ++ Framework = NULL; >>>> ++ >>>> ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME)); >>>> ++ >>>> ++ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION); >>>> ++ if (EFI_ERROR (Status)) { >>>> ++ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status)); >>>> ++ goto EXIT; >>>> ++ } >>>> ++ >>>> ++ Status = CreateUnitTestSuite (&Tcg2MeasureBootLibValidationTestSuite, Framework, "Tcg2MeasureBootLibValidationTestSuite", "Common.Tcg2MeasureBootLibValidation", NULL, NULL); >>>> ++ if (EFI_ERROR (Status)) { >>>> ++ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for Tcg2MeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME)); >>>> ++ Status = EFI_OUT_OF_RESOURCES; >>>> ++ goto EXIT; >>>> ++ } >>>> ++ >>>> ++ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context >>>> ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.Tcg2MeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL); >>>> ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL); >>>> ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL); >>>> ++ >>>> ++ Status = RunAllTestSuites (Framework); >>>> ++ >>>> ++EXIT: >>>> ++ if (Framework != NULL) { >>>> ++ FreeUnitTestFramework (Framework); >>>> ++ } >>>> ++ >>>> ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME)); >>>> ++ return Status; >>>> ++} >>>> ++ >>>> ++/// >>>> ++/// Avoid ECC error for function name that starts with lower case letter >>>> ++/// >>>> ++#define DxeTpm2MeasureBootLibUnitTestMain main >>>> ++ >>>> ++/** >>>> ++ Standard POSIX C entry point for host based unit test execution. >>>> ++ >>>> ++ @param[in] Argc Number of arguments >>>> ++ @param[in] Argv Array of pointers to arguments >>>> ++ >>>> ++ @retval 0 Success >>>> ++ @retval other Error >>>> ++**/ >>>> ++INT32 >>>> ++DxeTpm2MeasureBootLibUnitTestMain ( >>>> ++ IN INT32 Argc, >>>> ++ IN CHAR8 *Argv[] >>>> ++ ) >>>> ++{ >>>> ++ return (INT32)UefiTestMain (); >>>> ++} >>>> +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf >>>> +new file mode 100644 >>>> +index 0000000000..2999aa2a44 >>>> +--- /dev/null >>>> ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf >>>> +@@ -0,0 +1,28 @@ >>>> ++## @file >>>> ++# This file builds the unit tests for DxeTpm2MeasureBootLib >>>> ++# >>>> ++# Copyright (C) Microsoft Corporation.<BR> >>>> ++# SPDX-License-Identifier: BSD-2-Clause-Patent >>>> ++## >>>> ++ >>>> ++[Defines] >>>> ++ INF_VERSION = 0x00010006 >>>> ++ BASE_NAME = DxeTpm2MeasuredBootLibTest >>>> ++ FILE_GUID = 144d757f-d423-484e-9309-a23695fad5bd >>>> ++ MODULE_TYPE = HOST_APPLICATION >>>> ++ VERSION_STRING = 1.0 >>>> ++ ENTRY_POINT = main >>>> ++ >>>> ++[Sources] >>>> ++ DxeTpm2MeasureBootLibSanitizationTest.c >>>> ++ ../DxeTpm2MeasureBootLibSanitization.c >>>> ++ >>>> ++[Packages] >>>> ++ MdePkg/MdePkg.dec >>>> ++ >>>> ++[LibraryClasses] >>>> ++ BaseLib >>>> ++ DebugLib >>>> ++ UnitTestLib >>>> ++ PrintLib >>>> ++ SafeIntLib >>>> +diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml >>>> +index 7912142398..da811fdf93 100644 >>>> +--- a/SecurityPkg/SecurityPkg.ci.yaml >>>> ++++ b/SecurityPkg/SecurityPkg.ci.yaml >>>> +@@ -15,6 +15,7 @@ >>>> + ## "<ErrorID>", "<KeyWord>" >>>> + ## ] >>>> + "ExceptionList": [ >>>> ++ "8001", "DxeTpm2MeasureBootLibUnitTestMain", >>>> + ], >>>> + ## Both file path and directory path are accepted. >>>> + "IgnoreFiles": [ >>>> +-- >>>> +2.40.0 >>>> + >>>> diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch >>>> new file mode 100644 >>>> index 0000000000..6c20cc305e >>>> --- /dev/null >>>> +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch >>>> @@ -0,0 +1,889 @@ >>>> +From 4776a1b39ee08fc45c70c1eab5a0195f325000d3 Mon Sep 17 00:00:00 2001 >>>> +From: "Douglas Flick [MSFT]"<doug.edk2@gmail.com> >>>> +Date: Fri, 12 Jan 2024 02:16:02 +0800 >>>> +Subject: [PATCH] SecurityPkg: DxeTpmMeasureBootLib: SECURITY PATCH 4117 - CVE >>>> + 2022-36763 >>>> + >>>> +This commit contains the patch files and tests for DxeTpmMeasureBootLib >>>> +CVE 2022-36763. >>>> + >>>> +Cc: Jiewen Yao<jiewen.yao@intel.com> >>>> + >>>> +Signed-off-by: Doug Flick [MSFT]<doug.edk2@gmail.com> >>>> +Reviewed-by: Jiewen Yao<jiewen.yao@intel.com> >>>> + >>>> +CVE: CVE-2022-36763 >>>> + >>>> +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/4776a1b39ee08fc45c70c1eab5a0195f325000d3] >>>> + >>>> +Signed-off-by: Soumya Sambu<soumya.sambu@windriver.com> >>>> +--- >>>> + .../DxeTpmMeasureBootLib.c | 40 ++- >>>> + .../DxeTpmMeasureBootLib.inf | 4 +- >>>> + .../DxeTpmMeasureBootLibSanitization.c | 241 ++++++++++++++ >>>> + .../DxeTpmMeasureBootLibSanitization.h | 114 +++++++ >>>> + .../DxeTpmMeasureBootLibSanitizationTest.c | 301 ++++++++++++++++++ >>>> + ...eTpmMeasureBootLibSanitizationTestHost.inf | 28 ++ >>>> + SecurityPkg/SecurityPkg.ci.yaml | 1 + >>>> + 7 files changed, 715 insertions(+), 14 deletions(-) >>>> + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c >>>> + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h >>>> + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c >>>> + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf >>>> + >>>> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c >>>> +index 220393dd2b..669ab19134 100644 >>>> +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c >>>> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c >>>> +@@ -18,6 +18,8 @@ >>>> + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> >>>> + SPDX-License-Identifier: BSD-2-Clause-Patent >>>> + >>>> ++Copyright (c) Microsoft Corporation.<BR> >>>> ++SPDX-License-Identifier: BSD-2-Clause-Patent >>>> + **/ >>>> + >>>> + #include <PiDxe.h> >>>> +@@ -40,6 +42,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent >>>> + #include <Library/SecurityManagementLib.h> >>>> + #include <Library/HobLib.h> >>>> + >>>> ++#include "DxeTpmMeasureBootLibSanitization.h" >>>> ++ >>>> + // >>>> + // Flag to check GPT partition. It only need be measured once. >>>> + // >>>> +@@ -136,6 +140,9 @@ TcgMeasureGptTable ( >>>> + UINT32 EventSize; >>>> + UINT32 EventNumber; >>>> + EFI_PHYSICAL_ADDRESS EventLogLastEntry; >>>> ++ UINT32 AllocSize; >>>> ++ >>>> ++ GptData = NULL; >>>> + >>>> + if (mMeasureGptCount > 0) { >>>> + return EFI_SUCCESS; >>>> +@@ -166,8 +173,8 @@ TcgMeasureGptTable ( >>>> + BlockIo->Media->BlockSize, >>>> + (UINT8 *)PrimaryHeader >>>> + ); >>>> +- if (EFI_ERROR (Status)) { >>>> +- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n")); >>>> ++ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) { >>>> ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n")); >>>> + FreePool (PrimaryHeader); >>>> + return EFI_DEVICE_ERROR; >>>> + } >>>> +@@ -175,7 +182,13 @@ TcgMeasureGptTable ( >>>> + // >>>> + // Read the partition entry. >>>> + // >>>> +- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry); >>>> ++ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize); >>>> ++ if (EFI_ERROR (Status)) { >>>> ++ FreePool (PrimaryHeader); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize); >>>> + if (EntryPtr == NULL) { >>>> + FreePool (PrimaryHeader); >>>> + return EFI_OUT_OF_RESOURCES; >>>> +@@ -185,7 +198,7 @@ TcgMeasureGptTable ( >>>> + DiskIo, >>>> + BlockIo->Media->MediaId, >>>> + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), >>>> +- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry, >>>> ++ AllocSize, >>>> + EntryPtr >>>> + ); >>>> + if (EFI_ERROR (Status)) { >>>> +@@ -210,9 +223,8 @@ TcgMeasureGptTable ( >>>> + // >>>> + // Prepare Data for Measurement >>>> + // >>>> +- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) >>>> +- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry); >>>> +- TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT_HDR)); >>>> ++ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &EventSize); >>>> ++ TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize); >>>> + if (TcgEvent == NULL) { >>>> + FreePool (PrimaryHeader); >>>> + FreePool (EntryPtr); >>>> +@@ -221,7 +233,7 @@ TcgMeasureGptTable ( >>>> + >>>> + TcgEvent->PCRIndex = 5; >>>> + TcgEvent->EventType = EV_EFI_GPT_EVENT; >>>> +- TcgEvent->EventSize = EventSize; >>>> ++ TcgEvent->EventSize = EventSize - sizeof (TCG_PCR_EVENT_HDR); >>>> + GptData = (EFI_GPT_DATA *)TcgEvent->Event; >>>> + >>>> + // >>>> +@@ -361,11 +373,13 @@ TcgMeasurePeImage ( >>>> + TcgEvent->PCRIndex = 2; >>>> + break; >>>> + default: >>>> +- DEBUG (( >>>> +- DEBUG_ERROR, >>>> +- "TcgMeasurePeImage: Unknown subsystem type %d", >>>> +- ImageType >>>> +- )); >>>> ++ DEBUG ( >>>> ++ ( >>>> ++ DEBUG_ERROR, >>>> ++ "TcgMeasurePeImage: Unknown subsystem type %d", >>>> ++ ImageType >>>> ++ ) >>>> ++ ); >>>> + goto Finish; >>>> + } >>>> + >>>> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf >>>> +index ebab6f7c1e..414c654d15 100644 >>>> +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf >>>> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf >>>> +@@ -32,6 +32,8 @@ >>>> + >>>> + [Sources] >>>> + DxeTpmMeasureBootLib.c >>>> ++ DxeTpmMeasureBootLibSanitization.c >>>> ++ DxeTpmMeasureBootLibSanitization.h >>>> + >>>> + [Packages] >>>> + MdePkg/MdePkg.dec >>>> +@@ -41,6 +43,7 @@ >>>> + >>>> + [LibraryClasses] >>>> + BaseMemoryLib >>>> ++ SafeIntLib >>>> + DebugLib >>>> + MemoryAllocationLib >>>> + DevicePathLib >>>> +@@ -59,4 +62,3 @@ >>>> + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES >>>> + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES >>>> + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES >>>> +- >>>> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c >>>> +new file mode 100644 >>>> +index 0000000000..a3fa46f5e6 >>>> +--- /dev/null >>>> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c >>>> +@@ -0,0 +1,241 @@ >>>> ++/** @file >>>> ++ The library instance provides security service of TPM2 measure boot and >>>> ++ Confidential Computing (CC) 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. >>>> ++ >>>> ++ This file will pull out the validation logic from the following functions, in an >>>> ++ attempt to validate the untrusted input in the form of unit tests >>>> ++ >>>> ++ These are those functions: >>>> ++ >>>> ++ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content >>>> ++ read is within the image buffer. >>>> ++ >>>> ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse >>>> ++ partition data carefully. >>>> ++ >>>> ++ Copyright (c) Microsoft Corporation.<BR> >>>> ++ SPDX-License-Identifier: BSD-2-Clause-Patent >>>> ++**/ >>>> ++#include <Uefi.h> >>>> ++#include <Uefi/UefiSpec.h> >>>> ++#include <Library/SafeIntLib.h> >>>> ++#include <Library/UefiLib.h> >>>> ++#include <Library/DebugLib.h> >>>> ++#include <Library/BaseLib.h> >>>> ++#include <IndustryStandard/UefiTcgPlatform.h> >>>> ++#include <Protocol/BlockIo.h> >>>> ++#include <Library/MemoryAllocationLib.h> >>>> ++ >>>> ++#include "DxeTpmMeasureBootLibSanitization.h" >>>> ++ >>>> ++#define GPT_HEADER_REVISION_V1 0x00010000 >>>> ++ >>>> ++/** >>>> ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse >>>> ++ However this function will not attempt to verify the validity of the GPT partition >>>> ++ It will check the following: >>>> ++ - Signature >>>> ++ - Revision >>>> ++ - AlternateLBA >>>> ++ - FirstUsableLBA >>>> ++ - LastUsableLBA >>>> ++ - PartitionEntryLBA >>>> ++ - NumberOfPartitionEntries >>>> ++ - SizeOfPartitionEntry >>>> ++ - BlockIo >>>> ++ >>>> ++ @param[in] PrimaryHeader >>>> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. >>>> ++ >>>> ++ @param[in] BlockIo >>>> ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. >>>> ++ >>>> ++ @retval EFI_SUCCESS >>>> ++ The EFI_PARTITION_TABLE_HEADER structure is valid. >>>> ++ >>>> ++ @retval EFI_INVALID_PARAMETER >>>> ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. >>>> ++**/ >>>> ++EFI_STATUS >>>> ++EFIAPI >>>> ++SanitizeEfiPartitionTableHeader ( >>>> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, >>>> ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo >>>> ++ ) >>>> ++{ >>>> ++ // Verify that the input parameters are safe to use >>>> ++ if (PrimaryHeader == NULL) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); >>>> ++ return EFI_INVALID_PARAMETER; >>>> ++ } >>>> ++ >>>> ++ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n")); >>>> ++ return EFI_INVALID_PARAMETER; >>>> ++ } >>>> ++ >>>> ++ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII) >>>> ++ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ // The version must be GPT_HEADER_REVISION_V1 (0x00010000) >>>> ++ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n")); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size >>>> ++ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n")); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ // check that the PartitionEntryLBA greater than the Max LBA >>>> ++ // This will be used later for multiplication >>>> ++ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n")); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ // Check that the number of partition entries is greater than zero >>>> ++ if (PrimaryHeader->NumberOfPartitionEntries == 0) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory >>>> ++ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) { >>>> ++ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n")); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ // This check is to prevent overflow when calculating the allocation size for the partition entries >>>> ++ // This check will be used later for multiplication >>>> ++ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) { >>>> ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); >>>> ++ return EFI_DEVICE_ERROR; >>>> ++ } >>>> ++ >>>> ++ return EFI_SUCCESS; >>>> ++} >>>> ++ >>>> ++/** >>>> ++ This function will validate that the allocation size from the primary header is sane >>>> ++ It will check the following: >>>> ++ - AllocationSize does not overflow >>>> ++ >>>> ++ @param[in] PrimaryHeader >>>> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. >>>> ++ >>>> ++ @param[out] AllocationSize >>>> ++ Pointer to the allocation size. >>>> ++ >>>> ++ @retval EFI_SUCCESS >>>> ++ The allocation size is valid. >>>> ++ >>>> ++ @retval EFI_OUT_OF_RESOURCES >>>> ++ The allocation size is invalid. >>>> ++**/ >>>> ++EFI_STATUS >>>> ++EFIAPI >>>> ++SanitizePrimaryHeaderAllocationSize ( >>>> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, >>>> ++ OUT UINT32 *AllocationSize >>>> ++ ) >>>> ++{ >>>> ++ EFI_STATUS Status; >>>> ++ >>>> ++ if (PrimaryHeader == NULL) { >>>> ++ return EFI_INVALID_PARAMETER; >>>> ++ } >>>> ++ >>>> ++ if (AllocationSize == NULL) { >>>> ++ return EFI_INVALID_PARAMETER; >>>> ++ } >>>> ++ >>>> ++ // Replacing logic: >>>> ++ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry; >>>> ++ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize); >>>> ++ if (EFI_ERROR (Status)) { >>>> ++ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n")); >>>> ++ return EFI_BAD_BUFFER_SIZE; >>>> ++ } >>>> ++ >>>> ++ return EFI_SUCCESS; >>>> ++} >>>> ++ >>>> ++/** >>>> ++ This function will validate that the Gpt Event Size calculated from the primary header is sane >>>> ++ It will check the following: >>>> ++ - EventSize does not overflow >>>> ++ >>>> ++ Important: This function includes the entire length of the allocated space, including the >>>> ++ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract >>>> ++ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing. >>>> ++ >>>> ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. >>>> ++ @param[in] NumberOfPartition - Number of partitions. >>>> ++ @param[out] EventSize - Pointer to the event size. >>>> ++ >>>> ++ @retval EFI_SUCCESS >>>> ++ The event size is valid. >>>> ++ >>>> ++ @retval EFI_OUT_OF_RESOURCES >>>> ++ Overflow would have occurred. >>>> ++ >>>> ++ @retval EFI_INVALID_PARAMETER >>>> ++ One of the passed parameters was invalid. >>>> ++**/ >>>> ++EFI_STATUS >>>> ++SanitizePrimaryHeaderGptEventSize ( >>>> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, >>>> ++ IN UINTN NumberOfPartition, >>>> ++ OUT UINT32 *EventSize >>>> ++ ) >>>> ++{ >>>> ++ EFI_STATUS Status; >>>> ++ UINT32 SafeNumberOfPartitions; >>>> ++ >>>> ++ if (PrimaryHeader == NULL) { >>>> ++ return EFI_INVALID_PARAMETER; >>>> ++ } >>>> ++ >>>> ++ if (EventSize == NULL) { >>>> ++ return EFI_INVALID_PARAMETER; >>>> ++ } >>>> ++ >>>> ++ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32 >>>> ++ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions); >>>> ++ if (EFI_ERROR (Status)) { >>>> ++ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n")); >>>> ++ return EFI_INVALID_PARAMETER; >>>> ++ } >>>> ++ >>>> ++ // Replacing logic: >>>> ++ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry + sizeof (TCG_PCR_EVENT_HDR)); >>>> ++ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize); >>>> ++ if (EFI_ERROR (Status)) { >>>> ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n")); >>>> ++ return EFI_BAD_BUFFER_SIZE; >>>> ++ } >>>> ++ >>>> ++ Status = SafeUint32Add ( >>>> ++ sizeof (TCG_PCR_EVENT_HDR) + >>>> ++ OFFSET_OF (EFI_GPT_DATA, Partitions), >>>> ++ *EventSize, >>>> ++ EventSize >>>> ++ ); >>>> ++ if (EFI_ERROR (Status)) { >>>> ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n")); >>>> ++ return EFI_BAD_BUFFER_SIZE; >>>> ++ } >>>> ++ >>>> ++ return EFI_SUCCESS; >>>> ++} >>>> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h >>>> +new file mode 100644 >>>> +index 0000000000..0d9d00c281 >>>> +--- /dev/null >>>> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h >>>> +@@ -0,0 +1,114 @@ >>>> ++/** @file >>>> ++ This file includes the function prototypes for the sanitization functions. >>>> ++ >>>> ++ These are those functions: >>>> ++ >>>> ++ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content >>>> ++ read is within the image buffer. >>>> ++ >>>> ++ TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its >>>> ++ data structure within this image buffer before use. >>>> ++ >>>> ++ TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse >>>> ++ partition data carefully. >>>> ++ >>>> ++ Copyright (c) Microsoft Corporation.<BR> >>>> ++ SPDX-License-Identifier: BSD-2-Clause-Patent >>>> ++ >>>> ++**/ >>>> ++ >>>> ++#ifndef DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ >>>> ++#define DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ >>>> ++ >>>> ++#include <Uefi.h> >>>> ++#include <Uefi/UefiSpec.h> >>>> ++#include <Protocol/BlockIo.h> >>>> ++#include <IndustryStandard/UefiTcgPlatform.h> >>>> ++ >>>> ++/** >>>> ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse >>>> ++ However this function will not attempt to verify the validity of the GPT partition >>>> ++ It will check the following: >>>> ++ - Signature >>>> ++ - Revision >>>> ++ - AlternateLBA >>>> ++ - FirstUsableLBA >>>> ++ - LastUsableLBA >>>> ++ - PartitionEntryLBA >>>> ++ - NumberOfPartitionEntries >>>> ++ - SizeOfPartitionEntry >>>> ++ - BlockIo >>>> ++ >>>> ++ @param[in] PrimaryHeader >>>> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. >>>> ++ >>>> ++ @param[in] BlockIo >>>> ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. >>>> ++ >>>> ++ @retval EFI_SUCCESS >>>> ++ The EFI_PARTITION_TABLE_HEADER structure is valid. >>>> ++ >>>> ++ @retval EFI_INVALID_PARAMETER >>>> ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. >>>> ++**/ >>>> ++EFI_STATUS >>>> ++EFIAPI >>>> ++SanitizeEfiPartitionTableHeader ( >>>> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, >>>> ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo >>>> ++ ); >>>> ++ >>>> ++/** >>>> ++ This function will validate that the allocation size from the primary header is sane >>>> ++ It will check the following: >>>> ++ - AllocationSize does not overflow >>>> ++ >>>> ++ @param[in] PrimaryHeader >>>> ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. >>>> ++ >>>> ++ @param[out] AllocationSize >>>> ++ Pointer to the allocation size. >>>> ++ >>>> ++ @retval EFI_SUCCESS >>>> ++ The allocation size is valid. >>>> ++ >>>> ++ @retval EFI_OUT_OF_RESOURCES >>>> ++ The allocation size is invalid. >>>> ++**/ >>>> ++EFI_STATUS >>>> ++EFIAPI >>>> ++SanitizePrimaryHeaderAllocationSize ( >>>> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, >>>> ++ OUT UINT32 *AllocationSize >>>> ++ ); >>>> ++ >>>> ++/** >>>> ++ This function will validate that the Gpt Event Size calculated from the primary header is sane >>>> ++ It will check the following: >>>> ++ - EventSize does not overflow >>>> ++ >>>> ++ Important: This function includes the entire length of the allocated space, including the >>>> ++ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract >>>> ++ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing. >>>> ++ >>>> ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. >>>> ++ @param[in] NumberOfPartition - Number of partitions. >>>> ++ @param[out] EventSize - Pointer to the event size. >>>> ++ >>>> ++ @retval EFI_SUCCESS >>>> ++ The event size is valid. >>>> ++ >>>> ++ @retval EFI_OUT_OF_RESOURCES >>>> ++ Overflow would have occurred. >>>> ++ >>>> ++ @retval EFI_INVALID_PARAMETER >>>> ++ One of the passed parameters was invalid. >>>> ++**/ >>>> ++EFI_STATUS >>>> ++SanitizePrimaryHeaderGptEventSize ( >>>> ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, >>>> ++ IN UINTN NumberOfPartition, >>>> ++ OUT UINT32 *EventSize >>>> ++ ); >>>> ++ >>>> ++#endif // DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ >>>> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c >>>> +new file mode 100644 >>>> +index 0000000000..eeb928cdb0 >>>> +--- /dev/null >>>> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c >>>> +@@ -0,0 +1,301 @@ >>>> ++/** @file >>>> ++This file includes the unit test cases for the DxeTpmMeasureBootLibSanitizationTest.c. >>>> ++ >>>> ++Copyright (c) Microsoft Corporation.<BR> >>>> ++SPDX-License-Identifier: BSD-2-Clause-Patent >>>> ++**/ >>>> ++ >>>> ++#include <Uefi.h> >>>> ++#include <Library/UefiLib.h> >>>> ++#include <Library/DebugLib.h> >>>> ++#include <Library/UnitTestLib.h> >>>> ++#include <Protocol/BlockIo.h> >>>> ++#include <Library/MemoryAllocationLib.h> >>>> ++#include <Library/BaseMemoryLib.h> >>>> ++#include <IndustryStandard/UefiTcgPlatform.h> >>>> ++ >>>> ++#include "../DxeTpmMeasureBootLibSanitization.h" >>>> ++ >>>> ++#define UNIT_TEST_NAME "DxeTpmMeasureBootLibSanitizationTest" >>>> ++#define UNIT_TEST_VERSION "1.0" >>>> ++ >>>> ++#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000 >>>> ++#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1 >>>> ++#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128 >>>> ++ >>>> ++/** >>>> ++ This function tests the SanitizeEfiPartitionTableHeader function. >>>> ++ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER >>>> ++ structure will not cause undefined or unexpected behavior. >>>> ++ >>>> ++ In general the TPM should still be able to measure the data, but >>>> ++ be the header should be sanitized to prevent any unexpected behavior. >>>> ++ >>>> ++ @param[in] Context The unit test context. >>>> ++ >>>> ++ @retval UNIT_TEST_PASSED The test passed. >>>> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. >>>> ++**/ >>>> ++UNIT_TEST_STATUS >>>> ++EFIAPI >>>> ++TestSanitizeEfiPartitionTableHeader ( >>>> ++ IN UNIT_TEST_CONTEXT Context >>>> ++ ) >>>> ++{ >>>> ++ EFI_STATUS Status; >>>> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; >>>> ++ EFI_BLOCK_IO_PROTOCOL BlockIo; >>>> ++ EFI_BLOCK_IO_MEDIA BlockMedia; >>>> ++ >>>> ++ // Generate EFI_BLOCK_IO_MEDIA test data >>>> ++ BlockMedia.MediaId = 1; >>>> ++ BlockMedia.RemovableMedia = FALSE; >>>> ++ BlockMedia.MediaPresent = TRUE; >>>> ++ BlockMedia.LogicalPartition = FALSE; >>>> ++ BlockMedia.ReadOnly = FALSE; >>>> ++ BlockMedia.WriteCaching = FALSE; >>>> ++ BlockMedia.BlockSize = 512; >>>> ++ BlockMedia.IoAlign = 1; >>>> ++ BlockMedia.LastBlock = 0; >>>> ++ >>>> ++ // Generate EFI_BLOCK_IO_PROTOCOL test data >>>> ++ BlockIo.Revision = 1; >>>> ++ BlockIo.Media = &BlockMedia; >>>> ++ BlockIo.Reset = NULL; >>>> ++ BlockIo.ReadBlocks = NULL; >>>> ++ BlockIo.WriteBlocks = NULL; >>>> ++ BlockIo.FlushBlocks = NULL; >>>> ++ >>>> ++ // Geneate EFI_PARTITION_TABLE_HEADER test data >>>> ++ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID; >>>> ++ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION; >>>> ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); >>>> ++ PrimaryHeader.MyLBA = 1; >>>> ++ PrimaryHeader.AlternateLBA = 2; >>>> ++ PrimaryHeader.FirstUsableLBA = 3; >>>> ++ PrimaryHeader.LastUsableLBA = 4; >>>> ++ PrimaryHeader.PartitionEntryLBA = 5; >>>> ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES; >>>> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; >>>> ++ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid >>>> ++ >>>> ++ // Calculate the CRC32 of the PrimaryHeader >>>> ++ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize); >>>> ++ >>>> ++ // Test that a normal PrimaryHeader passes validation >>>> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); >>>> ++ UT_ASSERT_NOT_EFI_ERROR (Status); >>>> ++ >>>> ++ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR >>>> ++ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!"" >>>> ++ PrimaryHeader.NumberOfPartitionEntries = 0; >>>> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); >>>> ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; >>>> ++ >>>> ++ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR >>>> ++ // Should print "Invalid Partition Table Header Size!" >>>> ++ PrimaryHeader.Header.HeaderSize = 0; >>>> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); >>>> ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); >>>> ++ >>>> ++ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR >>>> ++ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!" >>>> ++ PrimaryHeader.SizeOfPartitionEntry = 1; >>>> ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); >>>> ++ >>>> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); >>>> ++ >>>> ++ return UNIT_TEST_PASSED; >>>> ++} >>>> ++ >>>> ++/** >>>> ++ This function tests the SanitizePrimaryHeaderAllocationSize function. >>>> ++ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER >>>> ++ structure will not cause an overflow when calculating the allocation size. >>>> ++ >>>> ++ @param[in] Context The unit test context. >>>> ++ >>>> ++ @retval UNIT_TEST_PASSED The test passed. >>>> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. >>>> ++**/ >>>> ++UNIT_TEST_STATUS >>>> ++EFIAPI >>>> ++TestSanitizePrimaryHeaderAllocationSize ( >>>> ++ IN UNIT_TEST_CONTEXT Context >>>> ++ ) >>>> ++{ >>>> ++ UINT32 AllocationSize; >>>> ++ >>>> ++ EFI_STATUS Status; >>>> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; >>>> ++ >>>> ++ // Test that a normal PrimaryHeader passes validation >>>> ++ PrimaryHeader.NumberOfPartitionEntries = 5; >>>> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; >>>> ++ >>>> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); >>>> ++ UT_ASSERT_NOT_EFI_ERROR (Status); >>>> ++ >>>> ++ // Test that the allocation size is correct compared to the existing logic >>>> ++ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry); >>>> ++ >>>> ++ // Test that an overflow is detected >>>> ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; >>>> ++ PrimaryHeader.SizeOfPartitionEntry = 5; >>>> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); >>>> ++ >>>> ++ // Test the inverse >>>> ++ PrimaryHeader.NumberOfPartitionEntries = 5; >>>> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; >>>> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); >>>> ++ >>>> ++ // Test the worst case scenario >>>> ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; >>>> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; >>>> ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); >>>> ++ >>>> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); >>>> ++ >>>> ++ return UNIT_TEST_PASSED; >>>> ++} >>>> ++ >>>> ++/** >>>> ++ This function tests the SanitizePrimaryHeaderGptEventSize function. >>>> ++ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure >>>> ++ will not cause an overflow when calculating the event size. >>>> ++ >>>> ++ @param[in] Context The unit test context. >>>> ++ >>>> ++ @retval UNIT_TEST_PASSED The test passed. >>>> ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. >>>> ++**/ >>>> ++UNIT_TEST_STATUS >>>> ++EFIAPI >>>> ++TestSanitizePrimaryHeaderGptEventSize ( >>>> ++ IN UNIT_TEST_CONTEXT Context >>>> ++ ) >>>> ++{ >>>> ++ UINT32 EventSize; >>>> ++ UINT32 ExistingLogicEventSize; >>>> ++ EFI_STATUS Status; >>>> ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; >>>> ++ UINTN NumberOfPartition; >>>> ++ EFI_GPT_DATA *GptData; >>>> ++ >>>> ++ GptData = NULL; >>>> ++ >>>> ++ // Test that a normal PrimaryHeader passes validation >>>> ++ PrimaryHeader.NumberOfPartitionEntries = 5; >>>> ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; >>>> ++ >>>> ++ // set the number of partitions >>>> ++ NumberOfPartition = 13; >>>> ++ >>>> ++ // that the primary event size is correct >>>> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); >>>> ++ UT_ASSERT_NOT_EFI_ERROR (Status); >>>> ++ >>>> ++ // Calculate the existing logic event size >>>> ++ ExistingLogicEventSize = (UINT32)(sizeof (TCG_PCR_EVENT_HDR) + OFFSET_OF (EFI_GPT_DATA, Partitions) >>>> ++ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry); >>>> ++ >>>> ++ // Check that the event size is correct >>>> ++ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize); >>>> ++ >>>> ++ // Tests that the primary event size may not overflow >>>> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); >>>> ++ >>>> ++ // Test that the size of partition entries may not overflow >>>> ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; >>>> ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); >>>> ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); >>>> ++ >>>> ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); >>>> ++ >>>> ++ return UNIT_TEST_PASSED; >>>> ++} >>>> ++ >>>> ++// *--------------------------------------------------------------------* >>>> ++// * Unit Test Code Main Function >>>> ++// *--------------------------------------------------------------------* >>>> ++ >>>> ++/** >>>> ++ This function acts as the entry point for the unit tests. >>>> ++ >>>> ++ @param argc - The number of command line arguments >>>> ++ @param argv - The command line arguments >>>> ++ >>>> ++ @return int - The status of the test >>>> ++**/ >>>> ++EFI_STATUS >>>> ++EFIAPI >>>> ++UefiTestMain ( >>>> ++ VOID >>>> ++ ) >>>> ++{ >>>> ++ EFI_STATUS Status; >>>> ++ UNIT_TEST_FRAMEWORK_HANDLE Framework; >>>> ++ UNIT_TEST_SUITE_HANDLE TcgMeasureBootLibValidationTestSuite; >>>> ++ >>>> ++ Framework = NULL; >>>> ++ >>>> ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME)); >>>> ++ >>>> ++ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION); >>>> ++ if (EFI_ERROR (Status)) { >>>> ++ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status)); >>>> ++ goto EXIT; >>>> ++ } >>>> ++ >>>> ++ Status = CreateUnitTestSuite (&TcgMeasureBootLibValidationTestSuite, Framework, "TcgMeasureBootLibValidationTestSuite", "Common.TcgMeasureBootLibValidation", NULL, NULL); >>>> ++ if (EFI_ERROR (Status)) { >>>> ++ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for TcgMeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME)); >>>> ++ Status = EFI_OUT_OF_RESOURCES; >>>> ++ goto EXIT; >>>> ++ } >>>> ++ >>>> ++ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context >>>> ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.TcgMeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL); >>>> ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL); >>>> ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL); >>>> ++ >>>> ++ Status = RunAllTestSuites (Framework); >>>> ++ >>>> ++EXIT: >>>> ++ if (Framework != NULL) { >>>> ++ FreeUnitTestFramework (Framework); >>>> ++ } >>>> ++ >>>> ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME)); >>>> ++ return Status; >>>> ++} >>>> ++ >>>> ++/// >>>> ++/// Avoid ECC error for function name that starts with lower case letter >>>> ++/// >>>> ++#define DxeTpmMeasureBootLibUnitTestMain main >>>> ++ >>>> ++/** >>>> ++ Standard POSIX C entry point for host based unit test execution. >>>> ++ >>>> ++ @param[in] Argc Number of arguments >>>> ++ @param[in] Argv Array of pointers to arguments >>>> ++ >>>> ++ @retval 0 Success >>>> ++ @retval other Error >>>> ++**/ >>>> ++INT32 >>>> ++DxeTpmMeasureBootLibUnitTestMain ( >>>> ++ IN INT32 Argc, >>>> ++ IN CHAR8 *Argv[] >>>> ++ ) >>>> ++{ >>>> ++ return (INT32)UefiTestMain (); >>>> ++} >>>> +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf >>>> +new file mode 100644 >>>> +index 0000000000..47b0811b00 >>>> +--- /dev/null >>>> ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf >>>> +@@ -0,0 +1,28 @@ >>>> ++## @file >>>> ++# This file builds the unit tests for DxeTpmMeasureBootLib >>>> ++# >>>> ++# Copyright (C) Microsoft Corporation.<BR> >>>> ++# SPDX-License-Identifier: BSD-2-Clause-Patent >>>> ++## >>>> ++ >>>> ++[Defines] >>>> ++ INF_VERSION = 0x00010006 >>>> ++ BASE_NAME = DxeTpmMeasuredBootLibTest >>>> ++ FILE_GUID = eb01bc38-309c-4d3e-967e-9f078c90772f >>>> ++ MODULE_TYPE = HOST_APPLICATION >>>> ++ VERSION_STRING = 1.0 >>>> ++ ENTRY_POINT = main >>>> ++ >>>> ++[Sources] >>>> ++ DxeTpmMeasureBootLibSanitizationTest.c >>>> ++ ../DxeTpmMeasureBootLibSanitization.c >>>> ++ >>>> ++[Packages] >>>> ++ MdePkg/MdePkg.dec >>>> ++ >>>> ++[LibraryClasses] >>>> ++ BaseLib >>>> ++ DebugLib >>>> ++ UnitTestLib >>>> ++ PrintLib >>>> ++ SafeIntLib >>>> +diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml >>>> +index da811fdf93..0e40eaa0fe 100644 >>>> +--- a/SecurityPkg/SecurityPkg.ci.yaml >>>> ++++ b/SecurityPkg/SecurityPkg.ci.yaml >>>> +@@ -16,6 +16,7 @@ >>>> + ## ] >>>> + "ExceptionList": [ >>>> + "8001", "DxeTpm2MeasureBootLibUnitTestMain", >>>> ++ "8001", "DxeTpmMeasureBootLibUnitTestMain" >>>> + ], >>>> + ## Both file path and directory path are accepted. >>>> + "IgnoreFiles": [ >>>> +-- >>>> +2.40.0 >>>> + >>>> diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch >>>> new file mode 100644 >>>> index 0000000000..59bd5c4910 >>>> --- /dev/null >>>> +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch >>>> @@ -0,0 +1,55 @@ >>>> +From 1ddcb9fc6b4164e882687b031e8beacfcf7df29e Mon Sep 17 00:00:00 2001 >>>> +From: "Douglas Flick [MSFT]"<doug.edk2@gmail.com> >>>> +Date: Fri, 12 Jan 2024 02:16:03 +0800 >>>> +Subject: [PATCH] SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml >>>> + >>>> +This creates / adds a security file that tracks the security fixes >>>> +found in this package and can be used to find the fixes that were >>>> +applied. >>>> + >>>> +Cc: Jiewen Yao<jiewen.yao@intel.com> >>>> + >>>> +Signed-off-by: Doug Flick [MSFT]<doug.edk2@gmail.com> >>>> +Reviewed-by: Jiewen Yao<jiewen.yao@intel.com> >>>> + >>>> +CVE: CVE-2022-36763 >>>> + >>>> +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1ddcb9fc6b4164e882687b031e8beacfcf7df29e] >>>> + >>>> +Signed-off-by: Soumya Sambu<soumya.sambu@windriver.com> >>>> +--- >>>> + SecurityPkg/SecurityFixes.yaml | 22 ++++++++++++++++++++++ >>>> + 1 file changed, 22 insertions(+) >>>> + create mode 100644 SecurityPkg/SecurityFixes.yaml >>>> + >>>> +diff --git a/SecurityPkg/SecurityFixes.yaml b/SecurityPkg/SecurityFixes.yaml >>>> +new file mode 100644 >>>> +index 0000000000..f9e3e7be74 >>>> +--- /dev/null >>>> ++++ b/SecurityPkg/SecurityFixes.yaml >>>> +@@ -0,0 +1,22 @@ >>>> ++## @file >>>> ++# Security Fixes for SecurityPkg >>>> ++# >>>> ++# Copyright (c) Microsoft Corporation >>>> ++# SPDX-License-Identifier: BSD-2-Clause-Patent >>>> ++## >>>> ++CVE_2022_36763: >>>> ++ commit_titles: >>>> ++ - "SecurityPkg: DxeTpm2Measurement: SECURITY PATCH 4117 - CVE 2022-36763" >>>> ++ - "SecurityPkg: DxeTpmMeasurement: SECURITY PATCH 4117 - CVE 2022-36763" >>>> ++ - "SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml" >>>> ++ cve: CVE-2022-36763 >>>> ++ date_reported: 2022-10-25 11:31 UTC >>>> ++ description: (CVE-2022-36763) - Heap Buffer Overflow in Tcg2MeasureGptTable() >>>> ++ note: This patch is related to and supersedes TCBZ2168 >>>> ++ files_impacted: >>>> ++ - Library\DxeTpm2MeasureBootLib\DxeTpm2MeasureBootLib.c >>>> ++ - Library\DxeTpmMeasureBootLib\DxeTpmMeasureBootLib.c >>>> ++ links: >>>> ++ -https://bugzilla.tianocore.org/show_bug.cgi?id=4117 >>>> ++ -https://bugzilla.tianocore.org/show_bug.cgi?id=2168 >>>> ++ -https://bugzilla.tianocore.org/show_bug.cgi?id=1990 >>>> +-- >>>> +2.40.0 >>>> + >>>> diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb >>>> index 84e3360a3a..78d86ad879 100644 >>>> --- a/meta/recipes-core/ovmf/ovmf_git.bb >>>> +++ b/meta/recipes-core/ovmf/ovmf_git.bb >>>> @@ -27,6 +27,9 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ >>>> file://0006-reproducible.patch \ >>>> file://0001-BaseTools-fix-gcc12-warning.patch \ >>>> file://0001-BaseTools-fix-gcc12-warning-1.patch \ >>>> +file://CVE-2022-36763-0001.patch \ >>>> +file://CVE-2022-36763-0002.patch \ >>>> +file://CVE-2022-36763-0003.patch \ >>>> " >>>> >>>> PV = "edk2-stable202202" >>>> -- >>>> 2.25.1 >>>> >> -=-=-=-=-=-=-=-=-=-=-=- >> Links: You receive all messages sent to this group. >> View/Reply Online (#208147):https://lists.openembedded.org/g/openembedded-core/message/208147 >> Mute This Topic:https://lists.openembedded.org/mt/109784095/3620601 >> Group Owner:openembedded-core+owner@lists.openembedded.org >> Unsubscribe:https://lists.openembedded.org/g/openembedded-core/unsub [steve@sakoman.com] >> -=-=-=-=-=-=-=-=-=-=-=- >>
diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch new file mode 100644 index 0000000000..93cefe7740 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch @@ -0,0 +1,985 @@ +From 224446543206450ddb5830e6abd026d61d3c7f4b Mon Sep 17 00:00:00 2001 +From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com> +Date: Fri, 12 Jan 2024 02:16:01 +0800 +Subject: [PATCH] SecurityPkg: DxeTpm2MeasureBootLib: SECURITY PATCH 4117 - CVE + 2022-36763 + +This commit contains the patch files and tests for DxeTpm2MeasureBootLib +CVE 2022-36763. + +Cc: Jiewen Yao <jiewen.yao@intel.com> + +Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> + +CVE: CVE-2022-36763 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/224446543206450ddb5830e6abd026d61d3c7f4b] + +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> +--- + .../DxeTpm2MeasureBootLib.c | 69 ++-- + .../DxeTpm2MeasureBootLib.inf | 4 +- + .../DxeTpm2MeasureBootLibSanitization.c | 275 ++++++++++++++++ + .../DxeTpm2MeasureBootLibSanitization.h | 113 +++++++ + .../DxeTpm2MeasureBootLibSanitizationTest.c | 303 ++++++++++++++++++ + ...Tpm2MeasureBootLibSanitizationTestHost.inf | 28 ++ + SecurityPkg/SecurityPkg.ci.yaml | 1 + + 7 files changed, 763 insertions(+), 30 deletions(-) + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf + +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c +index 36a256a7af..0475103d6e 100644 +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c +@@ -20,6 +20,8 @@ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> + (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + ++Copyright (c) Microsoft Corporation.<BR> ++SPDX-License-Identifier: BSD-2-Clause-Patent + **/ + + #include <PiDxe.h> +@@ -44,6 +46,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + #include <Library/HobLib.h> + #include <Protocol/CcMeasurement.h> + ++#include "DxeTpm2MeasureBootLibSanitization.h" ++ + typedef struct { + EFI_TCG2_PROTOCOL *Tcg2Protocol; + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol; +@@ -144,10 +148,11 @@ Tcg2MeasureGptTable ( + EFI_TCG2_EVENT *Tcg2Event; + EFI_CC_EVENT *CcEvent; + EFI_GPT_DATA *GptData; +- UINT32 EventSize; ++ UINT32 TcgEventSize; + EFI_TCG2_PROTOCOL *Tcg2Protocol; + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol; + EFI_CC_MR_INDEX MrIndex; ++ UINT32 AllocSize; + + if (mTcg2MeasureGptCount > 0) { + return EFI_SUCCESS; +@@ -195,25 +200,22 @@ Tcg2MeasureGptTable ( + BlockIo->Media->BlockSize, + (UINT8 *)PrimaryHeader + ); +- if (EFI_ERROR (Status)) { +- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n")); ++ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) { ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n")); + FreePool (PrimaryHeader); + return EFI_DEVICE_ERROR; + } + + // +- // PrimaryHeader->SizeOfPartitionEntry should not be zero ++ // Read the partition entry. + // +- if (PrimaryHeader->SizeOfPartitionEntry == 0) { +- DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry should not be zero!\n")); ++ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize); ++ if (EFI_ERROR (Status)) { + FreePool (PrimaryHeader); + return EFI_BAD_BUFFER_SIZE; + } + +- // +- // Read the partition entry. +- // +- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry); ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize); + if (EntryPtr == NULL) { + FreePool (PrimaryHeader); + return EFI_OUT_OF_RESOURCES; +@@ -223,7 +225,7 @@ Tcg2MeasureGptTable ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), +- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry, ++ AllocSize, + EntryPtr + ); + if (EFI_ERROR (Status)) { +@@ -248,16 +250,21 @@ Tcg2MeasureGptTable ( + // + // Prepare Data for Measurement (CcProtocol and Tcg2Protocol) + // +- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) +- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry); +- EventPtr = (UINT8 *)AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)); ++ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &TcgEventSize); ++ if (EFI_ERROR (Status)) { ++ FreePool (PrimaryHeader); ++ FreePool (EntryPtr); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ EventPtr = (UINT8 *)AllocateZeroPool (TcgEventSize); + if (EventPtr == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + Tcg2Event = (EFI_TCG2_EVENT *)EventPtr; +- Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event); ++ Tcg2Event->Size = TcgEventSize; + Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER); + Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; + Tcg2Event->Header.PCRIndex = 5; +@@ -310,7 +317,7 @@ Tcg2MeasureGptTable ( + CcProtocol, + 0, + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData, +- (UINT64)EventSize, ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), + CcEvent + ); + if (!EFI_ERROR (Status)) { +@@ -326,7 +333,7 @@ Tcg2MeasureGptTable ( + Tcg2Protocol, + 0, + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData, +- (UINT64)EventSize, ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), + Tcg2Event + ); + if (!EFI_ERROR (Status)) { +@@ -443,11 +450,13 @@ Tcg2MeasurePeImage ( + Tcg2Event->Header.PCRIndex = 2; + break; + default: +- DEBUG (( +- DEBUG_ERROR, +- "Tcg2MeasurePeImage: Unknown subsystem type %d", +- ImageType +- )); ++ DEBUG ( ++ ( ++ DEBUG_ERROR, ++ "Tcg2MeasurePeImage: Unknown subsystem type %d", ++ ImageType ++ ) ++ ); + goto Finish; + } + +@@ -515,7 +524,7 @@ Finish: + + @param MeasureBootProtocols Pointer to the located measure boot protocol instances. + +- @retval EFI_SUCCESS Sucessfully locate the measure boot protocol instances (at least one instance). ++ @retval EFI_SUCCESS Successfully locate the measure boot protocol instances (at least one instance). + @retval EFI_UNSUPPORTED Measure boot is not supported. + **/ + EFI_STATUS +@@ -646,12 +655,14 @@ DxeTpm2MeasureBootHandler ( + return EFI_SUCCESS; + } + +- DEBUG (( +- DEBUG_INFO, +- "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n", +- MeasureBootProtocols.Tcg2Protocol, +- MeasureBootProtocols.CcProtocol +- )); ++ DEBUG ( ++ ( ++ DEBUG_INFO, ++ "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n", ++ MeasureBootProtocols.Tcg2Protocol, ++ MeasureBootProtocols.CcProtocol ++ ) ++ ); + + // + // Copy File Device Path +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf +index 6dca79a20c..28995f438d 100644 +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf +@@ -37,6 +37,8 @@ + + [Sources] + DxeTpm2MeasureBootLib.c ++ DxeTpm2MeasureBootLibSanitization.c ++ DxeTpm2MeasureBootLibSanitization.h + + [Packages] + MdePkg/MdePkg.dec +@@ -46,6 +48,7 @@ + + [LibraryClasses] + BaseMemoryLib ++ SafeIntLib + DebugLib + MemoryAllocationLib + DevicePathLib +@@ -65,4 +68,3 @@ + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES +- +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c +new file mode 100644 +index 0000000000..e2309655d3 +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c +@@ -0,0 +1,275 @@ ++/** @file ++ The library instance provides security service of TPM2 measure boot and ++ Confidential Computing (CC) 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. ++ ++ This file will pull out the validation logic from the following functions, in an ++ attempt to validate the untrusted input in the form of unit tests ++ ++ These are those functions: ++ ++ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content ++ read is within the image buffer. ++ ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse ++ partition data carefully. ++ ++ Copyright (c) Microsoft Corporation.<BR> ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++#include <Uefi.h> ++#include <Uefi/UefiSpec.h> ++#include <Library/SafeIntLib.h> ++#include <Library/UefiLib.h> ++#include <Library/DebugLib.h> ++#include <Library/BaseLib.h> ++#include <IndustryStandard/UefiTcgPlatform.h> ++#include <Protocol/BlockIo.h> ++#include <Library/MemoryAllocationLib.h> ++ ++#include "DxeTpm2MeasureBootLibSanitization.h" ++ ++#define GPT_HEADER_REVISION_V1 0x00010000 ++ ++/** ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse ++ However this function will not attempt to verify the validity of the GPT partition ++ It will check the following: ++ - Signature ++ - Revision ++ - AlternateLBA ++ - FirstUsableLBA ++ - LastUsableLBA ++ - PartitionEntryLBA ++ - NumberOfPartitionEntries ++ - SizeOfPartitionEntry ++ - BlockIo ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[in] BlockIo ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. ++ ++ @retval EFI_SUCCESS ++ The EFI_PARTITION_TABLE_HEADER structure is valid. ++ ++ @retval EFI_INVALID_PARAMETER ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizeEfiPartitionTableHeader ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo ++ ) ++{ ++ // ++ // Verify that the input parameters are safe to use ++ // ++ if (PrimaryHeader == NULL) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) { ++ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n")); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII) ++ // ++ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // The version must be GPT_HEADER_REVISION_V1 (0x00010000) ++ // ++ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size ++ // ++ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // The partition entries should all be before the first usable block ++ // ++ if (PrimaryHeader->FirstUsableLBA <= PrimaryHeader->PartitionEntryLBA) { ++ DEBUG ((DEBUG_ERROR, "GPT PartitionEntryLBA is not less than FirstUsableLBA!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // Check that the PartitionEntryLBA greater than the Max LBA ++ // This will be used later for multiplication ++ // ++ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // Check that the number of partition entries is greater than zero ++ // ++ if (PrimaryHeader->NumberOfPartitionEntries == 0) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory ++ // ++ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) { ++ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // This check is to prevent overflow when calculating the allocation size for the partition entries ++ // This check will be used later for multiplication ++ // ++ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ This function will validate that the allocation size from the primary header is sane ++ It will check the following: ++ - AllocationSize does not overflow ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[out] AllocationSize ++ Pointer to the allocation size. ++ ++ @retval EFI_SUCCESS ++ The allocation size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ The allocation size is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizePrimaryHeaderAllocationSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ OUT UINT32 *AllocationSize ++ ) ++{ ++ EFI_STATUS Status; ++ ++ if (PrimaryHeader == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (AllocationSize == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // Replacing logic: ++ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry; ++ // ++ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ This function will validate that the Gpt Event Size calculated from the primary header is sane ++ It will check the following: ++ - EventSize does not overflow ++ ++ Important: This function includes the entire length of the allocated space, including ++ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this ++ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) ++ from the size of the buffer before hashing. ++ ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ @param[in] NumberOfPartition - Number of partitions. ++ @param[out] EventSize - Pointer to the event size. ++ ++ @retval EFI_SUCCESS ++ The event size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ Overflow would have occurred. ++ ++ @retval EFI_INVALID_PARAMETER ++ One of the passed parameters was invalid. ++**/ ++EFI_STATUS ++SanitizePrimaryHeaderGptEventSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN UINTN NumberOfPartition, ++ OUT UINT32 *EventSize ++ ) ++{ ++ EFI_STATUS Status; ++ UINT32 SafeNumberOfPartitions; ++ ++ if (PrimaryHeader == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (EventSize == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32 ++ // ++ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n")); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // Replacing logic: ++ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry); ++ // ++ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ // ++ // Replacing logic: ++ // *EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event); ++ // ++ Status = SafeUint32Add ( ++ OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions), ++ *EventSize, ++ EventSize ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ return EFI_SUCCESS; ++} +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h +new file mode 100644 +index 0000000000..048b738987 +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h +@@ -0,0 +1,113 @@ ++/** @file ++ This file includes the function prototypes for the sanitization functions. ++ ++ These are those functions: ++ ++ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content ++ read is within the image buffer. ++ ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse ++ partition data carefully. ++ ++ Copyright (c) Microsoft Corporation.<BR> ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#ifndef DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ ++#define DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ ++ ++#include <Uefi.h> ++#include <Uefi/UefiSpec.h> ++#include <Protocol/BlockIo.h> ++#include <IndustryStandard/UefiTcgPlatform.h> ++#include <Protocol/Tcg2Protocol.h> ++ ++/** ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse ++ However this function will not attempt to verify the validity of the GPT partition ++ It will check the following: ++ - Signature ++ - Revision ++ - AlternateLBA ++ - FirstUsableLBA ++ - LastUsableLBA ++ - PartitionEntryLBA ++ - NumberOfPartitionEntries ++ - SizeOfPartitionEntry ++ - BlockIo ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[in] BlockIo ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. ++ ++ @retval EFI_SUCCESS ++ The EFI_PARTITION_TABLE_HEADER structure is valid. ++ ++ @retval EFI_INVALID_PARAMETER ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizeEfiPartitionTableHeader ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo ++ ); ++ ++/** ++ This function will validate that the allocation size from the primary header is sane ++ It will check the following: ++ - AllocationSize does not overflow ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[out] AllocationSize ++ Pointer to the allocation size. ++ ++ @retval EFI_SUCCESS ++ The allocation size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ The allocation size is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizePrimaryHeaderAllocationSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ OUT UINT32 *AllocationSize ++ ); ++ ++/** ++ This function will validate that the Gpt Event Size calculated from the primary header is sane ++ It will check the following: ++ - EventSize does not overflow ++ ++ Important: This function includes the entire length of the allocated space, including ++ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this ++ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) ++ from the size of the buffer before hashing. ++ ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ @param[in] NumberOfPartition - Number of partitions. ++ @param[out] EventSize - Pointer to the event size. ++ ++ @retval EFI_SUCCESS ++ The event size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ Overflow would have occurred. ++ ++ @retval EFI_INVALID_PARAMETER ++ One of the passed parameters was invalid. ++**/ ++EFI_STATUS ++SanitizePrimaryHeaderGptEventSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN UINTN NumberOfPartition, ++ OUT UINT32 *EventSize ++ ); ++ ++#endif // DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c +new file mode 100644 +index 0000000000..3eb9763e3c +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c +@@ -0,0 +1,303 @@ ++/** @file ++ This file includes the unit test cases for the DxeTpm2MeasureBootLibSanitizationTest.c. ++ ++ Copyright (c) Microsoft Corporation.<BR> ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++ ++#include <Uefi.h> ++#include <Library/UefiLib.h> ++#include <Library/DebugLib.h> ++#include <Library/UnitTestLib.h> ++#include <Protocol/BlockIo.h> ++#include <Library/MemoryAllocationLib.h> ++#include <Library/BaseMemoryLib.h> ++#include <IndustryStandard/UefiTcgPlatform.h> ++#include <Protocol/Tcg2Protocol.h> ++ ++#include "../DxeTpm2MeasureBootLibSanitization.h" ++ ++#define UNIT_TEST_NAME "DxeTpm2MeasureBootLibSanitizationTest" ++#define UNIT_TEST_VERSION "1.0" ++ ++#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000 ++#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1 ++#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128 ++ ++/** ++ This function tests the SanitizeEfiPartitionTableHeader function. ++ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER ++ structure will not cause undefined or unexpected behavior. ++ ++ In general the TPM should still be able to measure the data, but ++ be the header should be sanitized to prevent any unexpected behavior. ++ ++ @param[in] Context The unit test context. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++**/ ++UNIT_TEST_STATUS ++EFIAPI ++TestSanitizeEfiPartitionTableHeader ( ++ IN UNIT_TEST_CONTEXT Context ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; ++ EFI_BLOCK_IO_PROTOCOL BlockIo; ++ EFI_BLOCK_IO_MEDIA BlockMedia; ++ ++ // Generate EFI_BLOCK_IO_MEDIA test data ++ BlockMedia.MediaId = 1; ++ BlockMedia.RemovableMedia = FALSE; ++ BlockMedia.MediaPresent = TRUE; ++ BlockMedia.LogicalPartition = FALSE; ++ BlockMedia.ReadOnly = FALSE; ++ BlockMedia.WriteCaching = FALSE; ++ BlockMedia.BlockSize = 512; ++ BlockMedia.IoAlign = 1; ++ BlockMedia.LastBlock = 0; ++ ++ // Generate EFI_BLOCK_IO_PROTOCOL test data ++ BlockIo.Revision = 1; ++ BlockIo.Media = &BlockMedia; ++ BlockIo.Reset = NULL; ++ BlockIo.ReadBlocks = NULL; ++ BlockIo.WriteBlocks = NULL; ++ BlockIo.FlushBlocks = NULL; ++ ++ // Geneate EFI_PARTITION_TABLE_HEADER test data ++ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID; ++ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION; ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); ++ PrimaryHeader.MyLBA = 1; ++ PrimaryHeader.AlternateLBA = 2; ++ PrimaryHeader.FirstUsableLBA = 3; ++ PrimaryHeader.LastUsableLBA = 4; ++ PrimaryHeader.PartitionEntryLBA = 5; ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES; ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid ++ ++ // Calculate the CRC32 of the PrimaryHeader ++ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize); ++ ++ // Test that a normal PrimaryHeader passes validation ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_NOT_EFI_ERROR (Status); ++ ++ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR ++ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!"" ++ PrimaryHeader.NumberOfPartitionEntries = 0; ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ ++ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR ++ // Should print "Invalid Partition Table Header Size!" ++ PrimaryHeader.Header.HeaderSize = 0; ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); ++ ++ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR ++ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!" ++ PrimaryHeader.SizeOfPartitionEntry = 1; ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); ++ ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); ++ ++ return UNIT_TEST_PASSED; ++} ++ ++/** ++ This function tests the SanitizePrimaryHeaderAllocationSize function. ++ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER ++ structure will not cause an overflow when calculating the allocation size. ++ ++ @param[in] Context The unit test context. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++**/ ++UNIT_TEST_STATUS ++EFIAPI ++TestSanitizePrimaryHeaderAllocationSize ( ++ IN UNIT_TEST_CONTEXT Context ++ ) ++{ ++ UINT32 AllocationSize; ++ ++ EFI_STATUS Status; ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; ++ ++ // Test that a normal PrimaryHeader passes validation ++ PrimaryHeader.NumberOfPartitionEntries = 5; ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_NOT_EFI_ERROR (Status); ++ ++ // Test that the allocation size is correct compared to the existing logic ++ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry); ++ ++ // Test that an overflow is detected ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; ++ PrimaryHeader.SizeOfPartitionEntry = 5; ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ // Test the inverse ++ PrimaryHeader.NumberOfPartitionEntries = 5; ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ // Test the worst case scenario ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); ++ ++ return UNIT_TEST_PASSED; ++} ++ ++/** ++ This function tests the SanitizePrimaryHeaderGptEventSize function. ++ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure ++ will not cause an overflow when calculating the event size. ++ ++ @param[in] Context The unit test context. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++**/ ++UNIT_TEST_STATUS ++EFIAPI ++TestSanitizePrimaryHeaderGptEventSize ( ++ IN UNIT_TEST_CONTEXT Context ++ ) ++{ ++ UINT32 EventSize; ++ UINT32 ExistingLogicEventSize; ++ EFI_STATUS Status; ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; ++ UINTN NumberOfPartition; ++ EFI_GPT_DATA *GptData; ++ EFI_TCG2_EVENT *Tcg2Event; ++ ++ Tcg2Event = NULL; ++ GptData = NULL; ++ ++ // Test that a normal PrimaryHeader passes validation ++ PrimaryHeader.NumberOfPartitionEntries = 5; ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ ++ // set the number of partitions ++ NumberOfPartition = 13; ++ ++ // that the primary event size is correct ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); ++ UT_ASSERT_NOT_EFI_ERROR (Status); ++ ++ // Calculate the existing logic event size ++ ExistingLogicEventSize = (UINT32)(OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions) ++ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry); ++ ++ // Check that the event size is correct ++ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize); ++ ++ // Tests that the primary event size may not overflow ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ // Test that the size of partition entries may not overflow ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); ++ ++ return UNIT_TEST_PASSED; ++} ++ ++// *--------------------------------------------------------------------* ++// * Unit Test Code Main Function ++// *--------------------------------------------------------------------* ++ ++/** ++ This function acts as the entry point for the unit tests. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++ @retval others The test failed. ++**/ ++EFI_STATUS ++EFIAPI ++UefiTestMain ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ UNIT_TEST_FRAMEWORK_HANDLE Framework; ++ UNIT_TEST_SUITE_HANDLE Tcg2MeasureBootLibValidationTestSuite; ++ ++ Framework = NULL; ++ ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME)); ++ ++ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status)); ++ goto EXIT; ++ } ++ ++ Status = CreateUnitTestSuite (&Tcg2MeasureBootLibValidationTestSuite, Framework, "Tcg2MeasureBootLibValidationTestSuite", "Common.Tcg2MeasureBootLibValidation", NULL, NULL); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for Tcg2MeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME)); ++ Status = EFI_OUT_OF_RESOURCES; ++ goto EXIT; ++ } ++ ++ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.Tcg2MeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL); ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL); ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL); ++ ++ Status = RunAllTestSuites (Framework); ++ ++EXIT: ++ if (Framework != NULL) { ++ FreeUnitTestFramework (Framework); ++ } ++ ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME)); ++ return Status; ++} ++ ++/// ++/// Avoid ECC error for function name that starts with lower case letter ++/// ++#define DxeTpm2MeasureBootLibUnitTestMain main ++ ++/** ++ Standard POSIX C entry point for host based unit test execution. ++ ++ @param[in] Argc Number of arguments ++ @param[in] Argv Array of pointers to arguments ++ ++ @retval 0 Success ++ @retval other Error ++**/ ++INT32 ++DxeTpm2MeasureBootLibUnitTestMain ( ++ IN INT32 Argc, ++ IN CHAR8 *Argv[] ++ ) ++{ ++ return (INT32)UefiTestMain (); ++} +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf +new file mode 100644 +index 0000000000..2999aa2a44 +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf +@@ -0,0 +1,28 @@ ++## @file ++# This file builds the unit tests for DxeTpm2MeasureBootLib ++# ++# Copyright (C) Microsoft Corporation.<BR> ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++## ++ ++[Defines] ++ INF_VERSION = 0x00010006 ++ BASE_NAME = DxeTpm2MeasuredBootLibTest ++ FILE_GUID = 144d757f-d423-484e-9309-a23695fad5bd ++ MODULE_TYPE = HOST_APPLICATION ++ VERSION_STRING = 1.0 ++ ENTRY_POINT = main ++ ++[Sources] ++ DxeTpm2MeasureBootLibSanitizationTest.c ++ ../DxeTpm2MeasureBootLibSanitization.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ BaseLib ++ DebugLib ++ UnitTestLib ++ PrintLib ++ SafeIntLib +diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml +index 7912142398..da811fdf93 100644 +--- a/SecurityPkg/SecurityPkg.ci.yaml ++++ b/SecurityPkg/SecurityPkg.ci.yaml +@@ -15,6 +15,7 @@ + ## "<ErrorID>", "<KeyWord>" + ## ] + "ExceptionList": [ ++ "8001", "DxeTpm2MeasureBootLibUnitTestMain", + ], + ## Both file path and directory path are accepted. + "IgnoreFiles": [ +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch new file mode 100644 index 0000000000..6c20cc305e --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch @@ -0,0 +1,889 @@ +From 4776a1b39ee08fc45c70c1eab5a0195f325000d3 Mon Sep 17 00:00:00 2001 +From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com> +Date: Fri, 12 Jan 2024 02:16:02 +0800 +Subject: [PATCH] SecurityPkg: DxeTpmMeasureBootLib: SECURITY PATCH 4117 - CVE + 2022-36763 + +This commit contains the patch files and tests for DxeTpmMeasureBootLib +CVE 2022-36763. + +Cc: Jiewen Yao <jiewen.yao@intel.com> + +Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> +Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> + +CVE: CVE-2022-36763 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/4776a1b39ee08fc45c70c1eab5a0195f325000d3] + +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> +--- + .../DxeTpmMeasureBootLib.c | 40 ++- + .../DxeTpmMeasureBootLib.inf | 4 +- + .../DxeTpmMeasureBootLibSanitization.c | 241 ++++++++++++++ + .../DxeTpmMeasureBootLibSanitization.h | 114 +++++++ + .../DxeTpmMeasureBootLibSanitizationTest.c | 301 ++++++++++++++++++ + ...eTpmMeasureBootLibSanitizationTestHost.inf | 28 ++ + SecurityPkg/SecurityPkg.ci.yaml | 1 + + 7 files changed, 715 insertions(+), 14 deletions(-) + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf + +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c +index 220393dd2b..669ab19134 100644 +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c +@@ -18,6 +18,8 @@ + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + ++Copyright (c) Microsoft Corporation.<BR> ++SPDX-License-Identifier: BSD-2-Clause-Patent + **/ + + #include <PiDxe.h> +@@ -40,6 +42,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + #include <Library/SecurityManagementLib.h> + #include <Library/HobLib.h> + ++#include "DxeTpmMeasureBootLibSanitization.h" ++ + // + // Flag to check GPT partition. It only need be measured once. + // +@@ -136,6 +140,9 @@ TcgMeasureGptTable ( + UINT32 EventSize; + UINT32 EventNumber; + EFI_PHYSICAL_ADDRESS EventLogLastEntry; ++ UINT32 AllocSize; ++ ++ GptData = NULL; + + if (mMeasureGptCount > 0) { + return EFI_SUCCESS; +@@ -166,8 +173,8 @@ TcgMeasureGptTable ( + BlockIo->Media->BlockSize, + (UINT8 *)PrimaryHeader + ); +- if (EFI_ERROR (Status)) { +- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n")); ++ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) { ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n")); + FreePool (PrimaryHeader); + return EFI_DEVICE_ERROR; + } +@@ -175,7 +182,13 @@ TcgMeasureGptTable ( + // + // Read the partition entry. + // +- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry); ++ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize); ++ if (EFI_ERROR (Status)) { ++ FreePool (PrimaryHeader); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize); + if (EntryPtr == NULL) { + FreePool (PrimaryHeader); + return EFI_OUT_OF_RESOURCES; +@@ -185,7 +198,7 @@ TcgMeasureGptTable ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), +- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry, ++ AllocSize, + EntryPtr + ); + if (EFI_ERROR (Status)) { +@@ -210,9 +223,8 @@ TcgMeasureGptTable ( + // + // Prepare Data for Measurement + // +- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) +- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry); +- TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT_HDR)); ++ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &EventSize); ++ TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize); + if (TcgEvent == NULL) { + FreePool (PrimaryHeader); + FreePool (EntryPtr); +@@ -221,7 +233,7 @@ TcgMeasureGptTable ( + + TcgEvent->PCRIndex = 5; + TcgEvent->EventType = EV_EFI_GPT_EVENT; +- TcgEvent->EventSize = EventSize; ++ TcgEvent->EventSize = EventSize - sizeof (TCG_PCR_EVENT_HDR); + GptData = (EFI_GPT_DATA *)TcgEvent->Event; + + // +@@ -361,11 +373,13 @@ TcgMeasurePeImage ( + TcgEvent->PCRIndex = 2; + break; + default: +- DEBUG (( +- DEBUG_ERROR, +- "TcgMeasurePeImage: Unknown subsystem type %d", +- ImageType +- )); ++ DEBUG ( ++ ( ++ DEBUG_ERROR, ++ "TcgMeasurePeImage: Unknown subsystem type %d", ++ ImageType ++ ) ++ ); + goto Finish; + } + +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf +index ebab6f7c1e..414c654d15 100644 +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf +@@ -32,6 +32,8 @@ + + [Sources] + DxeTpmMeasureBootLib.c ++ DxeTpmMeasureBootLibSanitization.c ++ DxeTpmMeasureBootLibSanitization.h + + [Packages] + MdePkg/MdePkg.dec +@@ -41,6 +43,7 @@ + + [LibraryClasses] + BaseMemoryLib ++ SafeIntLib + DebugLib + MemoryAllocationLib + DevicePathLib +@@ -59,4 +62,3 @@ + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES +- +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c +new file mode 100644 +index 0000000000..a3fa46f5e6 +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c +@@ -0,0 +1,241 @@ ++/** @file ++ The library instance provides security service of TPM2 measure boot and ++ Confidential Computing (CC) 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. ++ ++ This file will pull out the validation logic from the following functions, in an ++ attempt to validate the untrusted input in the form of unit tests ++ ++ These are those functions: ++ ++ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content ++ read is within the image buffer. ++ ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse ++ partition data carefully. ++ ++ Copyright (c) Microsoft Corporation.<BR> ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++#include <Uefi.h> ++#include <Uefi/UefiSpec.h> ++#include <Library/SafeIntLib.h> ++#include <Library/UefiLib.h> ++#include <Library/DebugLib.h> ++#include <Library/BaseLib.h> ++#include <IndustryStandard/UefiTcgPlatform.h> ++#include <Protocol/BlockIo.h> ++#include <Library/MemoryAllocationLib.h> ++ ++#include "DxeTpmMeasureBootLibSanitization.h" ++ ++#define GPT_HEADER_REVISION_V1 0x00010000 ++ ++/** ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse ++ However this function will not attempt to verify the validity of the GPT partition ++ It will check the following: ++ - Signature ++ - Revision ++ - AlternateLBA ++ - FirstUsableLBA ++ - LastUsableLBA ++ - PartitionEntryLBA ++ - NumberOfPartitionEntries ++ - SizeOfPartitionEntry ++ - BlockIo ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[in] BlockIo ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. ++ ++ @retval EFI_SUCCESS ++ The EFI_PARTITION_TABLE_HEADER structure is valid. ++ ++ @retval EFI_INVALID_PARAMETER ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizeEfiPartitionTableHeader ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo ++ ) ++{ ++ // Verify that the input parameters are safe to use ++ if (PrimaryHeader == NULL) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) { ++ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n")); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII) ++ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // The version must be GPT_HEADER_REVISION_V1 (0x00010000) ++ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size ++ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // check that the PartitionEntryLBA greater than the Max LBA ++ // This will be used later for multiplication ++ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // Check that the number of partition entries is greater than zero ++ if (PrimaryHeader->NumberOfPartitionEntries == 0) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory ++ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) { ++ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // This check is to prevent overflow when calculating the allocation size for the partition entries ++ // This check will be used later for multiplication ++ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ This function will validate that the allocation size from the primary header is sane ++ It will check the following: ++ - AllocationSize does not overflow ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[out] AllocationSize ++ Pointer to the allocation size. ++ ++ @retval EFI_SUCCESS ++ The allocation size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ The allocation size is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizePrimaryHeaderAllocationSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ OUT UINT32 *AllocationSize ++ ) ++{ ++ EFI_STATUS Status; ++ ++ if (PrimaryHeader == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (AllocationSize == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // Replacing logic: ++ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry; ++ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ This function will validate that the Gpt Event Size calculated from the primary header is sane ++ It will check the following: ++ - EventSize does not overflow ++ ++ Important: This function includes the entire length of the allocated space, including the ++ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract ++ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing. ++ ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ @param[in] NumberOfPartition - Number of partitions. ++ @param[out] EventSize - Pointer to the event size. ++ ++ @retval EFI_SUCCESS ++ The event size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ Overflow would have occurred. ++ ++ @retval EFI_INVALID_PARAMETER ++ One of the passed parameters was invalid. ++**/ ++EFI_STATUS ++SanitizePrimaryHeaderGptEventSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN UINTN NumberOfPartition, ++ OUT UINT32 *EventSize ++ ) ++{ ++ EFI_STATUS Status; ++ UINT32 SafeNumberOfPartitions; ++ ++ if (PrimaryHeader == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (EventSize == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32 ++ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n")); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // Replacing logic: ++ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry + sizeof (TCG_PCR_EVENT_HDR)); ++ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ Status = SafeUint32Add ( ++ sizeof (TCG_PCR_EVENT_HDR) + ++ OFFSET_OF (EFI_GPT_DATA, Partitions), ++ *EventSize, ++ EventSize ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ return EFI_SUCCESS; ++} +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h +new file mode 100644 +index 0000000000..0d9d00c281 +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h +@@ -0,0 +1,114 @@ ++/** @file ++ This file includes the function prototypes for the sanitization functions. ++ ++ These are those functions: ++ ++ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content ++ read is within the image buffer. ++ ++ TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its ++ data structure within this image buffer before use. ++ ++ TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse ++ partition data carefully. ++ ++ Copyright (c) Microsoft Corporation.<BR> ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#ifndef DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ ++#define DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ ++ ++#include <Uefi.h> ++#include <Uefi/UefiSpec.h> ++#include <Protocol/BlockIo.h> ++#include <IndustryStandard/UefiTcgPlatform.h> ++ ++/** ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse ++ However this function will not attempt to verify the validity of the GPT partition ++ It will check the following: ++ - Signature ++ - Revision ++ - AlternateLBA ++ - FirstUsableLBA ++ - LastUsableLBA ++ - PartitionEntryLBA ++ - NumberOfPartitionEntries ++ - SizeOfPartitionEntry ++ - BlockIo ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[in] BlockIo ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. ++ ++ @retval EFI_SUCCESS ++ The EFI_PARTITION_TABLE_HEADER structure is valid. ++ ++ @retval EFI_INVALID_PARAMETER ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizeEfiPartitionTableHeader ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo ++ ); ++ ++/** ++ This function will validate that the allocation size from the primary header is sane ++ It will check the following: ++ - AllocationSize does not overflow ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[out] AllocationSize ++ Pointer to the allocation size. ++ ++ @retval EFI_SUCCESS ++ The allocation size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ The allocation size is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizePrimaryHeaderAllocationSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ OUT UINT32 *AllocationSize ++ ); ++ ++/** ++ This function will validate that the Gpt Event Size calculated from the primary header is sane ++ It will check the following: ++ - EventSize does not overflow ++ ++ Important: This function includes the entire length of the allocated space, including the ++ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract ++ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing. ++ ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ @param[in] NumberOfPartition - Number of partitions. ++ @param[out] EventSize - Pointer to the event size. ++ ++ @retval EFI_SUCCESS ++ The event size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ Overflow would have occurred. ++ ++ @retval EFI_INVALID_PARAMETER ++ One of the passed parameters was invalid. ++**/ ++EFI_STATUS ++SanitizePrimaryHeaderGptEventSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN UINTN NumberOfPartition, ++ OUT UINT32 *EventSize ++ ); ++ ++#endif // DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c +new file mode 100644 +index 0000000000..eeb928cdb0 +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c +@@ -0,0 +1,301 @@ ++/** @file ++This file includes the unit test cases for the DxeTpmMeasureBootLibSanitizationTest.c. ++ ++Copyright (c) Microsoft Corporation.<BR> ++SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++ ++#include <Uefi.h> ++#include <Library/UefiLib.h> ++#include <Library/DebugLib.h> ++#include <Library/UnitTestLib.h> ++#include <Protocol/BlockIo.h> ++#include <Library/MemoryAllocationLib.h> ++#include <Library/BaseMemoryLib.h> ++#include <IndustryStandard/UefiTcgPlatform.h> ++ ++#include "../DxeTpmMeasureBootLibSanitization.h" ++ ++#define UNIT_TEST_NAME "DxeTpmMeasureBootLibSanitizationTest" ++#define UNIT_TEST_VERSION "1.0" ++ ++#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000 ++#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1 ++#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128 ++ ++/** ++ This function tests the SanitizeEfiPartitionTableHeader function. ++ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER ++ structure will not cause undefined or unexpected behavior. ++ ++ In general the TPM should still be able to measure the data, but ++ be the header should be sanitized to prevent any unexpected behavior. ++ ++ @param[in] Context The unit test context. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++**/ ++UNIT_TEST_STATUS ++EFIAPI ++TestSanitizeEfiPartitionTableHeader ( ++ IN UNIT_TEST_CONTEXT Context ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; ++ EFI_BLOCK_IO_PROTOCOL BlockIo; ++ EFI_BLOCK_IO_MEDIA BlockMedia; ++ ++ // Generate EFI_BLOCK_IO_MEDIA test data ++ BlockMedia.MediaId = 1; ++ BlockMedia.RemovableMedia = FALSE; ++ BlockMedia.MediaPresent = TRUE; ++ BlockMedia.LogicalPartition = FALSE; ++ BlockMedia.ReadOnly = FALSE; ++ BlockMedia.WriteCaching = FALSE; ++ BlockMedia.BlockSize = 512; ++ BlockMedia.IoAlign = 1; ++ BlockMedia.LastBlock = 0; ++ ++ // Generate EFI_BLOCK_IO_PROTOCOL test data ++ BlockIo.Revision = 1; ++ BlockIo.Media = &BlockMedia; ++ BlockIo.Reset = NULL; ++ BlockIo.ReadBlocks = NULL; ++ BlockIo.WriteBlocks = NULL; ++ BlockIo.FlushBlocks = NULL; ++ ++ // Geneate EFI_PARTITION_TABLE_HEADER test data ++ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID; ++ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION; ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); ++ PrimaryHeader.MyLBA = 1; ++ PrimaryHeader.AlternateLBA = 2; ++ PrimaryHeader.FirstUsableLBA = 3; ++ PrimaryHeader.LastUsableLBA = 4; ++ PrimaryHeader.PartitionEntryLBA = 5; ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES; ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid ++ ++ // Calculate the CRC32 of the PrimaryHeader ++ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize); ++ ++ // Test that a normal PrimaryHeader passes validation ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_NOT_EFI_ERROR (Status); ++ ++ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR ++ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!"" ++ PrimaryHeader.NumberOfPartitionEntries = 0; ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ ++ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR ++ // Should print "Invalid Partition Table Header Size!" ++ PrimaryHeader.Header.HeaderSize = 0; ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); ++ ++ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR ++ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!" ++ PrimaryHeader.SizeOfPartitionEntry = 1; ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); ++ ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); ++ ++ return UNIT_TEST_PASSED; ++} ++ ++/** ++ This function tests the SanitizePrimaryHeaderAllocationSize function. ++ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER ++ structure will not cause an overflow when calculating the allocation size. ++ ++ @param[in] Context The unit test context. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++**/ ++UNIT_TEST_STATUS ++EFIAPI ++TestSanitizePrimaryHeaderAllocationSize ( ++ IN UNIT_TEST_CONTEXT Context ++ ) ++{ ++ UINT32 AllocationSize; ++ ++ EFI_STATUS Status; ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; ++ ++ // Test that a normal PrimaryHeader passes validation ++ PrimaryHeader.NumberOfPartitionEntries = 5; ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_NOT_EFI_ERROR (Status); ++ ++ // Test that the allocation size is correct compared to the existing logic ++ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry); ++ ++ // Test that an overflow is detected ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; ++ PrimaryHeader.SizeOfPartitionEntry = 5; ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ // Test the inverse ++ PrimaryHeader.NumberOfPartitionEntries = 5; ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ // Test the worst case scenario ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); ++ ++ return UNIT_TEST_PASSED; ++} ++ ++/** ++ This function tests the SanitizePrimaryHeaderGptEventSize function. ++ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure ++ will not cause an overflow when calculating the event size. ++ ++ @param[in] Context The unit test context. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++**/ ++UNIT_TEST_STATUS ++EFIAPI ++TestSanitizePrimaryHeaderGptEventSize ( ++ IN UNIT_TEST_CONTEXT Context ++ ) ++{ ++ UINT32 EventSize; ++ UINT32 ExistingLogicEventSize; ++ EFI_STATUS Status; ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; ++ UINTN NumberOfPartition; ++ EFI_GPT_DATA *GptData; ++ ++ GptData = NULL; ++ ++ // Test that a normal PrimaryHeader passes validation ++ PrimaryHeader.NumberOfPartitionEntries = 5; ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ ++ // set the number of partitions ++ NumberOfPartition = 13; ++ ++ // that the primary event size is correct ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); ++ UT_ASSERT_NOT_EFI_ERROR (Status); ++ ++ // Calculate the existing logic event size ++ ExistingLogicEventSize = (UINT32)(sizeof (TCG_PCR_EVENT_HDR) + OFFSET_OF (EFI_GPT_DATA, Partitions) ++ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry); ++ ++ // Check that the event size is correct ++ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize); ++ ++ // Tests that the primary event size may not overflow ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ // Test that the size of partition entries may not overflow ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); ++ ++ return UNIT_TEST_PASSED; ++} ++ ++// *--------------------------------------------------------------------* ++// * Unit Test Code Main Function ++// *--------------------------------------------------------------------* ++ ++/** ++ This function acts as the entry point for the unit tests. ++ ++ @param argc - The number of command line arguments ++ @param argv - The command line arguments ++ ++ @return int - The status of the test ++**/ ++EFI_STATUS ++EFIAPI ++UefiTestMain ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ UNIT_TEST_FRAMEWORK_HANDLE Framework; ++ UNIT_TEST_SUITE_HANDLE TcgMeasureBootLibValidationTestSuite; ++ ++ Framework = NULL; ++ ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME)); ++ ++ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status)); ++ goto EXIT; ++ } ++ ++ Status = CreateUnitTestSuite (&TcgMeasureBootLibValidationTestSuite, Framework, "TcgMeasureBootLibValidationTestSuite", "Common.TcgMeasureBootLibValidation", NULL, NULL); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for TcgMeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME)); ++ Status = EFI_OUT_OF_RESOURCES; ++ goto EXIT; ++ } ++ ++ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.TcgMeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL); ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL); ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL); ++ ++ Status = RunAllTestSuites (Framework); ++ ++EXIT: ++ if (Framework != NULL) { ++ FreeUnitTestFramework (Framework); ++ } ++ ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME)); ++ return Status; ++} ++ ++/// ++/// Avoid ECC error for function name that starts with lower case letter ++/// ++#define DxeTpmMeasureBootLibUnitTestMain main ++ ++/** ++ Standard POSIX C entry point for host based unit test execution. ++ ++ @param[in] Argc Number of arguments ++ @param[in] Argv Array of pointers to arguments ++ ++ @retval 0 Success ++ @retval other Error ++**/ ++INT32 ++DxeTpmMeasureBootLibUnitTestMain ( ++ IN INT32 Argc, ++ IN CHAR8 *Argv[] ++ ) ++{ ++ return (INT32)UefiTestMain (); ++} +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf +new file mode 100644 +index 0000000000..47b0811b00 +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf +@@ -0,0 +1,28 @@ ++## @file ++# This file builds the unit tests for DxeTpmMeasureBootLib ++# ++# Copyright (C) Microsoft Corporation.<BR> ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++## ++ ++[Defines] ++ INF_VERSION = 0x00010006 ++ BASE_NAME = DxeTpmMeasuredBootLibTest ++ FILE_GUID = eb01bc38-309c-4d3e-967e-9f078c90772f ++ MODULE_TYPE = HOST_APPLICATION ++ VERSION_STRING = 1.0 ++ ENTRY_POINT = main ++ ++[Sources] ++ DxeTpmMeasureBootLibSanitizationTest.c ++ ../DxeTpmMeasureBootLibSanitization.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ BaseLib ++ DebugLib ++ UnitTestLib ++ PrintLib ++ SafeIntLib +diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml +index da811fdf93..0e40eaa0fe 100644 +--- a/SecurityPkg/SecurityPkg.ci.yaml ++++ b/SecurityPkg/SecurityPkg.ci.yaml +@@ -16,6 +16,7 @@ + ## ] + "ExceptionList": [ + "8001", "DxeTpm2MeasureBootLibUnitTestMain", ++ "8001", "DxeTpmMeasureBootLibUnitTestMain" + ], + ## Both file path and directory path are accepted. + "IgnoreFiles": [ +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch new file mode 100644 index 0000000000..59bd5c4910 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch @@ -0,0 +1,55 @@ +From 1ddcb9fc6b4164e882687b031e8beacfcf7df29e Mon Sep 17 00:00:00 2001 +From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com> +Date: Fri, 12 Jan 2024 02:16:03 +0800 +Subject: [PATCH] SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml + +This creates / adds a security file that tracks the security fixes +found in this package and can be used to find the fixes that were +applied. + +Cc: Jiewen Yao <jiewen.yao@intel.com> + +Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> +Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> + +CVE: CVE-2022-36763 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1ddcb9fc6b4164e882687b031e8beacfcf7df29e] + +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> +--- + SecurityPkg/SecurityFixes.yaml | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + create mode 100644 SecurityPkg/SecurityFixes.yaml + +diff --git a/SecurityPkg/SecurityFixes.yaml b/SecurityPkg/SecurityFixes.yaml +new file mode 100644 +index 0000000000..f9e3e7be74 +--- /dev/null ++++ b/SecurityPkg/SecurityFixes.yaml +@@ -0,0 +1,22 @@ ++## @file ++# Security Fixes for SecurityPkg ++# ++# Copyright (c) Microsoft Corporation ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++## ++CVE_2022_36763: ++ commit_titles: ++ - "SecurityPkg: DxeTpm2Measurement: SECURITY PATCH 4117 - CVE 2022-36763" ++ - "SecurityPkg: DxeTpmMeasurement: SECURITY PATCH 4117 - CVE 2022-36763" ++ - "SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml" ++ cve: CVE-2022-36763 ++ date_reported: 2022-10-25 11:31 UTC ++ description: (CVE-2022-36763) - Heap Buffer Overflow in Tcg2MeasureGptTable() ++ note: This patch is related to and supersedes TCBZ2168 ++ files_impacted: ++ - Library\DxeTpm2MeasureBootLib\DxeTpm2MeasureBootLib.c ++ - Library\DxeTpmMeasureBootLib\DxeTpmMeasureBootLib.c ++ links: ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4117 ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=2168 ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=1990 +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb index 84e3360a3a..78d86ad879 100644 --- a/meta/recipes-core/ovmf/ovmf_git.bb +++ b/meta/recipes-core/ovmf/ovmf_git.bb @@ -27,6 +27,9 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ file://0006-reproducible.patch \ file://0001-BaseTools-fix-gcc12-warning.patch \ file://0001-BaseTools-fix-gcc12-warning-1.patch \ + file://CVE-2022-36763-0001.patch \ + file://CVE-2022-36763-0002.patch \ + file://CVE-2022-36763-0003.patch \ " PV = "edk2-stable202202"