This module registers report status code listener to collect performance data\r
for SMM driver boot records and S3 Suspend Performance Record.\r
\r
- Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
+ Caution: This module requires additional review when modified.\r
+ This driver will have external input - communicate buffer in SMM mode.\r
+ This external input must be validated carefully to avoid security issue like\r
+ buffer overflow, integer overflow.\r
\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ FpdtSmiHandler() will receive untrusted input and do basic validation.\r
+\r
+ Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include <PiSmm.h>\r
\r
-#include <IndustryStandard/Acpi50.h>\r
-\r
#include <Protocol/SmmReportStatusCodeHandler.h>\r
-#include <Protocol/SmmAccess2.h>\r
\r
#include <Guid/FirmwarePerformance.h>\r
\r
#include <Library/MemoryAllocationLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
#include <Library/SynchronizationLib.h>\r
+#include <Library/SmmMemLib.h>\r
\r
-#define EXTENSION_RECORD_SIZE 0x1000\r
+SMM_BOOT_PERFORMANCE_TABLE *mSmmBootPerformanceTable = NULL;\r
\r
EFI_SMM_RSC_HANDLER_PROTOCOL *mRscHandlerProtocol = NULL;\r
UINT64 mSuspendStartTime = 0;\r
BOOLEAN mS3SuspendLockBoxSaved = FALSE;\r
UINT32 mBootRecordSize = 0;\r
-UINT32 mBootRecordMaxSize = 0;\r
UINT8 *mBootRecordBuffer = NULL;\r
\r
-EFI_SMRAM_DESCRIPTOR *mSmramRanges;\r
-UINTN mSmramRangeCount;\r
SPIN_LOCK mSmmFpdtLock;\r
BOOLEAN mSmramIsOutOfResource = FALSE;\r
\r
EFI_STATUS Status;\r
UINT64 CurrentTime;\r
EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD S3SuspendRecord;\r
- UINT8 *NewRecordBuffer;\r
\r
//\r
// Check whether status code is what we are interested in.\r
if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) {\r
return EFI_UNSUPPORTED;\r
}\r
- \r
+\r
//\r
// Collect one or more Boot records in boot time\r
//\r
- if (Data != NULL && CompareGuid (&Data->Type, &gEfiFirmwarePerformanceGuid)) {\r
+ if (Data != NULL && CompareGuid (&Data->Type, &gEdkiiFpdtExtendedFirmwarePerformanceGuid)) {\r
AcquireSpinLock (&mSmmFpdtLock);\r
- \r
- if (mBootRecordSize + Data->Size > mBootRecordMaxSize) {\r
- //\r
- // Try to allocate big SMRAM data to store Boot record. \r
- //\r
- if (mSmramIsOutOfResource) {\r
- ReleaseSpinLock (&mSmmFpdtLock);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- NewRecordBuffer = ReallocatePool (mBootRecordSize, mBootRecordSize + Data->Size + EXTENSION_RECORD_SIZE, mBootRecordBuffer); \r
- if (NewRecordBuffer == NULL) {\r
- ReleaseSpinLock (&mSmmFpdtLock);\r
- mSmramIsOutOfResource = TRUE;\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- mBootRecordBuffer = NewRecordBuffer;\r
- mBootRecordMaxSize = mBootRecordSize + Data->Size + EXTENSION_RECORD_SIZE;\r
- }\r
//\r
- // Save boot record into the temp memory space.\r
+ // Get the boot performance data.\r
//\r
- CopyMem (mBootRecordBuffer + mBootRecordSize, Data + 1, Data->Size);\r
- mBootRecordSize += Data->Size;\r
- \r
+ CopyMem (&mSmmBootPerformanceTable, Data + 1, Data->Size);\r
+ mBootRecordBuffer = ((UINT8 *) (mSmmBootPerformanceTable)) + sizeof (SMM_BOOT_PERFORMANCE_TABLE);\r
+\r
ReleaseSpinLock (&mSmmFpdtLock);\r
return EFI_SUCCESS;\r
}\r
\r
+ if (Data != NULL && CompareGuid (&Data->Type, &gEfiFirmwarePerformanceGuid)) {\r
+ DEBUG ((DEBUG_ERROR, "FpdtStatusCodeListenerSmm: Performance data reported through gEfiFirmwarePerformanceGuid will not be collected by FirmwarePerformanceDataTableSmm\n"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
if ((Value != PcdGet32 (PcdProgressCodeS3SuspendStart)) &&\r
(Value != PcdGet32 (PcdProgressCodeS3SuspendEnd))) {\r
return EFI_UNSUPPORTED;\r
return EFI_SUCCESS;\r
}\r
\r
-/**\r
- This function check if the address is in SMRAM.\r
-\r
- @param Buffer the buffer address to be checked.\r
- @param Length the buffer length to be checked.\r
-\r
- @retval TRUE this address is in SMRAM.\r
- @retval FALSE this address is NOT in SMRAM.\r
-**/\r
-BOOLEAN\r
-InternalIsAddressInSmram (\r
- IN EFI_PHYSICAL_ADDRESS Buffer,\r
- IN UINT64 Length\r
- )\r
-{\r
- UINTN Index;\r
-\r
- for (Index = 0; Index < mSmramRangeCount; Index ++) {\r
- if (((Buffer >= mSmramRanges[Index].CpuStart) && (Buffer < mSmramRanges[Index].CpuStart + mSmramRanges[Index].PhysicalSize)) ||\r
- ((mSmramRanges[Index].CpuStart >= Buffer) && (mSmramRanges[Index].CpuStart < Buffer + Length))) {\r
- return TRUE;\r
- }\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
/**\r
Communication service SMI Handler entry.\r
\r
- This SMI handler provides services for report SMM boot records. \r
+ This SMI handler provides services for report SMM boot records.\r
+\r
+ Caution: This function may receive untrusted input.\r
+ Communicate buffer and buffer size are external input, so this function will do basic validation.\r
\r
@param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
@param[in] RegisterContext Points to an optional handler context which was specified when the\r
be conveyed from a non-SMM environment into an SMM environment.\r
@param[in, out] CommBufferSize The size of the CommBuffer.\r
\r
- @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers should still be called.\r
- @retval EFI_INVALID_PARAMETER The interrupt parameter is not valid. \r
- @retval EFI_ACCESS_DENIED The interrupt buffer can't be written. \r
- @retval EFI_UNSUPPORTED The interrupt is not supported. \r
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers\r
+ should still be called.\r
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should\r
+ still be called.\r
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still\r
+ be called.\r
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.\r
+\r
**/\r
EFI_STATUS\r
EFIAPI\r
{\r
EFI_STATUS Status;\r
SMM_BOOT_RECORD_COMMUNICATE *SmmCommData;\r
- \r
- ASSERT (CommBuffer != NULL);\r
- if (CommBuffer == NULL || *CommBufferSize < sizeof (SMM_BOOT_RECORD_COMMUNICATE)) {\r
- return EFI_INVALID_PARAMETER;\r
+ UINTN BootRecordOffset;\r
+ UINTN BootRecordSize;\r
+ VOID *BootRecordData;\r
+ UINTN TempCommBufferSize;\r
+\r
+ //\r
+ // If input is invalid, stop processing this SMI\r
+ //\r
+ if (CommBuffer == NULL || CommBufferSize == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ TempCommBufferSize = *CommBufferSize;\r
+\r
+ if(TempCommBufferSize < sizeof (SMM_BOOT_RECORD_COMMUNICATE)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {\r
+ DEBUG ((EFI_D_ERROR, "FpdtSmiHandler: SMM communication data buffer in SMRAM or overflow!\n"));\r
+ return EFI_SUCCESS;\r
}\r
\r
- Status = EFI_SUCCESS;\r
SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE*)CommBuffer;\r
\r
+ Status = EFI_SUCCESS;\r
+\r
switch (SmmCommData->Function) {\r
case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE :\r
- SmmCommData->BootRecordSize = mBootRecordSize;\r
- break;\r
+ if (mSmmBootPerformanceTable != NULL) {\r
+ mBootRecordSize = mSmmBootPerformanceTable->Header.Length - sizeof (SMM_BOOT_PERFORMANCE_TABLE);\r
+ }\r
+ SmmCommData->BootRecordSize = mBootRecordSize;\r
+ break;\r
\r
case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA :\r
- if (SmmCommData->BootRecordData == NULL || SmmCommData->BootRecordSize < mBootRecordSize) {\r
- Status = EFI_INVALID_PARAMETER;\r
- break;\r
- } \r
- \r
- //\r
- // Sanity check\r
- //\r
- SmmCommData->BootRecordSize = mBootRecordSize;\r
- if (InternalIsAddressInSmram ((EFI_PHYSICAL_ADDRESS)(UINTN)SmmCommData->BootRecordData, mBootRecordSize)) {\r
- DEBUG ((EFI_D_ERROR, "Smm Data buffer is in SMRAM!\n"));\r
- Status = EFI_ACCESS_DENIED;\r
- break;\r
- }\r
-\r
- CopyMem (\r
- (UINT8*)SmmCommData->BootRecordData, \r
- mBootRecordBuffer, \r
- mBootRecordSize\r
- );\r
- break;\r
+ Status = EFI_UNSUPPORTED;\r
+ break;\r
+\r
+ case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET :\r
+ BootRecordOffset = SmmCommData->BootRecordOffset;\r
+ BootRecordData = SmmCommData->BootRecordData;\r
+ BootRecordSize = SmmCommData->BootRecordSize;\r
+ if (BootRecordData == NULL || BootRecordOffset >= mBootRecordSize) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Sanity check\r
+ //\r
+ if (BootRecordSize > mBootRecordSize - BootRecordOffset) {\r
+ BootRecordSize = mBootRecordSize - BootRecordOffset;\r
+ }\r
+ SmmCommData->BootRecordSize = BootRecordSize;\r
+ if (!SmmIsBufferOutsideSmmValid ((UINTN)BootRecordData, BootRecordSize)) {\r
+ DEBUG ((EFI_D_ERROR, "FpdtSmiHandler: SMM Data buffer in SMRAM or overflow!\n"));\r
+ Status = EFI_ACCESS_DENIED;\r
+ break;\r
+ }\r
+\r
+ CopyMem (\r
+ (UINT8*)BootRecordData,\r
+ mBootRecordBuffer + BootRecordOffset,\r
+ BootRecordSize\r
+ );\r
+ break;\r
\r
default:\r
- ASSERT (FALSE);\r
- Status = EFI_UNSUPPORTED;\r
+ Status = EFI_UNSUPPORTED;\r
}\r
\r
SmmCommData->ReturnStatus = Status;\r
+\r
return EFI_SUCCESS;\r
}\r
\r
{\r
EFI_STATUS Status;\r
EFI_HANDLE Handle;\r
- EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;\r
- UINTN Size;\r
\r
//\r
// Initialize spin lock\r
//\r
- InitializeSpinLock (&mSmmFpdtLock); \r
- \r
+ InitializeSpinLock (&mSmmFpdtLock);\r
+\r
//\r
// Get SMM Report Status Code Handler Protocol.\r
//\r
Status = mRscHandlerProtocol->Register (FpdtStatusCodeListenerSmm);\r
ASSERT_EFI_ERROR (Status);\r
\r
- //\r
- // Get SMRAM information\r
- //\r
- Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- Size = 0;\r
- Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);\r
- ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
-\r
- Status = gSmst->SmmAllocatePool (\r
- EfiRuntimeServicesData,\r
- Size,\r
- (VOID **)&mSmramRanges\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmramRanges);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- mSmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);\r
-\r
//\r
// Register SMI handler.\r
//\r