SecurityPkg: DxeTpm2MeasureBootLib: SECURITY PATCH 4118 - CVE 2022-36764

This commit contains the patch files and tests for DxeTpm2MeasureBootLib
CVE 2022-36764.

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>
This commit is contained in:
Douglas Flick [MSFT] 2024-01-12 02:16:04 +08:00 committed by mergify[bot]
parent 1ddcb9fc6b
commit c7b2794421
4 changed files with 131 additions and 15 deletions

View File

@ -378,7 +378,6 @@ Exit:
@retval EFI_OUT_OF_RESOURCES No enough resource to measure image. @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.
@retval EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format. @retval EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format.
@retval other error value @retval other error value
**/ **/
EFI_STATUS EFI_STATUS
EFIAPI EFIAPI
@ -405,6 +404,7 @@ Tcg2MeasurePeImage (
Status = EFI_UNSUPPORTED; Status = EFI_UNSUPPORTED;
ImageLoad = NULL; ImageLoad = NULL;
EventPtr = NULL; EventPtr = NULL;
Tcg2Event = NULL;
Tcg2Protocol = MeasureBootProtocols->Tcg2Protocol; Tcg2Protocol = MeasureBootProtocols->Tcg2Protocol;
CcProtocol = MeasureBootProtocols->CcProtocol; CcProtocol = MeasureBootProtocols->CcProtocol;
@ -420,18 +420,22 @@ Tcg2MeasurePeImage (
} }
FilePathSize = (UINT32)GetDevicePathSize (FilePath); FilePathSize = (UINT32)GetDevicePathSize (FilePath);
Status = SanitizePeImageEventSize (FilePathSize, &EventSize);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
// //
// Determine destination PCR by BootPolicy // Determine destination PCR by BootPolicy
// //
EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize; // from a malicious GPT disk partition
EventPtr = AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)); EventPtr = AllocateZeroPool (EventSize);
if (EventPtr == NULL) { if (EventPtr == NULL) {
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
} }
Tcg2Event = (EFI_TCG2_EVENT *)EventPtr; Tcg2Event = (EFI_TCG2_EVENT *)EventPtr;
Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event); Tcg2Event->Size = EventSize;
Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER); Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER);
Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;
ImageLoad = (EFI_IMAGE_LOAD_EVENT *)Tcg2Event->Event; ImageLoad = (EFI_IMAGE_LOAD_EVENT *)Tcg2Event->Event;

View File

