1. Fix TOCTOU issue in VariableSmm, FtwSmm, FpdtSmm, SmmCorePerformance SMM handler. For VariableSmm, pre-allocate a mVariableBufferPayload buffer with mVariableBufferPayloadSize(match with mVariableBufferPayloadSize in VariableSmmRuntimeDxe) to hold communicate buffer payload to avoid TOCTOU issue.

2. Add check to ensure CommBufferPayloadSize not exceed mVariableBufferPayloadSize or is enough to hold function structure in VariableSmm and FtwSmm.
3. Align FtwGetLastWrite() in FaultTolerantWriteSmmDxe.c to FtwGetLastWrite() in FaultTolerantWrite.c.

Signed-off-by: Star Zeng <star.zeng@intel.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@14325 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
lzeng14
2013-05-07 05:38:32 +00:00
parent 845a7fe028
commit 5e5bb2a9ba
9 changed files with 311 additions and 187 deletions

View File

@ -540,6 +540,9 @@ SmmPerformanceHandlerEx (
SMM_PERF_COMMUNICATE_EX *SmmPerfCommData; SMM_PERF_COMMUNICATE_EX *SmmPerfCommData;
GAUGE_DATA_ENTRY_EX *GaugeEntryExArray; GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
UINTN DataSize; UINTN DataSize;
GAUGE_DATA_ENTRY_EX *GaugeDataEx;
UINTN NumberOfEntries;
UINTN LogEntryKey;
GaugeEntryExArray = NULL; GaugeEntryExArray = NULL;
@ -555,7 +558,7 @@ SmmPerformanceHandlerEx (
} }
if (!IsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) { if (!IsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) {
DEBUG ((EFI_D_ERROR, "SMM communcation data buffer in SMRAM or overflow!\n")); DEBUG ((EFI_D_ERROR, "SmmPerformanceHandlerEx: SMM communcation data buffer in SMRAM or overflow!\n"));
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -568,8 +571,11 @@ SmmPerformanceHandlerEx (
break; break;
case SMM_PERF_FUNCTION_GET_GAUGE_DATA : case SMM_PERF_FUNCTION_GET_GAUGE_DATA :
if ( SmmPerfCommData->GaugeDataEx == NULL || SmmPerfCommData->NumberOfEntries == 0 || GaugeDataEx = SmmPerfCommData->GaugeDataEx;
(SmmPerfCommData->LogEntryKey + SmmPerfCommData->NumberOfEntries) > mGaugeData->NumberOfEntries) { NumberOfEntries = SmmPerfCommData->NumberOfEntries;
LogEntryKey = SmmPerfCommData->LogEntryKey;
if (GaugeDataEx == NULL || NumberOfEntries == 0 || LogEntryKey > mGaugeData->NumberOfEntries ||
NumberOfEntries > mGaugeData->NumberOfEntries || (LogEntryKey + NumberOfEntries) > mGaugeData->NumberOfEntries) {
Status = EFI_INVALID_PARAMETER; Status = EFI_INVALID_PARAMETER;
break; break;
} }
@ -577,17 +583,17 @@ SmmPerformanceHandlerEx (
// //
// Sanity check // Sanity check
// //
DataSize = SmmPerfCommData->NumberOfEntries * sizeof(GAUGE_DATA_ENTRY_EX); DataSize = NumberOfEntries * sizeof(GAUGE_DATA_ENTRY_EX);
if (!IsAddressValid ((UINTN)SmmPerfCommData->GaugeDataEx, DataSize)) { if (!IsAddressValid ((UINTN)GaugeDataEx, DataSize)) {
DEBUG ((EFI_D_ERROR, "SMM Performance Data buffer in SMRAM or overflow!\n")); DEBUG ((EFI_D_ERROR, "SmmPerformanceHandlerEx: SMM Performance Data buffer in SMRAM or overflow!\n"));
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
break; break;
} }
GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1); GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
CopyMem( CopyMem(
(UINT8 *) (SmmPerfCommData->GaugeDataEx), (UINT8 *) GaugeDataEx,
(UINT8 *) &GaugeEntryExArray[SmmPerfCommData->LogEntryKey], (UINT8 *) &GaugeEntryExArray[LogEntryKey],
DataSize DataSize
); );
Status = EFI_SUCCESS; Status = EFI_SUCCESS;
@ -640,6 +646,8 @@ SmmPerformanceHandler (
GAUGE_DATA_ENTRY_EX *GaugeEntryExArray; GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
UINTN DataSize; UINTN DataSize;
UINTN Index; UINTN Index;
GAUGE_DATA_ENTRY *GaugeData;
UINTN NumberOfEntries;
UINTN LogEntryKey; UINTN LogEntryKey;
GaugeEntryExArray = NULL; GaugeEntryExArray = NULL;
@ -656,7 +664,7 @@ SmmPerformanceHandler (
} }
if (!IsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) { if (!IsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) {
DEBUG ((EFI_D_ERROR, "SMM communcation data buffer in SMRAM or overflow!\n")); DEBUG ((EFI_D_ERROR, "SmmPerformanceHandler: SMM communcation data buffer in SMRAM or overflow!\n"));
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -669,8 +677,11 @@ SmmPerformanceHandler (
break; break;
case SMM_PERF_FUNCTION_GET_GAUGE_DATA : case SMM_PERF_FUNCTION_GET_GAUGE_DATA :
if ( SmmPerfCommData->GaugeData == NULL || SmmPerfCommData->NumberOfEntries == 0 || GaugeData = SmmPerfCommData->GaugeData;
(SmmPerfCommData->LogEntryKey + SmmPerfCommData->NumberOfEntries) > mGaugeData->NumberOfEntries) { NumberOfEntries = SmmPerfCommData->NumberOfEntries;
LogEntryKey = SmmPerfCommData->LogEntryKey;
if (GaugeData == NULL || NumberOfEntries == 0 || LogEntryKey > mGaugeData->NumberOfEntries ||
NumberOfEntries > mGaugeData->NumberOfEntries || (LogEntryKey + NumberOfEntries) > mGaugeData->NumberOfEntries) {
Status = EFI_INVALID_PARAMETER; Status = EFI_INVALID_PARAMETER;
break; break;
} }
@ -678,19 +689,18 @@ SmmPerformanceHandler (
// //
// Sanity check // Sanity check
// //
DataSize = SmmPerfCommData->NumberOfEntries * sizeof(GAUGE_DATA_ENTRY); DataSize = NumberOfEntries * sizeof(GAUGE_DATA_ENTRY);
if (!IsAddressValid ((UINTN)SmmPerfCommData->GaugeData, DataSize)) { if (!IsAddressValid ((UINTN)GaugeData, DataSize)) {
DEBUG ((EFI_D_ERROR, "SMM Performance Data buffer in SMRAM or overflow!\n")); DEBUG ((EFI_D_ERROR, "SmmPerformanceHandler: SMM Performance Data buffer in SMRAM or overflow!\n"));
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
break; break;
} }
GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1); GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
LogEntryKey = SmmPerfCommData->LogEntryKey; for (Index = 0; Index < NumberOfEntries; Index++) {
for (Index = 0; Index < SmmPerfCommData->NumberOfEntries; Index++) {
CopyMem( CopyMem(
(UINT8 *) &(SmmPerfCommData->GaugeData[Index]), (UINT8 *) &GaugeData[Index],
(UINT8 *) &GaugeEntryExArray[LogEntryKey++], (UINT8 *) &GaugeEntryExArray[LogEntryKey++],
sizeof (GAUGE_DATA_ENTRY) sizeof (GAUGE_DATA_ENTRY)
); );

View File

@ -266,6 +266,8 @@ FpdtSmiHandler (
{ {
EFI_STATUS Status; EFI_STATUS Status;
SMM_BOOT_RECORD_COMMUNICATE *SmmCommData; SMM_BOOT_RECORD_COMMUNICATE *SmmCommData;
UINTN BootRecordSize;
VOID *BootRecordData;
// //
// If input is invalid, stop processing this SMI // If input is invalid, stop processing this SMI
@ -279,7 +281,7 @@ FpdtSmiHandler (
} }
if (!InternalIsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) { if (!InternalIsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) {
DEBUG ((EFI_D_ERROR, "SMM communication data buffer in SMRAM or overflow!\n")); DEBUG ((EFI_D_ERROR, "FpdtSmiHandler: SMM communication data buffer in SMRAM or overflow!\n"));
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -293,7 +295,9 @@ FpdtSmiHandler (
break; break;
case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA : case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA :
if (SmmCommData->BootRecordData == NULL || SmmCommData->BootRecordSize < mBootRecordSize) { BootRecordData = SmmCommData->BootRecordData;
BootRecordSize = SmmCommData->BootRecordSize;
if (BootRecordData == NULL || BootRecordSize < mBootRecordSize) {
Status = EFI_INVALID_PARAMETER; Status = EFI_INVALID_PARAMETER;
break; break;
} }
@ -302,14 +306,14 @@ FpdtSmiHandler (
// Sanity check // Sanity check
// //
SmmCommData->BootRecordSize = mBootRecordSize; SmmCommData->BootRecordSize = mBootRecordSize;
if (!InternalIsAddressValid ((UINTN)SmmCommData->BootRecordData, mBootRecordSize)) { if (!InternalIsAddressValid ((UINTN)BootRecordData, mBootRecordSize)) {
DEBUG ((EFI_D_ERROR, "SMM Data buffer in SMRAM or overflow!\n")); DEBUG ((EFI_D_ERROR, "FpdtSmiHandler: SMM Data buffer in SMRAM or overflow!\n"));
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
break; break;
} }
CopyMem ( CopyMem (
(UINT8*)SmmCommData->BootRecordData, (UINT8*)BootRecordData,
mBootRecordBuffer, mBootRecordBuffer,
mBootRecordSize mBootRecordSize
); );

View File

@ -369,6 +369,9 @@ SmmFaultTolerantWriteHandler (
VOID *PrivateData; VOID *PrivateData;
EFI_HANDLE SmmFvbHandle; EFI_HANDLE SmmFvbHandle;
UINTN InfoSize; UINTN InfoSize;
UINTN CommBufferPayloadSize;
UINTN PrivateDataSize;
UINTN Length;
// //
@ -379,11 +382,13 @@ SmmFaultTolerantWriteHandler (
} }
if (*CommBufferSize < SMM_FTW_COMMUNICATE_HEADER_SIZE) { if (*CommBufferSize < SMM_FTW_COMMUNICATE_HEADER_SIZE) {
DEBUG ((EFI_D_ERROR, "SmmFtwHandler: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS; return EFI_SUCCESS;
} }
CommBufferPayloadSize = *CommBufferSize - SMM_FTW_COMMUNICATE_HEADER_SIZE;
if (!InternalIsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) { if (!InternalIsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) {
DEBUG ((EFI_D_ERROR, "SMM communication buffer in SMRAM or overflow!\n")); DEBUG ((EFI_D_ERROR, "SmmFtwHandler: SMM communication buffer in SMRAM or overflow!\n"));
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -400,17 +405,11 @@ SmmFaultTolerantWriteHandler (
switch (SmmFtwFunctionHeader->Function) { switch (SmmFtwFunctionHeader->Function) {
case FTW_FUNCTION_GET_MAX_BLOCK_SIZE: case FTW_FUNCTION_GET_MAX_BLOCK_SIZE:
SmmGetMaxBlockSizeHeader = (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER *) SmmFtwFunctionHeader->Data; if (CommBufferPayloadSize < sizeof (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER)) {
InfoSize = sizeof (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER); DEBUG ((EFI_D_ERROR, "GetMaxBlockSize: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
//
// SMRAM range check already covered before
//
if (InfoSize > *CommBufferSize - SMM_FTW_COMMUNICATE_HEADER_SIZE) {
DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n"));
Status = EFI_ACCESS_DENIED;
break;
} }
SmmGetMaxBlockSizeHeader = (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER *) SmmFtwFunctionHeader->Data;
Status = FtwGetMaxBlockSize ( Status = FtwGetMaxBlockSize (
&mFtwDevice->FtwInstance, &mFtwDevice->FtwInstance,
@ -419,6 +418,10 @@ SmmFaultTolerantWriteHandler (
break; break;
case FTW_FUNCTION_ALLOCATE: case FTW_FUNCTION_ALLOCATE:
if (CommBufferPayloadSize < sizeof (SMM_FTW_ALLOCATE_HEADER)) {
DEBUG ((EFI_D_ERROR, "Allocate: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
SmmFtwAllocateHeader = (SMM_FTW_ALLOCATE_HEADER *) SmmFtwFunctionHeader->Data; SmmFtwAllocateHeader = (SMM_FTW_ALLOCATE_HEADER *) SmmFtwFunctionHeader->Data;
Status = FtwAllocate ( Status = FtwAllocate (
&mFtwDevice->FtwInstance, &mFtwDevice->FtwInstance,
@ -429,11 +432,36 @@ SmmFaultTolerantWriteHandler (
break; break;
case FTW_FUNCTION_WRITE: case FTW_FUNCTION_WRITE:
if (CommBufferPayloadSize < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data)) {
DEBUG ((EFI_D_ERROR, "Write: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
SmmFtwWriteHeader = (SMM_FTW_WRITE_HEADER *) SmmFtwFunctionHeader->Data; SmmFtwWriteHeader = (SMM_FTW_WRITE_HEADER *) SmmFtwFunctionHeader->Data;
if (SmmFtwWriteHeader->PrivateDataSize == 0) { Length = SmmFtwWriteHeader->Length;
PrivateDataSize = SmmFtwWriteHeader->PrivateDataSize;
if (((UINTN)(~0) - Length < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data)) ||
((UINTN)(~0) - PrivateDataSize < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data) + Length)) {
//
// Prevent InfoSize overflow
//
Status = EFI_ACCESS_DENIED;
break;
}
InfoSize = OFFSET_OF (SMM_FTW_WRITE_HEADER, Data) + Length + PrivateDataSize;
//
// SMRAM range check already covered before
//
if (InfoSize > CommBufferPayloadSize) {
DEBUG ((EFI_D_ERROR, "Write: Data size exceed communication buffer size limit!\n"));
Status = EFI_ACCESS_DENIED;
break;
}
if (PrivateDataSize == 0) {
PrivateData = NULL; PrivateData = NULL;
} else { } else {
PrivateData = (VOID *)&SmmFtwWriteHeader->Data[SmmFtwWriteHeader->Length]; PrivateData = (VOID *)&SmmFtwWriteHeader->Data[Length];
} }
Status = GetFvbByAddressAndAttribute ( Status = GetFvbByAddressAndAttribute (
SmmFtwWriteHeader->FvbBaseAddress, SmmFtwWriteHeader->FvbBaseAddress,
@ -445,7 +473,7 @@ SmmFaultTolerantWriteHandler (
&mFtwDevice->FtwInstance, &mFtwDevice->FtwInstance,
SmmFtwWriteHeader->Lba, SmmFtwWriteHeader->Lba,
SmmFtwWriteHeader->Offset, SmmFtwWriteHeader->Offset,
SmmFtwWriteHeader->Length, Length,
PrivateData, PrivateData,
SmmFvbHandle, SmmFvbHandle,
SmmFtwWriteHeader->Data SmmFtwWriteHeader->Data
@ -454,6 +482,10 @@ SmmFaultTolerantWriteHandler (
break; break;
case FTW_FUNCTION_RESTART: case FTW_FUNCTION_RESTART:
if (CommBufferPayloadSize < sizeof (SMM_FTW_RESTART_HEADER)) {
DEBUG ((EFI_D_ERROR, "Restart: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
SmmFtwRestartHeader = (SMM_FTW_RESTART_HEADER *) SmmFtwFunctionHeader->Data; SmmFtwRestartHeader = (SMM_FTW_RESTART_HEADER *) SmmFtwFunctionHeader->Data;
Status = GetFvbByAddressAndAttribute ( Status = GetFvbByAddressAndAttribute (
SmmFtwRestartHeader->FvbBaseAddress, SmmFtwRestartHeader->FvbBaseAddress,
@ -470,20 +502,25 @@ SmmFaultTolerantWriteHandler (
break; break;
case FTW_FUNCTION_GET_LAST_WRITE: case FTW_FUNCTION_GET_LAST_WRITE:
if (CommBufferPayloadSize < OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data)) {
DEBUG ((EFI_D_ERROR, "GetLastWrite: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
SmmFtwGetLastWriteHeader = (SMM_FTW_GET_LAST_WRITE_HEADER *) SmmFtwFunctionHeader->Data; SmmFtwGetLastWriteHeader = (SMM_FTW_GET_LAST_WRITE_HEADER *) SmmFtwFunctionHeader->Data;
if ((UINTN)(~0) - SmmFtwGetLastWriteHeader->PrivateDataSize < OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data)){ PrivateDataSize = SmmFtwGetLastWriteHeader->PrivateDataSize;
if ((UINTN)(~0) - PrivateDataSize < OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data)){
// //
// Prevent InfoSize overflow // Prevent InfoSize overflow
// //
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
break; break;
} }
InfoSize = OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data) + SmmFtwGetLastWriteHeader->PrivateDataSize; InfoSize = OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data) + PrivateDataSize;
// //
// SMRAM range check already covered before // SMRAM range check already covered before
// //
if (InfoSize > *CommBufferSize - SMM_FTW_COMMUNICATE_HEADER_SIZE) { if (InfoSize > CommBufferPayloadSize) {
DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n")); DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n"));
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
break; break;
@ -495,10 +532,11 @@ SmmFaultTolerantWriteHandler (
&SmmFtwGetLastWriteHeader->Lba, &SmmFtwGetLastWriteHeader->Lba,
&SmmFtwGetLastWriteHeader->Offset, &SmmFtwGetLastWriteHeader->Offset,
&SmmFtwGetLastWriteHeader->Length, &SmmFtwGetLastWriteHeader->Length,
&SmmFtwGetLastWriteHeader->PrivateDataSize, &PrivateDataSize,
(VOID *)SmmFtwGetLastWriteHeader->Data, (VOID *)SmmFtwGetLastWriteHeader->Data,
&SmmFtwGetLastWriteHeader->Complete &SmmFtwGetLastWriteHeader->Complete
); );
SmmFtwGetLastWriteHeader->PrivateDataSize = PrivateDataSize;
break; break;
default: default:
@ -532,6 +570,7 @@ FvbNotificationEvent (
EFI_STATUS Status; EFI_STATUS Status;
EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
EFI_HANDLE SmmFtwHandle; EFI_HANDLE SmmFtwHandle;
EFI_HANDLE FtwHandle;
// //
// Just return to avoid install SMM FaultTolerantWriteProtocol again // Just return to avoid install SMM FaultTolerantWriteProtocol again
@ -565,12 +604,18 @@ FvbNotificationEvent (
); );
ASSERT_EFI_ERROR (Status); ASSERT_EFI_ERROR (Status);
///
/// Register SMM FTW SMI handler
///
Status = gSmst->SmiHandlerRegister (SmmFaultTolerantWriteHandler, &gEfiSmmFaultTolerantWriteProtocolGuid, &SmmFtwHandle);
ASSERT_EFI_ERROR (Status);
// //
// Notify the Ftw wrapper driver SMM Ftw is ready // Notify the Ftw wrapper driver SMM Ftw is ready
// //
SmmFtwHandle = NULL; FtwHandle = NULL;
Status = gBS->InstallProtocolInterface ( Status = gBS->InstallProtocolInterface (
&SmmFtwHandle, &FtwHandle,
&gEfiSmmFaultTolerantWriteProtocolGuid, &gEfiSmmFaultTolerantWriteProtocolGuid,
EFI_NATIVE_INTERFACE, EFI_NATIVE_INTERFACE,
NULL NULL
@ -621,7 +666,6 @@ SmmFaultTolerantWriteInitialize (
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
EFI_HANDLE FtwHandle;
EFI_SMM_ACCESS2_PROTOCOL *SmmAccess; EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;
UINTN Size; UINTN Size;
VOID *SmmEndOfDxeRegistration; VOID *SmmEndOfDxeRegistration;
@ -678,11 +722,5 @@ SmmFaultTolerantWriteInitialize (
FvbNotificationEvent (NULL, NULL, NULL); FvbNotificationEvent (NULL, NULL, NULL);
///
/// Register SMM FTW SMI handler
///
Status = gSmst->SmiHandlerRegister (SmmFaultTolerantWriteHandler, &gEfiSmmFaultTolerantWriteProtocolGuid, &FtwHandle);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS; return EFI_SUCCESS;
} }

View File

@ -3,7 +3,7 @@
Implement the Fault Tolerant Write (FTW) protocol based on SMM FTW Implement the Fault Tolerant Write (FTW) protocol based on SMM FTW
module. module.
Copyright (c) 2011, Intel Corporation. All rights reserved. <BR> Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved. <BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
@ -463,14 +463,18 @@ FtwGetLastWrite (
// Get data from SMM // Get data from SMM
// //
*PrivateDataSize = SmmFtwGetLastWriteHeader->PrivateDataSize; *PrivateDataSize = SmmFtwGetLastWriteHeader->PrivateDataSize;
if (!EFI_ERROR (Status)) { if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
*Lba = SmmFtwGetLastWriteHeader->Lba; *Lba = SmmFtwGetLastWriteHeader->Lba;
*Offset = SmmFtwGetLastWriteHeader->Offset; *Offset = SmmFtwGetLastWriteHeader->Offset;
*Length = SmmFtwGetLastWriteHeader->Length; *Length = SmmFtwGetLastWriteHeader->Length;
*Complete = SmmFtwGetLastWriteHeader->Complete; *Complete = SmmFtwGetLastWriteHeader->Complete;
CopyGuid (CallerId, &SmmFtwGetLastWriteHeader->CallerId); CopyGuid (CallerId, &SmmFtwGetLastWriteHeader->CallerId);
if (Status == EFI_SUCCESS) {
CopyMem (PrivateData, SmmFtwGetLastWriteHeader->Data, *PrivateDataSize); CopyMem (PrivateData, SmmFtwGetLastWriteHeader->Data, *PrivateDataSize);
} }
} else if (Status == EFI_NOT_FOUND) {
*Complete = SmmFtwGetLastWriteHeader->Complete;
}
FreePool (SmmCommunicateHeader); FreePool (SmmCommunicateHeader);
return Status; return Status;

View File

@ -111,6 +111,7 @@ SmmLockBoxSave (
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
EFI_SMM_LOCK_BOX_PARAMETER_SAVE TempLockBoxParameterSave;
// //
// Sanity check // Sanity check
@ -121,10 +122,12 @@ SmmLockBoxSave (
return ; return ;
} }
CopyMem (&TempLockBoxParameterSave, LockBoxParameterSave, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_SAVE));
// //
// Sanity check // Sanity check
// //
if (!IsAddressValid ((UINTN)LockBoxParameterSave->Buffer, (UINTN)LockBoxParameterSave->Length)) { if (!IsAddressValid ((UINTN)TempLockBoxParameterSave.Buffer, (UINTN)TempLockBoxParameterSave.Length)) {
DEBUG ((EFI_D_ERROR, "SmmLockBox Save address in SMRAM or buffer overflow!\n")); DEBUG ((EFI_D_ERROR, "SmmLockBox Save address in SMRAM or buffer overflow!\n"));
LockBoxParameterSave->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED; LockBoxParameterSave->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
return ; return ;
@ -134,9 +137,9 @@ SmmLockBoxSave (
// Save data // Save data
// //
Status = SaveLockBox ( Status = SaveLockBox (
&LockBoxParameterSave->Guid, &TempLockBoxParameterSave.Guid,
(VOID *)(UINTN)LockBoxParameterSave->Buffer, (VOID *)(UINTN)TempLockBoxParameterSave.Buffer,
(UINTN)LockBoxParameterSave->Length (UINTN)TempLockBoxParameterSave.Length
); );
LockBoxParameterSave->Header.ReturnStatus = (UINT64)Status; LockBoxParameterSave->Header.ReturnStatus = (UINT64)Status;
return ; return ;
@ -153,6 +156,7 @@ SmmLockBoxSetAttributes (
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES TempLockBoxParameterSetAttributes;
// //
// Sanity check // Sanity check
@ -163,12 +167,14 @@ SmmLockBoxSetAttributes (
return ; return ;
} }
CopyMem (&TempLockBoxParameterSetAttributes, LockBoxParameterSetAttributes, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES));
// //
// Update data // Update data
// //
Status = SetLockBoxAttributes ( Status = SetLockBoxAttributes (
&LockBoxParameterSetAttributes->Guid, &TempLockBoxParameterSetAttributes.Guid,
LockBoxParameterSetAttributes->Attributes TempLockBoxParameterSetAttributes.Attributes
); );
LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)Status; LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)Status;
return ; return ;
@ -189,6 +195,7 @@ SmmLockBoxUpdate (
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
EFI_SMM_LOCK_BOX_PARAMETER_UPDATE TempLockBoxParameterUpdate;
// //
// Sanity check // Sanity check
@ -199,10 +206,12 @@ SmmLockBoxUpdate (
return ; return ;
} }
CopyMem (&TempLockBoxParameterUpdate, LockBoxParameterUpdate, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_UPDATE));
// //
// Sanity check // Sanity check
// //
if (!IsAddressValid ((UINTN)LockBoxParameterUpdate->Buffer, (UINTN)LockBoxParameterUpdate->Length)) { if (!IsAddressValid ((UINTN)TempLockBoxParameterUpdate.Buffer, (UINTN)TempLockBoxParameterUpdate.Length)) {
DEBUG ((EFI_D_ERROR, "SmmLockBox Update address in SMRAM or buffer overflow!\n")); DEBUG ((EFI_D_ERROR, "SmmLockBox Update address in SMRAM or buffer overflow!\n"));
LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED; LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
return ; return ;
@ -212,10 +221,10 @@ SmmLockBoxUpdate (
// Update data // Update data
// //
Status = UpdateLockBox ( Status = UpdateLockBox (
&LockBoxParameterUpdate->Guid, &TempLockBoxParameterUpdate.Guid,
(UINTN)LockBoxParameterUpdate->Offset, (UINTN)TempLockBoxParameterUpdate.Offset,
(VOID *)(UINTN)LockBoxParameterUpdate->Buffer, (VOID *)(UINTN)TempLockBoxParameterUpdate.Buffer,
(UINTN)LockBoxParameterUpdate->Length (UINTN)TempLockBoxParameterUpdate.Length
); );
LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)Status; LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)Status;
return ; return ;
@ -236,11 +245,14 @@ SmmLockBoxRestore (
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
EFI_SMM_LOCK_BOX_PARAMETER_RESTORE TempLockBoxParameterRestore;
CopyMem (&TempLockBoxParameterRestore, LockBoxParameterRestore, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE));
// //
// Sanity check // Sanity check
// //
if (!IsAddressValid ((UINTN)LockBoxParameterRestore->Buffer, (UINTN)LockBoxParameterRestore->Length)) { if (!IsAddressValid ((UINTN)TempLockBoxParameterRestore.Buffer, (UINTN)TempLockBoxParameterRestore.Length)) {
DEBUG ((EFI_D_ERROR, "SmmLockBox Restore address in SMRAM or buffer overflow!\n")); DEBUG ((EFI_D_ERROR, "SmmLockBox Restore address in SMRAM or buffer overflow!\n"));
LockBoxParameterRestore->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED; LockBoxParameterRestore->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
return ; return ;
@ -249,17 +261,17 @@ SmmLockBoxRestore (
// //
// Restore data // Restore data
// //
if ((LockBoxParameterRestore->Length == 0) && (LockBoxParameterRestore->Buffer == 0)) { if ((TempLockBoxParameterRestore.Length == 0) && (TempLockBoxParameterRestore.Buffer == 0)) {
Status = RestoreLockBox ( Status = RestoreLockBox (
&LockBoxParameterRestore->Guid, &TempLockBoxParameterRestore.Guid,
NULL, NULL,
NULL NULL
); );
} else { } else {
Status = RestoreLockBox ( Status = RestoreLockBox (
&LockBoxParameterRestore->Guid, &TempLockBoxParameterRestore.Guid,
(VOID *)(UINTN)LockBoxParameterRestore->Buffer, (VOID *)(UINTN)TempLockBoxParameterRestore.Buffer,
(UINTN *)&LockBoxParameterRestore->Length (UINTN *)&TempLockBoxParameterRestore.Length
); );
} }
LockBoxParameterRestore->Header.ReturnStatus = (UINT64)Status; LockBoxParameterRestore->Header.ReturnStatus = (UINT64)Status;

View File

@ -15,7 +15,7 @@
VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(), VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
SmmVariableGetStatistics() should also do validation based on its own knowledge. SmmVariableGetStatistics() should also do validation based on its own knowledge.
Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR> Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
@ -44,6 +44,8 @@ EFI_HANDLE mSmmVariableHandle = N
EFI_HANDLE mVariableHandle = NULL; EFI_HANDLE mVariableHandle = NULL;
BOOLEAN mAtRuntime = FALSE; BOOLEAN mAtRuntime = FALSE;
EFI_GUID mZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; EFI_GUID mZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
UINT8 *mVariableBufferPayload = NULL;
UINTN mVariableBufferPayloadSize;
EFI_SMM_VARIABLE_PROTOCOL gSmmVariable = { EFI_SMM_VARIABLE_PROTOCOL gSmmVariable = {
VariableServiceGetVariable, VariableServiceGetVariable,
@ -302,6 +304,8 @@ GetFvbCountAndBuffer (
*NumberHandles = BufferSize / sizeof(EFI_HANDLE); *NumberHandles = BufferSize / sizeof(EFI_HANDLE);
if (EFI_ERROR(Status)) { if (EFI_ERROR(Status)) {
*NumberHandles = 0; *NumberHandles = 0;
FreePool (*Buffer);
*Buffer = NULL;
} }
return Status; return Status;
@ -337,6 +341,7 @@ SmmVariableGetStatistics (
UINTN NameLength; UINTN NameLength;
UINTN StatisticsInfoSize; UINTN StatisticsInfoSize;
CHAR16 *InfoName; CHAR16 *InfoName;
EFI_GUID VendorGuid;
ASSERT (InfoEntry != NULL); ASSERT (InfoEntry != NULL);
VariableInfo = gVariableInfo; VariableInfo = gVariableInfo;
@ -351,7 +356,9 @@ SmmVariableGetStatistics (
} }
InfoName = (CHAR16 *)(InfoEntry + 1); InfoName = (CHAR16 *)(InfoEntry + 1);
if (CompareGuid (&InfoEntry->VendorGuid, &mZeroGuid)) { CopyGuid (&VendorGuid, &InfoEntry->VendorGuid);
if (CompareGuid (&VendorGuid, &mZeroGuid)) {
// //
// Return the first variable info // Return the first variable info
// //
@ -365,7 +372,7 @@ SmmVariableGetStatistics (
// Get the next variable info // Get the next variable info
// //
while (VariableInfo != NULL) { while (VariableInfo != NULL) {
if (CompareGuid (&VariableInfo->VendorGuid, &InfoEntry->VendorGuid)) { if (CompareGuid (&VariableInfo->VendorGuid, &VendorGuid)) {
NameLength = StrSize (VariableInfo->Name); NameLength = StrSize (VariableInfo->Name);
if (NameLength == StrSize (InfoName)) { if (NameLength == StrSize (InfoName)) {
if (CompareMem (VariableInfo->Name, InfoName, NameLength) == 0) { if (CompareMem (VariableInfo->Name, InfoName, NameLength) == 0) {
@ -445,6 +452,7 @@ SmmVariableHandler (
VARIABLE_INFO_ENTRY *VariableInfo; VARIABLE_INFO_ENTRY *VariableInfo;
UINTN InfoSize; UINTN InfoSize;
UINTN NameBufferSize; UINTN NameBufferSize;
UINTN CommBufferPayloadSize;
// //
// If input is invalid, stop processing this SMI // If input is invalid, stop processing this SMI
@ -454,18 +462,32 @@ SmmVariableHandler (
} }
if (*CommBufferSize < SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { if (*CommBufferSize < SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
CommBufferPayloadSize = *CommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
if (CommBufferPayloadSize > mVariableBufferPayloadSize) {
DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer payload size invalid!\n"));
return EFI_SUCCESS; return EFI_SUCCESS;
} }
if (!InternalIsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) { if (!InternalIsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) {
DEBUG ((EFI_D_ERROR, "SMM communication buffer in SMRAM or overflow!\n")); DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer in SMRAM or overflow!\n"));
return EFI_SUCCESS; return EFI_SUCCESS;
} }
SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)CommBuffer; SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)CommBuffer;
switch (SmmVariableFunctionHeader->Function) { switch (SmmVariableFunctionHeader->Function) {
case SMM_VARIABLE_FUNCTION_GET_VARIABLE: case SMM_VARIABLE_FUNCTION_GET_VARIABLE:
SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) SmmVariableFunctionHeader->Data; if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
DEBUG ((EFI_D_ERROR, "GetVariable: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
//
// Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
//
CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) mVariableBufferPayload;
if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) || if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) { ((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) {
// //
@ -480,8 +502,8 @@ SmmVariableHandler (
// //
// SMRAM range check already covered before // SMRAM range check already covered before
// //
if (InfoSize > *CommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { if (InfoSize > CommBufferPayloadSize) {
DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n")); DEBUG ((EFI_D_ERROR, "GetVariable: Data size exceed communication buffer size limit!\n"));
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
goto EXIT; goto EXIT;
} }
@ -501,10 +523,19 @@ SmmVariableHandler (
&SmmVariableHeader->DataSize, &SmmVariableHeader->DataSize,
(UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize
); );
CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
break; break;
case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME: case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME:
GetNextVariableName = (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) SmmVariableFunctionHeader->Data; if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
DEBUG ((EFI_D_ERROR, "GetNextVariableName: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
//
// Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
//
CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
GetNextVariableName = (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) mVariableBufferPayload;
if ((UINTN)(~0) - GetNextVariableName->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) { if ((UINTN)(~0) - GetNextVariableName->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
// //
// Prevent InfoSize overflow happen // Prevent InfoSize overflow happen
@ -517,13 +548,13 @@ SmmVariableHandler (
// //
// SMRAM range check already covered before // SMRAM range check already covered before
// //
if (InfoSize > *CommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { if (InfoSize > CommBufferPayloadSize) {
DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n")); DEBUG ((EFI_D_ERROR, "GetNextVariableName: Data size exceed communication buffer size limit!\n"));
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
goto EXIT; goto EXIT;
} }
NameBufferSize = *CommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE - OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name); NameBufferSize = CommBufferPayloadSize - OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
if (NameBufferSize < sizeof (CHAR16) || GetNextVariableName->Name[NameBufferSize/sizeof (CHAR16) - 1] != L'\0') { if (NameBufferSize < sizeof (CHAR16) || GetNextVariableName->Name[NameBufferSize/sizeof (CHAR16) - 1] != L'\0') {
// //
// Make sure input VariableName is A Null-terminated string. // Make sure input VariableName is A Null-terminated string.
@ -537,10 +568,19 @@ SmmVariableHandler (
GetNextVariableName->Name, GetNextVariableName->Name,
&GetNextVariableName->Guid &GetNextVariableName->Guid
); );
CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
break; break;
case SMM_VARIABLE_FUNCTION_SET_VARIABLE: case SMM_VARIABLE_FUNCTION_SET_VARIABLE:
SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) SmmVariableFunctionHeader->Data; if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
DEBUG ((EFI_D_ERROR, "SetVariable: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
//
// Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
//
CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) mVariableBufferPayload;
if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) || if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) { ((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) {
// //
@ -556,8 +596,8 @@ SmmVariableHandler (
// SMRAM range check already covered before // SMRAM range check already covered before
// Data buffer should not contain SMM range // Data buffer should not contain SMM range
// //
if (InfoSize > *CommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { if (InfoSize > CommBufferPayloadSize) {
DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n")); DEBUG ((EFI_D_ERROR, "SetVariable: Data size exceed communication buffer size limit!\n"));
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
goto EXIT; goto EXIT;
} }
@ -580,17 +620,11 @@ SmmVariableHandler (
break; break;
case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO: case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO:
QueryVariableInfo = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *) SmmVariableFunctionHeader->Data; if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO)) {
InfoSize = sizeof(SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO); DEBUG ((EFI_D_ERROR, "QueryVariableInfo: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
//
// SMRAM range check already covered before
//
if (InfoSize > *CommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n"));
Status = EFI_ACCESS_DENIED;
goto EXIT;
} }
QueryVariableInfo = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *) SmmVariableFunctionHeader->Data;
Status = VariableServiceQueryVariableInfo ( Status = VariableServiceQueryVariableInfo (
QueryVariableInfo->Attributes, QueryVariableInfo->Attributes,
@ -624,7 +658,7 @@ SmmVariableHandler (
// //
if (InternalIsAddressInSmram ((EFI_PHYSICAL_ADDRESS)(UINTN)CommBufferSize, sizeof(UINTN))) { if (InternalIsAddressInSmram ((EFI_PHYSICAL_ADDRESS)(UINTN)CommBufferSize, sizeof(UINTN))) {
DEBUG ((EFI_D_ERROR, "SMM communication buffer in SMRAM!\n")); DEBUG ((EFI_D_ERROR, "GetStatistics: SMM communication buffer in SMRAM!\n"));
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
goto EXIT; goto EXIT;
} }
@ -781,6 +815,16 @@ VariableServiceInitialize (
mSmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR); mSmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
mVariableBufferPayloadSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) +
OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - sizeof (VARIABLE_HEADER);
Status = gSmst->SmmAllocatePool (
EfiRuntimeServicesData,
mVariableBufferPayloadSize,
(VOID **)&mVariableBufferPayload
);
ASSERT_EFI_ERROR (Status);
/// ///
/// Register SMM variable SMI handler /// Register SMM variable SMI handler
/// ///

View File

@ -42,6 +42,7 @@ EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
UINT8 *mVariableBuffer = NULL; UINT8 *mVariableBuffer = NULL;
UINT8 *mVariableBufferPhysical = NULL; UINT8 *mVariableBufferPhysical = NULL;
UINTN mVariableBufferSize; UINTN mVariableBufferSize;
UINTN mVariableBufferPayloadSize;
EFI_LOCK mVariableServicesLock; EFI_LOCK mVariableServicesLock;
/** /**
@ -189,7 +190,6 @@ RuntimeServiceGetVariable (
EFI_STATUS Status; EFI_STATUS Status;
UINTN PayloadSize; UINTN PayloadSize;
SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader; SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
UINTN SmmCommBufPayloadSize;
UINTN TempDataSize; UINTN TempDataSize;
UINTN VariableNameSize; UINTN VariableNameSize;
@ -201,17 +201,13 @@ RuntimeServiceGetVariable (
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
//
// SMM Communication Buffer max payload size
//
SmmCommBufPayloadSize = mVariableBufferSize - (SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE);
TempDataSize = *DataSize; TempDataSize = *DataSize;
VariableNameSize = StrSize (VariableName); VariableNameSize = StrSize (VariableName);
// //
// If VariableName exceeds SMM payload limit. Return failure // If VariableName exceeds SMM payload limit. Return failure
// //
if (VariableNameSize > SmmCommBufPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) { if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
@ -221,11 +217,11 @@ RuntimeServiceGetVariable (
// Init the communicate buffer. The buffer data size is: // Init the communicate buffer. The buffer data size is:
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
// //
if (TempDataSize > SmmCommBufPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) { if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {
// //
// If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
// //
TempDataSize = SmmCommBufPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize; TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;
} }
PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize; PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;
@ -300,7 +296,6 @@ RuntimeServiceGetNextVariableName (
EFI_STATUS Status; EFI_STATUS Status;
UINTN PayloadSize; UINTN PayloadSize;
SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName; SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;
UINTN SmmCommBufPayloadSize;
UINTN OutVariableNameSize; UINTN OutVariableNameSize;
UINTN InVariableNameSize; UINTN InVariableNameSize;
@ -308,17 +303,13 @@ RuntimeServiceGetNextVariableName (
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
//
// SMM Communication Buffer max payload size
//
SmmCommBufPayloadSize = mVariableBufferSize - (SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE);
OutVariableNameSize = *VariableNameSize; OutVariableNameSize = *VariableNameSize;
InVariableNameSize = StrSize (VariableName); InVariableNameSize = StrSize (VariableName);
// //
// If input string exceeds SMM payload limit. Return failure // If input string exceeds SMM payload limit. Return failure
// //
if (InVariableNameSize > SmmCommBufPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) { if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
@ -328,11 +319,11 @@ RuntimeServiceGetNextVariableName (
// Init the communicate buffer. The buffer data size is: // Init the communicate buffer. The buffer data size is:
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
// //
if (OutVariableNameSize > SmmCommBufPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) { if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
// //
// If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
// //
OutVariableNameSize = SmmCommBufPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name); OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
} }
// //
// Payload should be Guid + NameSize + MAX of Input & Output buffer // Payload should be Guid + NameSize + MAX of Input & Output buffer
@ -430,21 +421,13 @@ RuntimeServiceSetVariable (
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
if (DataSize >= mVariableBufferSize) {
//
// DataSize may be near MAX_ADDRESS incorrectly, this can cause the computed PayLoadSize to
// overflow to a small value and pass the check in InitCommunicateBuffer().
// To protect against this vulnerability, return EFI_INVALID_PARAMETER if DataSize is >= mVariableBufferSize.
// And there will be further check to ensure the total size is also not > mVariableBufferSize.
//
return EFI_INVALID_PARAMETER;
}
VariableNameSize = StrSize (VariableName); VariableNameSize = StrSize (VariableName);
if ((UINTN)(~0) - VariableNameSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + DataSize) {
// //
// Prevent PayloadSize overflow // If VariableName or DataSize exceeds SMM payload limit. Return failure
// //
if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
(DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
@ -654,10 +637,11 @@ SmmVariableReady (
ASSERT_EFI_ERROR (Status); ASSERT_EFI_ERROR (Status);
// //
// Allocate memory for variable store. // Allocate memory for variable communicate buffer.
// //
mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE; mVariableBufferPayloadSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) +
mVariableBufferSize += MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)); OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - sizeof (VARIABLE_HEADER);
mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;
mVariableBuffer = AllocateRuntimePool (mVariableBufferSize); mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);
ASSERT (mVariableBuffer != NULL); ASSERT (mVariableBuffer != NULL);

View File

@ -14,7 +14,7 @@
VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(), VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
SmmVariableGetStatistics() should also do validation based on its own knowledge. SmmVariableGetStatistics() should also do validation based on its own knowledge.
Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR> Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
@ -44,6 +44,8 @@ EFI_HANDLE mSmmVariableHandle = N
EFI_HANDLE mVariableHandle = NULL; EFI_HANDLE mVariableHandle = NULL;
BOOLEAN mAtRuntime = FALSE; BOOLEAN mAtRuntime = FALSE;
EFI_GUID mZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; EFI_GUID mZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
UINT8 *mVariableBufferPayload = NULL;
UINTN mVariableBufferPayloadSize;
EFI_SMM_VARIABLE_PROTOCOL gSmmVariable = { EFI_SMM_VARIABLE_PROTOCOL gSmmVariable = {
VariableServiceGetVariable, VariableServiceGetVariable,
@ -302,6 +304,8 @@ GetFvbCountAndBuffer (
*NumberHandles = BufferSize / sizeof(EFI_HANDLE); *NumberHandles = BufferSize / sizeof(EFI_HANDLE);
if (EFI_ERROR(Status)) { if (EFI_ERROR(Status)) {
*NumberHandles = 0; *NumberHandles = 0;
FreePool (*Buffer);
*Buffer = NULL;
} }
return Status; return Status;
@ -338,6 +342,7 @@ SmmVariableGetStatistics (
UINTN NameLength; UINTN NameLength;
UINTN StatisticsInfoSize; UINTN StatisticsInfoSize;
CHAR16 *InfoName; CHAR16 *InfoName;
EFI_GUID VendorGuid;
if (InfoEntry == NULL) { if (InfoEntry == NULL) {
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
@ -355,7 +360,9 @@ SmmVariableGetStatistics (
} }
InfoName = (CHAR16 *)(InfoEntry + 1); InfoName = (CHAR16 *)(InfoEntry + 1);
if (CompareGuid (&InfoEntry->VendorGuid, &mZeroGuid)) { CopyGuid (&VendorGuid, &InfoEntry->VendorGuid);
if (CompareGuid (&VendorGuid, &mZeroGuid)) {
// //
// Return the first variable info // Return the first variable info
// //
@ -369,7 +376,7 @@ SmmVariableGetStatistics (
// Get the next variable info // Get the next variable info
// //
while (VariableInfo != NULL) { while (VariableInfo != NULL) {
if (CompareGuid (&VariableInfo->VendorGuid, &InfoEntry->VendorGuid)) { if (CompareGuid (&VariableInfo->VendorGuid, &VendorGuid)) {
NameLength = StrSize (VariableInfo->Name); NameLength = StrSize (VariableInfo->Name);
if (NameLength == StrSize (InfoName)) { if (NameLength == StrSize (InfoName)) {
if (CompareMem (VariableInfo->Name, InfoName, NameLength) == 0) { if (CompareMem (VariableInfo->Name, InfoName, NameLength) == 0) {
@ -450,6 +457,7 @@ SmmVariableHandler (
VARIABLE_INFO_ENTRY *VariableInfo; VARIABLE_INFO_ENTRY *VariableInfo;
UINTN InfoSize; UINTN InfoSize;
UINTN NameBufferSize; UINTN NameBufferSize;
UINTN CommBufferPayloadSize;
// //
// If input is invalid, stop processing this SMI // If input is invalid, stop processing this SMI
@ -459,11 +467,17 @@ SmmVariableHandler (
} }
if (*CommBufferSize < SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { if (*CommBufferSize < SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
CommBufferPayloadSize = *CommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
if (CommBufferPayloadSize > mVariableBufferPayloadSize) {
DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer payload size invalid!\n"));
return EFI_SUCCESS; return EFI_SUCCESS;
} }
if (!InternalIsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) { if (!InternalIsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) {
DEBUG ((EFI_D_ERROR, "SMM communication buffer in SMRAM or overflow!\n")); DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer in SMRAM or overflow!\n"));
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -471,7 +485,15 @@ SmmVariableHandler (
switch (SmmVariableFunctionHeader->Function) { switch (SmmVariableFunctionHeader->Function) {
case SMM_VARIABLE_FUNCTION_GET_VARIABLE: case SMM_VARIABLE_FUNCTION_GET_VARIABLE:
SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) SmmVariableFunctionHeader->Data; if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
DEBUG ((EFI_D_ERROR, "GetVariable: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
//
// Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
//
CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) mVariableBufferPayload;
if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) || if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) { ((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) {
// //
@ -486,8 +508,8 @@ SmmVariableHandler (
// //
// SMRAM range check already covered before // SMRAM range check already covered before
// //
if (InfoSize > *CommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { if (InfoSize > CommBufferPayloadSize) {
DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n")); DEBUG ((EFI_D_ERROR, "GetVariable: Data size exceed communication buffer size limit!\n"));
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
goto EXIT; goto EXIT;
} }
@ -507,10 +529,19 @@ SmmVariableHandler (
&SmmVariableHeader->DataSize, &SmmVariableHeader->DataSize,
(UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize
); );
CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
break; break;
case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME: case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME:
GetNextVariableName = (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) SmmVariableFunctionHeader->Data; if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
DEBUG ((EFI_D_ERROR, "GetNextVariableName: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
//
// Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
//
CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
GetNextVariableName = (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) mVariableBufferPayload;
if ((UINTN)(~0) - GetNextVariableName->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) { if ((UINTN)(~0) - GetNextVariableName->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
// //
// Prevent InfoSize overflow happen // Prevent InfoSize overflow happen
@ -523,13 +554,13 @@ SmmVariableHandler (
// //
// SMRAM range check already covered before // SMRAM range check already covered before
// //
if (InfoSize > *CommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { if (InfoSize > CommBufferPayloadSize) {
DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n")); DEBUG ((EFI_D_ERROR, "GetNextVariableName: Data size exceed communication buffer size limit!\n"));
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
goto EXIT; goto EXIT;
} }
NameBufferSize = *CommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE - OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name); NameBufferSize = CommBufferPayloadSize - OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
if (NameBufferSize < sizeof (CHAR16) || GetNextVariableName->Name[NameBufferSize/sizeof (CHAR16) - 1] != L'\0') { if (NameBufferSize < sizeof (CHAR16) || GetNextVariableName->Name[NameBufferSize/sizeof (CHAR16) - 1] != L'\0') {
// //
// Make sure input VariableName is A Null-terminated string. // Make sure input VariableName is A Null-terminated string.
@ -543,10 +574,19 @@ SmmVariableHandler (
GetNextVariableName->Name, GetNextVariableName->Name,
&GetNextVariableName->Guid &GetNextVariableName->Guid
); );
CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
break; break;
case SMM_VARIABLE_FUNCTION_SET_VARIABLE: case SMM_VARIABLE_FUNCTION_SET_VARIABLE:
SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) SmmVariableFunctionHeader->Data; if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
DEBUG ((EFI_D_ERROR, "SetVariable: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
//
// Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
//
CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) mVariableBufferPayload;
if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) || if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) { ((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) {
// //
@ -562,8 +602,8 @@ SmmVariableHandler (
// SMRAM range check already covered before // SMRAM range check already covered before
// Data buffer should not contain SMM range // Data buffer should not contain SMM range
// //
if (InfoSize > *CommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { if (InfoSize > CommBufferPayloadSize) {
DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n")); DEBUG ((EFI_D_ERROR, "SetVariable: Data size exceed communication buffer size limit!\n"));
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
goto EXIT; goto EXIT;
} }
@ -586,17 +626,11 @@ SmmVariableHandler (
break; break;
case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO: case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO:
QueryVariableInfo = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *) SmmVariableFunctionHeader->Data; if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO)) {
InfoSize = sizeof(SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO); DEBUG ((EFI_D_ERROR, "QueryVariableInfo: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
//
// SMRAM range check already covered before
//
if (InfoSize > *CommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n"));
Status = EFI_ACCESS_DENIED;
goto EXIT;
} }
QueryVariableInfo = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *) SmmVariableFunctionHeader->Data;
Status = VariableServiceQueryVariableInfo ( Status = VariableServiceQueryVariableInfo (
QueryVariableInfo->Attributes, QueryVariableInfo->Attributes,
@ -630,7 +664,7 @@ SmmVariableHandler (
// //
if (InternalIsAddressInSmram ((EFI_PHYSICAL_ADDRESS)(UINTN)CommBufferSize, sizeof(UINTN))) { if (InternalIsAddressInSmram ((EFI_PHYSICAL_ADDRESS)(UINTN)CommBufferSize, sizeof(UINTN))) {
DEBUG ((EFI_D_ERROR, "SMM communication buffer in SMRAM!\n")); DEBUG ((EFI_D_ERROR, "GetStatistics: SMM communication buffer in SMRAM!\n"));
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
goto EXIT; goto EXIT;
} }
@ -786,6 +820,16 @@ VariableServiceInitialize (
mSmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR); mSmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
mVariableBufferPayloadSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) +
OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - sizeof (VARIABLE_HEADER);
Status = gSmst->SmmAllocatePool (
EfiRuntimeServicesData,
mVariableBufferPayloadSize,
(VOID **)&mVariableBufferPayload
);
ASSERT_EFI_ERROR (Status);
/// ///
/// Register SMM variable SMI handler /// Register SMM variable SMI handler
/// ///

View File

@ -52,6 +52,7 @@ EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
UINT8 *mVariableBuffer = NULL; UINT8 *mVariableBuffer = NULL;
UINT8 *mVariableBufferPhysical = NULL; UINT8 *mVariableBufferPhysical = NULL;
UINTN mVariableBufferSize; UINTN mVariableBufferSize;
UINTN mVariableBufferPayloadSize;
EFI_LOCK mVariableServicesLock; EFI_LOCK mVariableServicesLock;
/** /**
@ -205,7 +206,6 @@ RuntimeServiceGetVariable (
EFI_STATUS Status; EFI_STATUS Status;
UINTN PayloadSize; UINTN PayloadSize;
SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader; SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
UINTN SmmCommBufPayloadSize;
UINTN TempDataSize; UINTN TempDataSize;
UINTN VariableNameSize; UINTN VariableNameSize;
@ -217,17 +217,13 @@ RuntimeServiceGetVariable (
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
//
// SMM Communication Buffer max payload size
//
SmmCommBufPayloadSize = mVariableBufferSize - (SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE);
TempDataSize = *DataSize; TempDataSize = *DataSize;
VariableNameSize = StrSize (VariableName); VariableNameSize = StrSize (VariableName);
// //
// If VariableName exceeds SMM payload limit. Return failure // If VariableName exceeds SMM payload limit. Return failure
// //
if (VariableNameSize > SmmCommBufPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) { if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
@ -237,11 +233,11 @@ RuntimeServiceGetVariable (
// Init the communicate buffer. The buffer data size is: // Init the communicate buffer. The buffer data size is:
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
// //
if (TempDataSize > SmmCommBufPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) { if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {
// //
// If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
// //
TempDataSize = SmmCommBufPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize; TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;
} }
PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize; PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;
@ -316,7 +312,6 @@ RuntimeServiceGetNextVariableName (
EFI_STATUS Status; EFI_STATUS Status;
UINTN PayloadSize; UINTN PayloadSize;
SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName; SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;
UINTN SmmCommBufPayloadSize;
UINTN OutVariableNameSize; UINTN OutVariableNameSize;
UINTN InVariableNameSize; UINTN InVariableNameSize;
@ -324,17 +319,13 @@ RuntimeServiceGetNextVariableName (
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
//
// SMM Communication Buffer max payload size
//
SmmCommBufPayloadSize = mVariableBufferSize - (SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE);
OutVariableNameSize = *VariableNameSize; OutVariableNameSize = *VariableNameSize;
InVariableNameSize = StrSize (VariableName); InVariableNameSize = StrSize (VariableName);
// //
// If input string exceeds SMM payload limit. Return failure // If input string exceeds SMM payload limit. Return failure
// //
if (InVariableNameSize > SmmCommBufPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) { if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
@ -344,11 +335,11 @@ RuntimeServiceGetNextVariableName (
// Init the communicate buffer. The buffer data size is: // Init the communicate buffer. The buffer data size is:
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
// //
if (OutVariableNameSize > SmmCommBufPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) { if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
// //
// If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
// //
OutVariableNameSize = SmmCommBufPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name); OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
} }
// //
// Payload should be Guid + NameSize + MAX of Input & Output buffer // Payload should be Guid + NameSize + MAX of Input & Output buffer
@ -448,21 +439,13 @@ RuntimeServiceSetVariable (
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
if (DataSize >= mVariableBufferSize) {
//
// DataSize may be near MAX_ADDRESS incorrectly, this can cause the computed PayLoadSize to
// overflow to a small value and pass the check in InitCommunicateBuffer().
// To protect against this vulnerability, return EFI_INVALID_PARAMETER if DataSize is >= mVariableBufferSize.
// And there will be further check to ensure the total size is also not > mVariableBufferSize.
//
return EFI_INVALID_PARAMETER;
}
VariableNameSize = StrSize (VariableName); VariableNameSize = StrSize (VariableName);
if ((UINTN)(~0) - VariableNameSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + DataSize) {
// //
// Prevent PayloadSize overflow // If VariableName or DataSize exceeds SMM payload limit. Return failure
// //
if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
(DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
@ -672,10 +655,11 @@ SmmVariableReady (
ASSERT_EFI_ERROR (Status); ASSERT_EFI_ERROR (Status);
// //
// Allocate memory for variable store. // Allocate memory for variable communicate buffer.
// //
mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE; mVariableBufferPayloadSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) +
mVariableBufferSize += MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)); OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - sizeof (VARIABLE_HEADER);
mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;
mVariableBuffer = AllocateRuntimePool (mVariableBufferSize); mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);
ASSERT (mVariableBuffer != NULL); ASSERT (mVariableBuffer != NULL);