Skip to content

Heap Buffer Overflow in Tcg2MeasurePeImage()

High
jkmathews published GHSA-4hcq-p8q8-hj8j Jan 9, 2024

Package

SecurityPkg (EDK2)

Affected versions

<=202311

Patched versions

None

Description

Summary

An integer overflow can happen when calculating the EventSize variable at line 420 at SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c, which leads to a heap-buffer overflow shortly after at line 459.

This vulnerability was originally reported at https://bugzilla.tianocore.org/show_bug.cgi?id=4118.

Details

The Tcg2MeasurePeImage() function, which as stated in code comments receives untrusted input, calls to GetDevicePathSize() to get the size (uint32) of the “FilePath”:

FilePathSize = (UINT32)GetDevicePathSize (FilePath);

This size is later used for computing the EventSize which is then used for performing an allocation:

EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize;
EventPtr  = AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT)
                 - sizeof (Tcg2Event->Event));
 if (EventPtr == NULL) {
   return EFI_OUT_OF_RESOURCES;
 }
// (...)

Between the call to GetDevicePathSize() and the allocation no checks are performed on EventSize, which means that the allocation size can overflow, and AllocateZeroPool() can return a very small allocation for a very big FilePathSize.

Later on the code FilePathSize is used again for copying memory into the allocated buffer, also without further checks on FilePathSize:

CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize);

This means, the responsibility for checking that the EventSize variable doesn’t overflow when FilePathSize is added, is on the GetDevicePathSize() function.

GetDevicePathSize() calls IsDevicePathValid() which does the following:

  • Sets the MaxSize variable (max value we can return) to MAX_UINTN.
  • In a loop we sum up the size of the nodes and check that we don’t exceed the limit, which is not a problem because the limit is high enough. Also, even if the limit was MAX_UINT32 we could still exploit this, because we don’t have to exceed MaxSize - END_DEVICE_PATH_LENGTH (4), and in Tcg2MeasurePeImage() we calculate EventSize by doing: sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize which is 0x24 - 4 + FilePathSize, so GetDevicePathSize() could return up to 0xfffffffb which is more than enough for overflowing.
  • Finally, near the end of the loop it checks that we don’t exceed the maximum amount of nodes by checking the PcdMaximumDevicePathNodeCount PCD, and in case is set to zero it skips this check.

So the return value from GetDevicePathSize() should be checked to ensure that it will not overflow when calculating the size for the allocation.

Impact

An attacker could use this heap-buffer overflow to achieve arbitrary code execution in the DXE phase in a number of ways:

  1. Corrupting PREV-NEXT pointers of an object in the heap to setup an unlink() attack. By default all memory is RWX, so this primitive could be very powerful as could allow an attacker to overwrite code from UEFI applications, or pointers from the BootServices table.
  2. Using the heap-buffer overflow itself to overwrite UEFI application code.

Mitigation release plan

Patch files are available now via https://bugzilla.tianocore.org/show_bug.cgi?id=4118. Patch will be integrated for the Feb 2024 EDK2 release.

Severity

High
7.0
/ 10

CVSS base metrics

Attack vector
Local
Attack complexity
High
Privileges required
Low
User interaction
None
Scope
Changed
Confidentiality
Low
Integrity
Low
Availability
High
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:H

CVE ID

CVE-2022-36764

Weaknesses

Credits