Multiple SMM memory corruption vulnerabilities in SMM module on Lenovo device (SMRAM write).
BINARLY REsearch team has discovered multiple memory corruption vulnerabilities in Lenovo device firmware that could allow a potential attacker to write fixed or predictable data to an attacker-controlled address.
Image preview
Potential Impact
An attacker could exploit this vulnerability to elevate privileges from ring 0 to ring -2 and execute arbitrary code in System Management Mode, an environment more privileged than and completely isolated from the operating system (OS). Running arbitrary code in SMM also bypasses SMM-based SPI flash protections against modification, which can help an attacker to install a firmware backdoor/implant. Such malicious code in the firmware could persist through operating system reinstallations. In addition, this vulnerability could potentially be used by malicious actors to bypass security mechanisms provided by UEFI firmware, such as Secure Boot and some types of memory isolation for hypervisors.
Image preview
Vulnerability Information
- BINARLY internal vulnerability identifier: BRLY-DVA-2025-019
- CVSS v3.1: 8.2 High AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H
Image preview
Affected firmware
| Device name | Unpacked firmware SHA256 | Firmware version | OEM | IBV | Module name | Module GUID | Module SHA256 | Module kind |
|---|---|---|---|---|---|---|---|---|
thinkpad-e495-type-20ne | 35faca245658dd9b664202f4a07f01a743a0cffea8012653d8a5384439f4f571 | 1.31 (2024-10-29) | Lenovo | Phoenix | SmmOEMInt15 | 243c8c8a-bbd0-4aa9-be17-cf9b583130ec | 0dcc17a8a2e2ea0313bdd6ea02e3a1f1e6f658cedec3a44fecb7629dfa8ba1e7 | SmmModule |
thinkpad-a485-type-20mu-20mv | 0d92ead276d0ff88b1154a6caa6ff383e72d86bac873db3616bac3a9deb242ad | 1.36 (2023-12-28) | Lenovo | Phoenix | SmmOEMInt15 | 243c8c8a-bbd0-4aa9-be17-cf9b583130ec | 1e173aa62b00d0057ae872c16060b159aae096bd8b98730d45870d71b7f460e5 | SmmModule |
thinkpad-a285-type-20mw-20mx | 1357d8a0287404d648cc3e43059a677fdc0c2b68df4a2aa9f297b88a65ae6095 | 1.50 (2023-12-29) | Lenovo | Phoenix | SmmOEMInt15 | 243c8c8a-bbd0-4aa9-be17-cf9b583130ec | 6c1b7400b2756770ecdd283c40af59b78011437518353efc327ffd29a90322f8 | SmmModule |
thinkpad-p50 | 503a5503e71c4ebfcb1c3a5d44790a1d61b4542f0fa39e9b1f401b57fa2e8dfa | 1.75 (2024-04-04) | Lenovo | Phoenix | SmmOEMInt15 | 243c8c8a-bbd0-4aa9-be17-cf9b583130ec | 7e6cdd6dc2213cf779e61b05f0206e3397fab3cfce402b24108768455b734adc | SmmModule |
thinkpad-p70 | 56afaac7f9120c2eb34ce7c500611d7a9ddca1057e7c0b6115f1ca160722084a | 2.49 (2024-04-15) | Lenovo | Phoenix | SmmOEMInt15 | 243c8c8a-bbd0-4aa9-be17-cf9b583130ec | 7e6cdd6dc2213cf779e61b05f0206e3397fab3cfce402b24108768455b734adc | SmmModule |
thinkpad-t470p | 8efec2f367462b37f1fb9c0a6ff584425a25cff1925209d32630e6f8413030b4 | 1.41 (2023-11-08) | Lenovo | Phoenix | SmmOEMInt15 | 243c8c8a-bbd0-4aa9-be17-cf9b583130ec | 85c32e72d1c1e6f82122708280b2e66799b696c118c3a1428e520e4a7fd21e7e | SmmModule |
thinkpad-e485-type-20ku | f46ec73f54db67733ccd0bf5caca173451ec4afb8cbe0962bf9e640a1ba5f52e | 1.64 (2023-12-13) | Lenovo | Phoenix | SmmOEMInt15 | 243c8c8a-bbd0-4aa9-be17-cf9b583130ec | f88b3d5cf1f7a901ad1ae2dec7ced9a967385ab54e2c559aaca2dad55ed66e5c | SmmModule |
Image preview
Vulnerability description
Let's consider the module 0dcc17a8a2e2ea0313bdd6ea02e3a1f1e6f658cedec3a44fecb7629dfa8ba1e7.
The partial pseudocode of the vulnerable handler is shown below:
EFI_STATUS SwSmiHandler(
EFI_HANDLE DispatchHandle,
const void *Context,
EFI_SMM_SW_CONTEXT *CommBuffer,
UINTN *CommBufferSize)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS NUMPAD "+" TO EXPAND]
CpuIndex = CommBuffer->SwSmiCpuIndex;
if ( (gEfiSmmCpuProtocol->ReadSaveState(
gEfiSmmCpuProtocol,
4,
EFI_SMM_SAVE_STATE_REGISTER_RSI,
CommBuffer->SwSmiCpuIndex,
&RsiReg)
& 0x8000000000000000) != 0 )
return EFI_ACCESS_DENIED;
// Param is an attacker contolled pointer
Param = (UINT16 *)RsiReg;
if ( (gEfiSmmCpuProtocol->ReadSaveState(
gEfiSmmCpuProtocol,
2,
EFI_SMM_SAVE_STATE_REGISTER_RFLAGS,
CpuIndex,
&RflagsReg)
& 0x8000000000000000) != 0 )
return EFI_ACCESS_DENIED;
Command = *Param;
if ( Command <= 0x5380 )
{
if ( Command != 0x5380 )
{
...
}
}
...
if ( Status >= 0 )
{
Param[12] &= ~1; // SMRAM write
*(Param + 1) = 0; // SMRAM write
}
else
{
Param[12] |= 1; // SMRAM write
}
_CheckStatus:
if ( Status < 0 )
{
Param[12] |= 1; // SMRAM write
goto _WriteRflags;
}
_WriteRflagsAndParam:
Param[12] &= ~1; // SMRAM write
_WriteRflags:
RflagsReg &= 0xFFFA;
gEfiSmmCpuProtocol->WriteSaveState(gEfiSmmCpuProtocol, 2, EFI_SMM_SAVE_STATE_REGISTER_RFLAGS, CpuIndex, &RflagsReg);
return 0;
}
As we can see from the pseudocode, the RsiReg value (obtained from the RSI register with gEfiSmmCpuProtocol->ReadSaveState) is not validated before attempting to write to the buffer pointed to by RsiReg.
The handler, as well as the handler's child functions, contains multiple write operations:
if ( Status >= 0 )
{
Param[12] &= ~1; // SMRAM write
*(Param + 1) = 0; // SMRAM write
}
else
{
Param[12] |= 1; // SMRAM write
}
_CheckStatus:
if ( Status < 0 )
{
Param[12] |= 1; // SMRAM write
goto _WriteRflags;
}
_WriteRflagsAndParam:
Param[12] &= ~1; // SMRAM write
_WriteRflags:
RflagsReg &= 0xFFFA;
gEfiSmmCpuProtocol->WriteSaveState(gEfiSmmCpuProtocol, 2, EFI_SMM_SAVE_STATE_REGISTER_RFLAGS, CpuIndex, &RflagsReg);
An example of a child function of a handler containing arbitrary write operations is the functin at 0x1AF0:
MACRO_EFI sub_1AF0(UINT16 *Param)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS NUMPAD "+" TO EXPAND]
...
_Exit:
// SMRAM write
*Param = *Param;
*Param |= Value << 8;
return Status;
}
These write primitives allow to corrupt SMRAM with subsequent code execution.
It should be noted that this handler also contains multiple SMM callout vulnerabilities (also detected by the Deep Vulnerability Analysis (DVA) component from Binarly Platform) via Runtime Services, Boot Services and EFI_USB_IO_PROTOCOL.
For example, the following snippet contains an SMM callout via Runtime Services:
if ( Param[2] == 0x7004 )
{
Status = gSmst->SmmLocateProtocol(&FDISK_OEM_SMM_PROTOCOL_GUID, 0, &gFdiskOemSmmProtocol);
if ( Status >= 0 )
{
gFdiskOemSmmProtocol->Func38();
gRT->ResetSystem(EfiResetShutdown, 0, 0, 0); // SMM callout
}
}
else
{
Status = EFI_INVALID_PARAMETER;
*Param = 2688; // SMRAM write
}
And the following snippet contains an SMM callout via Boot Services and EFI_USB_IO_PROTOCOL:
...
MEMORY[4] = 0xFFFEFFFE;
SetMem(gBuffer, 0x30, Value);
Status = gBS->LocateHandleBuffer(ByProtocol, &EFI_USB_IO_PROTOCOL_GUID, 0, &NoHandles, &Buffer);
if ( Status >= 0 && NoHandles )
{
Index = 0;
Ptr = (ControlledBuffer + 16);
while ( 1 )
{
Status = gBS->HandleProtocol(Buffer[v4], &EFI_USB_IO_PROTOCOL_GUID, &EfiUsbIoProtocol);
if ( Status < 0 )
break;
EfiUsbIoProtocol0 = EfiUsbIoProtocol;
if ( (EfiUsbIoProtocol->UsbGetDeviceDescriptor)(EfiUsbIoProtocol, &Descriptor) >= 0 && Descriptor.DeviceClass != 9 )
{
IdVendor = *(ControlledBuffer + 10);
if ( Descriptor.IdVendor == IdVendor || !IdVendor || IdVendor == 255 )
{
IdProduct = *(ControlledBuffer + 12);
if ( (Descriptor.IdProduct == IdProduct || !IdProduct || IdProduct == 255)
&& (EfiUsbIoProtocol0->UsbGetInterfaceDescriptor)(EfiUsbIoProtocol0, &InterfaceDescriptor) >= 0 )
{
InterfaceClass = *(ControlledBuffer + 8);
if ( InterfaceDescriptor.InterfaceClass == InterfaceClass || ((InterfaceClass + 1) & 0xFE) == 0 )
...
}
}
}
}
}
Image preview
Disclosure timeline
This vulnerability is subject to a 90 day disclosure period. After 90 days or when a patch has been made generally available (whichever comes first) the advisory will be publicly disclosed.
| Disclosure Activity | Date |
|---|---|
Lenovo PSIRT is notified | 2025-04-08 |
Lenovo PSIRT is confirmed issue | 2025-06-16 |
BINARLY public disclosure date | 2025-07-29 |
Image preview
Acknowledgements
Image preview
See if you are impacted now with our Firmware Vulnerability Scanner
Find Vulnerabilities, Generate SBOMs & CBOMs