@ -151,7 +151,7 @@ SanitizeEfiPartitionTableHeader (
} }
/** /**
This function will validate that the allocation size from the primary header is sane This function will validate that the allocation size from the primary header is sane
It will check the following: It will check the following:
- AllocationSize does not overflow - AllocationSize does not overflow
@ -273,3 +273,47 @@ SanitizePrimaryHeaderGptEventSize (
return EFI_SUCCESS; return EFI_SUCCESS;
} }
/**
This function will validate that the PeImage Event Size from the loaded image is sane
It will check the following:
- EventSize does not overflow
@param[in] FilePathSize - Size of the file path.
@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
SanitizePeImageEventSize (
IN UINT32 FilePathSize,
OUT UINT32 *EventSize
)
{
EFI_STATUS Status;
// Replacing logic:
// sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize;
Status = SafeUint32Add (OFFSET_OF (EFI_IMAGE_LOAD_EVENT, DevicePath), FilePathSize, EventSize);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "EventSize would overflow!\n"));
return EFI_BAD_BUFFER_SIZE;
}
// Replacing logic:
// EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)
Status = SafeUint32Add (*EventSize, OFFSET_OF (EFI_TCG2_EVENT, Event), EventSize);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "EventSize would overflow!\n"));
return EFI_BAD_BUFFER_SIZE;
}
return EFI_SUCCESS;
}

View File

@ -9,6 +9,9 @@
Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse
partition data carefully. partition data carefully.
Tcg2MeasurePeImage() function will accept untrusted PE/COFF image and validate its
data structure within this image buffer before use.
Copyright (c) Microsoft Corporation.<BR> Copyright (c) Microsoft Corporation.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent SPDX-License-Identifier: BSD-2-Clause-Patent
@ -110,4 +113,27 @@ SanitizePrimaryHeaderGptEventSize (
OUT UINT32 *EventSize OUT UINT32 *EventSize
); );
#endif // DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ /**
This function will validate that the PeImage Event Size from the loaded image is sane
It will check the following:
- EventSize does not overflow
@param[in] FilePathSize - Size of the file path.
@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
SanitizePeImageEventSize (
IN UINT32 FilePathSize,
OUT UINT32 *EventSize
);
#endif // DXE_TPM2_MEASURE_BOOT_LIB_VALIDATION_

View File

@ -72,10 +72,10 @@ TestSanitizeEfiPartitionTableHeader (
PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION; PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION;
PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER);
PrimaryHeader.MyLBA = 1; PrimaryHeader.MyLBA = 1;
PrimaryHeader.AlternateLBA = 2; PrimaryHeader.PartitionEntryLBA = 2;
PrimaryHeader.FirstUsableLBA = 3; PrimaryHeader.AlternateLBA = 3;
PrimaryHeader.LastUsableLBA = 4; PrimaryHeader.FirstUsableLBA = 4;
PrimaryHeader.PartitionEntryLBA = 5; PrimaryHeader.LastUsableLBA = 5;
PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES; PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES;
PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid
@ -187,11 +187,6 @@ TestSanitizePrimaryHeaderGptEventSize (
EFI_STATUS Status; EFI_STATUS Status;
EFI_PARTITION_TABLE_HEADER PrimaryHeader; EFI_PARTITION_TABLE_HEADER PrimaryHeader;
UINTN NumberOfPartition; UINTN NumberOfPartition;
EFI_GPT_DATA *GptData;
EFI_TCG2_EVENT *Tcg2Event;
Tcg2Event = NULL;
GptData = NULL;
// Test that a normal PrimaryHeader passes validation // Test that a normal PrimaryHeader passes validation
PrimaryHeader.NumberOfPartitionEntries = 5; PrimaryHeader.NumberOfPartitionEntries = 5;
@ -225,6 +220,52 @@ TestSanitizePrimaryHeaderGptEventSize (
return UNIT_TEST_PASSED; return UNIT_TEST_PASSED;
} }
/**
This function tests the SanitizePeImageEventSize function.
It's intent is to test that the untrusted input from a file path when generating a
EFI_IMAGE_LOAD_EVENT structure will not cause an overflow when calculating
the event size when allocating space
@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
TestSanitizePeImageEventSize (
IN UNIT_TEST_CONTEXT Context
)
{
UINT32 EventSize;
UINTN ExistingLogicEventSize;
UINT32 FilePathSize;
EFI_STATUS Status;
FilePathSize = 255;
// Test that a normal PE image passes validation
Status = SanitizePeImageEventSize (FilePathSize, &EventSize);
UT_ASSERT_EQUAL (Status, EFI_SUCCESS);
// Test that the event size is correct compared to the existing logic
ExistingLogicEventSize = OFFSET_OF (EFI_IMAGE_LOAD_EVENT, DevicePath) + FilePathSize;
ExistingLogicEventSize += OFFSET_OF (EFI_TCG2_EVENT, Event);
if (EventSize != ExistingLogicEventSize) {
UT_LOG_ERROR ("SanitizePeImageEventSize returned an incorrect event size. Expected %u, got %u\n", ExistingLogicEventSize, EventSize);
return UNIT_TEST_ERROR_TEST_FAILED;
}
// Test that the event size may not overflow
Status = SanitizePeImageEventSize (MAX_UINT32, &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 // * Unit Test Code Main Function
// *--------------------------------------------------------------------* // *--------------------------------------------------------------------*
@ -267,6 +308,7 @@ UefiTestMain (
AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.Tcg2MeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL); 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 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); AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL);
AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests PE Image and FileSize checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePeImageEventSize, NULL, NULL, NULL);
Status = RunAllTestSuites (Framework); Status = RunAllTestSuites (Framework);