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:
- 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.
- 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.
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 toGetDevicePathSize()
to get the size (uint32) of the “FilePath”:This size is later used for computing the
EventSize
which is then used for performing an allocation:Between the call to
GetDevicePathSize()
and the allocation no checks are performed onEventSize
, which means that the allocation size can overflow, andAllocateZeroPool()
can return a very small allocation for a very bigFilePathSize
.Later on the code
FilePathSize
is used again for copying memory into the allocated buffer, also without further checks onFilePathSize
:This means, the responsibility for checking that the
EventSize
variable doesn’t overflow whenFilePathSize
is added, is on theGetDevicePathSize()
function.GetDevicePathSize()
callsIsDevicePathValid()
which does the following:MaxSize
variable (max value we can return) toMAX_UINTN
.MAX_UINT32
we could still exploit this, because we don’t have to exceedMaxSize - END_DEVICE_PATH_LENGTH
(4), and inTcg2MeasurePeImage()
we calculateEventSize
by doing:sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize
which is0x24 - 4 + FilePathSize
, soGetDevicePathSize()
could return up to 0xfffffffb which is more than enough for overflowing.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:
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.