SMM memory corruption vulnerability in combined DXE/SMM driver on Fujitsu device (SMRAM write).
BINARLY efiXplorer team has discovered a SMM memory corruption vulnerability in a Fujitsu device allowing a possible attacker to write fixed or predictable data to SMRAM. Exploiting this issue could lead to escalating privileges to SMM.
Image preview
Potential Impact
An attacker can exploit this vulnerability to elevate privileges from ring 0 to ring -2, execute arbitrary code in System Management Mode - an environment more privileged than operating system (OS) and completely isolated from it. Running arbitrary code in SMM additionally bypasses SMM-based SPI flash protections against modifications, which can help an attacker to install a firmware backdoor/implant into BIOS. Such a malicious firmware code in BIOS could persist across operating system re-installs. Additionally, this vulnerability potentially could be used by malicious actors to bypass security mechanisms provided by UEFI firmware (for example, Secure Boot and some types of memory isolation for hypervisors).
Image preview
Vulnerability Information
- BINARLY internal vulnerability identifier: BRLY-DVA-2023-026
- Fujitsu PSIRT assigned CVE identifier: CVE-2024-25079
- 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 Insyde-based Fujitsu firmware images
| Device name | Unpacked firmware SHA256 | Firmware version | IBV | Module name | Module GUID | Module SHA256 | Module kind |
|---|---|---|---|---|---|---|---|
LIFEBOOK U9312X (BLACK, RED) | 6141b195ace260837f69e639c99c4fd7bf7200b18de83566090a04affbda59c0 | 2.14 | Insyde | HddPassword | e8571188-00c1-4ed4-b14e-e38451351ec4 | dd1ae67e3b6f6372a1ac87c997d2a48f62165572af79b6c2108c601139767a59 | CombinedSmmDxe |
Image preview
Vulnerability description
The pseudocode of the vulnerable ChildSwSmiHandler function (with the HandlerType: EFI_HDD_PASSWORD_SERVICE_PROTOCOL_GUID) is presented below:
EFI_STATUS __fastcall ChildSwSmiHandler(
EFI_HANDLE DispatchHandle,
const void *Context,
_QWORD *CommBuffer,
UINTN *CommBufferSize)
{
char *WpdhStructure; // rbp
EFI_STATUS Status; // rbx
_QWORD *Ptr2; // rcx
_QWORD *i; // rax
EFI_HANDLE *v9; // rdi
EFI_HANDLE *Buffer; // rax
UINTN v11; // r12
UINTN v12; // r13
_QWORD *Address; // r14
__int64 v14; // r15
EFI_DEVICE_PATH_PROTOCOL *v15; // rbx
__int64 Ptr1; // [rsp+30h] [rbp-48h]
EFI_DEVICE_PATH_PROTOCOL *EfiDevicePathProtocol; // [rsp+38h] [rbp-40h] BYREF
void *EfiStorageSecurityCommandProtocol; // [rsp+40h] [rbp-38h] BYREF
UINTN BufferSize; // [rsp+90h] [rbp+18h] BYREF
if ( !CommBuffer || !CommBufferSize )
return EFI_SUCCESS;
if ( CommBuffer != (gBuffer + 24) )
return EFI_ACCESS_DENIED;
WpdhStructure = (CommBuffer + 2);
if ( *CommBuffer == 1 )
goto _CheckSize;
if ( *CommBuffer != 2 )
{
if ( *CommBuffer != 3 )
{
if ( *CommBuffer == 4 )
{
if ( *CommBufferSize == 17 )
{
gFlag = *WpdhStructure;
goto _ExitSuccess;
}
return EFI_ACCESS_DENIED;
}
_Unsupported:
Status = EFI_UNSUPPORTED;
goto _Exit;
}
_CheckSize:
if ( *CommBufferSize != 248 )
return EFI_ACCESS_DENIED;
Ptr2 = (CommBuffer[22] + 8);
for ( i = *Ptr2; i != Ptr2; i = *i )
{
i[24] = 0; // unchecked write (SMRAM corruption)
i[4] = 0; // unchecked write (SMRAM corruption)
i[6] = 0; // unchecked write (SMRAM corruption)
}
if ( *WpdhStructure == 'wpdh' )
{
Ptr1 = CommBuffer[22];
if ( !Ptr1 )
{
Status = EFI_NOT_READY;
goto _Exit;
}
BufferSize = 0;
v9 = 0;
Status = gSmst_0->SmmLocateHandle(
ByProtocol,
&EFI_STORAGE_SECURITY_COMMAND_PROTOCOL_GUID,
0,
&BufferSize,
0);
if ( Status == EFI_BUFFER_TOO_SMALL )
{
Buffer = AllocatePool(6);
v9 = Buffer;
if ( !Buffer )
{
Status = EFI_OUT_OF_RESOURCES;
goto _Exit;
}
Status = gSmst_0->SmmLocateHandle(
ByProtocol,
&EFI_STORAGE_SECURITY_COMMAND_PROTOCOL_GUID,
0,
&BufferSize,
Buffer);
}
if ( Status )
{
if ( v9 )
Free(v9);
}
else if ( v9 )
{
v11 = 0;
v12 = BufferSize >> 3;
if ( BufferSize >> 3 )
{
do
{
Status = gSmst_0->SmmHandleProtocol(
v9[v11],
&EFI_STORAGE_SECURITY_COMMAND_PROTOCOL_GUID,
&EfiStorageSecurityCommandProtocol);
if ( !Status )
{
Status = gSmst_0->SmmHandleProtocol(v9[v11], &EFI_DEVICE_PATH_PROTOCOL_GUID, &EfiDevicePathProtocol);
if ( !Status )
{
Address = *(Ptr1 + 8);
if ( Address != (Ptr1 + 8) )
{
while ( 2 )
{
v14 = Address[57];
v15 = EfiDevicePathProtocol;
while ( *v14 != 127 || *(v14 + 1) != 0xFF )
{
if ( v15->Type == 127 && v15->SubType == 0xFF )
{
if ( *v14 != 127 || *(v14 + 1) != 0xFF )
goto _Continue;
break;
}
if ( *(v14 + 2) != *v15->Length || *v15->Length && v14 != v15 && sub_1060(v14, v15, *v15->Length) )
goto _Continue;
v14 += *(v14 + 2);
v15 = (v15 + *v15->Length);
}
if ( v15->Type == 127 && v15->SubType == 0xFF )
{
Status = 0;
Address[24] = v9[v11]; // unchecked write (SMRAM corruption)
Address[4] = v9[v11]; // unchecked write (SMRAM corruption)
Address[6] = EfiStorageSecurityCommandProtocol;// unchecked write (SMRAM corruption)
goto _Next;
}
_Continue:
Address = *Address;
if ( Address != (Ptr1 + 8) )
continue;
break;
}
Status = EFI_ABORTED;
}
}
}
_Next:
++v11;
}
while ( v11 < v12 );
WpdhStructure = (CommBuffer + 2);
}
Free(v9);
if ( *CommBuffer == 1 || !gWpdhBuffer )
sub_5B7C(WpdhStructure); // unchecked write (SMRAM corruption) inside this function
goto _Exit;
}
}
goto _Unsupported;
}
if ( *CommBufferSize == 16 )
{
if ( !gAcpiRestoreRegistration )
{
Status = gSmst_0->SmmRegisterProtocolNotify(
&ACPI_RESTORE_CALLBACK_START_PROTOCOL_GUID,
AcpiRestoreNotifier,
&gAcpiRestoreRegistration);
goto _Exit;
}
_ExitSuccess:
Status = 0;
_Exit:
CommBuffer[1] = Status;
return 0;
}
return EFI_ACCESS_DENIED;
}
As we can see from the comments in the pseudocode, the function contains many unchecked write operatons to the controlled pointer.
Let's break them down in more detail:
-
The code snippet below contains multiple write operations to a buffer that may overlap with SMRAM since Ptr2 is controllable by an attacker:
Ptr2 = (CommBuffer[22] + 8); for ( i = *Ptr2; i != Ptr2; i = *i ) { i[24] = 0; // unchecked write (SMRAM corruption) i[4] = 0; // unchecked write (SMRAM corruption) i[6] = 0; // unchecked write (SMRAM corruption) } -
The code snippet below contains multiple write operations to a buffer that may overlap with SMRAM since Ptr1 is controllable by an attacker:
Ptr1 = CommBuffer[22]; ... Address = *(Ptr1 + 8); ... Address[24] = v9[v11]; // unchecked write (SMRAM corruption) Address[4] = v9[v11]; // unchecked write (SMRAM corruption) Address[6] = EfiStorageSecurityCommandProtocol;// unchecked write (SMRAM corruption) -
The function below contains multiple write operations to a buffer that may overlap with SMRAM since WpdhStructure pointer is controllable by an attacker (when consider the case with
gWpdhBuffer=NULL)__int64 __fastcall sub_5B7C(__int64 WpdhStructure) { __int64 v1; // rax __int64 v2; // rdi __int64 CtrlPtr1; // rdx __int64 CtrlPtr2; // rcx __int64 result; // rax __int64 v7; // rcx EFI_HANDLE Handle; // [rsp+30h] [rbp+8h] BYREF v1 = *(WpdhStructure + 160); v2 = 0; if ( !v1 || !*(WpdhStructure + 184) ) return EFI_NOT_READY; CtrlPtr1 = gWpdhBuffer; if ( !gWpdhBuffer ) { CtrlPtr2 = *(WpdhStructure + 176); CtrlPtr1 = *(CtrlPtr2 + 16); *(CtrlPtr2 + 24) -= 232; gWpdhBuffer = CtrlPtr1; *(CtrlPtr2 + 16) = CtrlPtr1 + 232; *(CtrlPtr1 + 176) = CtrlPtr2; *CtrlPtr1 = 'wpdh'; *(CtrlPtr1 + 160) = *(WpdhStructure + 160); v1 = *(WpdhStructure + 160); } *(CtrlPtr1 + 160) = v1; *(CtrlPtr1 + 169) = 1; *(CtrlPtr1 + 8) = sub_3D70; *(CtrlPtr1 + 184) = 1; *(CtrlPtr1 + 16) = sub_3DBC; *(CtrlPtr1 + 24) = sub_3E04; *(CtrlPtr1 + 32) = sub_30E0; *(CtrlPtr1 + 40) = sub_2B8C; *(CtrlPtr1 + 48) = sub_3E4C; *(CtrlPtr1 + 56) = sub_3350; *(CtrlPtr1 + 64) = sub_3A3C; *(CtrlPtr1 + 72) = sub_4170; *(CtrlPtr1 + 80) = sub_2B00; *(CtrlPtr1 + 88) = sub_439C; *(CtrlPtr1 + 186) = *(WpdhStructure + 186); *(CtrlPtr1 + 96) = sub_6BC4; *(CtrlPtr1 + 104) = sub_6C90; *(CtrlPtr1 + 112) = sub_6CB8; *(CtrlPtr1 + 120) = sub_793C; *(CtrlPtr1 + 128) = sub_7B68; *(CtrlPtr1 + 136) = sub_7C80; *(CtrlPtr1 + 144) = sub_7D80; *(CtrlPtr1 + 152) = sub_8380; Handle = 0; result = gSmst_0->SmmInstallProtocolInterface( &Handle, &EFI_HDD_PASSWORD_SERVICE_PROTOCOL_GUID, EFI_NATIVE_INTERFACE, (CtrlPtr1 + 8)); if ( result >= 0 ) { *(gWpdhBuffer + 224) = *(WpdhStructure + 224); sub_7F14(); v7 = gWpdhBuffer; *(gWpdhBuffer + 200) = *(WpdhStructure + 200); *(v7 + 208) = *(WpdhStructure + 208); *(v7 + 216) = *(WpdhStructure + 216); sub_6DB0(v7 + 8, 1); if ( !gAcpiRestoreRegistration ) return gSmst_0->SmmRegisterProtocolNotify( &ACPI_RESTORE_CALLBACK_START_PROTOCOL_GUID, AcpiRestoreNotifier, &gAcpiRestoreRegistration); return v2; } return result; }
In order to fix this vulnerability, it is necessary to check all nested pointers for overlapping with SMRAM before attempting to write to buffer pointed by it.
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 (YYYY-mm-dd) |
|---|---|
Fujitsu PSIRT is notified | 2023-12-22 |
Fujitsu PSIRT informed Insyde | 2024-01-22 |
Insyde PSIRT is confirmed issue | 2024-01-24 |
Insyde PSIRT provide patch release | 2024-05-13 |
BINARLY public disclosure date | 2024-06-17 |
Image preview
Acknowledgements
Image preview
See if you are impacted now with our Firmware Vulnerability Scanner
Find Vulnerabilities, Generate SBOMs & CBOMs