/** @file\r
-\r
Implement all four UEFI Runtime Variable services for the nonvolatile\r
and volatile storage space and install variable architecture protocol\r
based on SMM variable module.\r
\r
-Copyright (c) 2010, 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 - variable data.\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
+ RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are external API\r
+ to receive data buffer. The size should be checked carefully.\r
\r
-**/\r
+ InitCommunicateBuffer() is really function to check the variable data size.\r
+\r
+Copyright (c) 2010 - 2017, 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
\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
+\r
+**/\r
+#include <PiDxe.h>\r
#include <Protocol/VariableWrite.h>\r
#include <Protocol/Variable.h>\r
#include <Protocol/SmmCommunication.h>\r
+#include <Protocol/SmmVariable.h>\r
+#include <Protocol/VariableLock.h>\r
+#include <Protocol/VarCheck.h>\r
\r
#include <Library/UefiBootServicesTableLib.h>\r
#include <Library/UefiRuntimeServicesTableLib.h>\r
#include <Library/UefiRuntimeLib.h>\r
#include <Library/BaseMemoryLib.h>\r
#include <Library/DebugLib.h>\r
-#include <Library/PcdLib.h>\r
#include <Library/UefiLib.h>\r
#include <Library/BaseLib.h>\r
\r
#include <Guid/EventGroup.h>\r
-#include "VariableSmmCommon.h"\r
+#include <Guid/SmmVariableCommon.h>\r
\r
-EFI_HANDLE mHandle = NULL; \r
+#include "PrivilegePolymorphic.h"\r
+\r
+EFI_HANDLE mHandle = NULL;\r
EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL;\r
EFI_EVENT mVirtualAddressChangeEvent = NULL;\r
EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;\r
UINT8 *mVariableBuffer = NULL;\r
UINT8 *mVariableBufferPhysical = NULL;\r
-EFI_GUID mSmmVariableWriteGuid = EFI_SMM_VARIABLE_WRITE_GUID;\r
UINTN mVariableBufferSize;\r
+UINTN mVariableBufferPayloadSize;\r
+EFI_LOCK mVariableServicesLock;\r
+EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock;\r
+EDKII_VAR_CHECK_PROTOCOL mVarCheck;\r
+\r
+/**\r
+ Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).\r
+ Record their initial State when variable write service is ready.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+RecordSecureBootPolicyVarData(\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Acquires lock only at boot time. Simply returns at runtime.\r
+\r
+ This is a temperary function that will be removed when\r
+ EfiAcquireLock() in UefiLib can handle the call in UEFI\r
+ Runtimer driver in RT phase.\r
+ It calls EfiAcquireLock() at boot time, and simply returns\r
+ at runtime.\r
+\r
+ @param Lock A pointer to the lock to acquire.\r
+\r
+**/\r
+VOID\r
+AcquireLockOnlyAtBootTime (\r
+ IN EFI_LOCK *Lock\r
+ )\r
+{\r
+ if (!EfiAtRuntime ()) {\r
+ EfiAcquireLock (Lock);\r
+ }\r
+}\r
+\r
+/**\r
+ Releases lock only at boot time. Simply returns at runtime.\r
+\r
+ This is a temperary function which will be removed when\r
+ EfiReleaseLock() in UefiLib can handle the call in UEFI\r
+ Runtimer driver in RT phase.\r
+ It calls EfiReleaseLock() at boot time and simply returns\r
+ at runtime.\r
\r
+ @param Lock A pointer to the lock to release.\r
+\r
+**/\r
+VOID\r
+ReleaseLockOnlyAtBootTime (\r
+ IN EFI_LOCK *Lock\r
+ )\r
+{\r
+ if (!EfiAtRuntime ()) {\r
+ EfiReleaseLock (Lock);\r
+ }\r
+}\r
\r
/**\r
Initialize the communicate buffer using DataSize and Function.\r
The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +\r
DataSize.\r
\r
+ Caution: This function may receive untrusted input.\r
+ The data size external input, so this function will validate it carefully to avoid buffer overflow.\r
+\r
@param[out] DataPtr Points to the data in the communicate buffer.\r
@param[in] DataSize The data size to send to SMM.\r
@param[in] Function The function number to initialize the communicate header.\r
- \r
+\r
@retval EFI_INVALID_PARAMETER The data size is too big.\r
@retval EFI_SUCCESS Find the specified variable.\r
\r
IN UINTN Function\r
)\r
{\r
- EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; \r
- SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; \r
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
+\r
\r
- \r
if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {\r
return EFI_INVALID_PARAMETER;\r
}\r
SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
- \r
+\r
SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
SmmVariableFunctionHeader->Function = Function;\r
if (DataPtr != NULL) {\r
\r
@param[in] DataSize This size of the function header and the data.\r
\r
- @RetVal EFI_SUCCESS Success is returned from the functin in SMM.\r
- @RetVal Others Failure is returned from the function in SMM. \r
- \r
+ @retval EFI_SUCCESS Success is returned from the functin in SMM.\r
+ @retval Others Failure is returned from the function in SMM.\r
+\r
**/\r
EFI_STATUS\r
SendCommunicateBuffer (\r
{\r
EFI_STATUS Status;\r
UINTN CommSize;\r
- EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; \r
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
- \r
+\r
CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);\r
ASSERT_EFI_ERROR (Status);\r
return SmmVariableFunctionHeader->ReturnStatus;\r
}\r
\r
+/**\r
+ Mark a variable that will become read-only after leaving the DXE phase of execution.\r
+\r
+ @param[in] This The VARIABLE_LOCK_PROTOCOL instance.\r
+ @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.\r
+ @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.\r
+\r
+ @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked\r
+ as pending to be read-only.\r
+ @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.\r
+ Or VariableName is an empty string.\r
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
+ already been signaled.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableLockRequestToLock (\r
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN VariableNameSize;\r
+ UINTN PayloadSize;\r
+ SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;\r
+\r
+ if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ VariableNameSize = StrSize (VariableName);\r
+ VariableToLock = NULL;\r
+\r
+ //\r
+ // If VariableName exceeds SMM payload limit. Return failure\r
+ //\r
+ if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
+\r
+ //\r
+ // Init the communicate buffer. The buffer data size is:\r
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
+ //\r
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;\r
+ Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ ASSERT (VariableToLock != NULL);\r
+\r
+ CopyGuid (&VariableToLock->Guid, VendorGuid);\r
+ VariableToLock->NameSize = VariableNameSize;\r
+ CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);\r
+\r
+ //\r
+ // Send data to SMM.\r
+ //\r
+ Status = SendCommunicateBuffer (PayloadSize);\r
+\r
+Done:\r
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Register SetVariable check handler.\r
+\r
+ @param[in] Handler Pointer to check handler.\r
+\r
+ @retval EFI_SUCCESS The SetVariable check handler was registered successfully.\r
+ @retval EFI_INVALID_PARAMETER Handler is NULL.\r
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
+ already been signaled.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.\r
+ @retval EFI_UNSUPPORTED This interface is not implemented.\r
+ For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VarCheckRegisterSetVariableCheckHandler (\r
+ IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Variable property set.\r
+\r
+ @param[in] Name Pointer to the variable name.\r
+ @param[in] Guid Pointer to the vendor GUID.\r
+ @param[in] VariableProperty Pointer to the input variable property.\r
+\r
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.\r
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,\r
+ or the fields of VariableProperty are not valid.\r
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
+ already been signaled.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VarCheckVariablePropertySet (\r
+ IN CHAR16 *Name,\r
+ IN EFI_GUID *Guid,\r
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN VariableNameSize;\r
+ UINTN PayloadSize;\r
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;\r
+\r
+ if (Name == NULL || Name[0] == 0 || Guid == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (VariableProperty == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ VariableNameSize = StrSize (Name);\r
+ CommVariableProperty = NULL;\r
+\r
+ //\r
+ // If VariableName exceeds SMM payload limit. Return failure\r
+ //\r
+ if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
+\r
+ //\r
+ // Init the communicate buffer. The buffer data size is:\r
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
+ //\r
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;\r
+ Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ ASSERT (CommVariableProperty != NULL);\r
+\r
+ CopyGuid (&CommVariableProperty->Guid, Guid);\r
+ CopyMem (&CommVariableProperty->VariableProperty, VariableProperty, sizeof (*VariableProperty));\r
+ CommVariableProperty->NameSize = VariableNameSize;\r
+ CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);\r
+\r
+ //\r
+ // Send data to SMM.\r
+ //\r
+ Status = SendCommunicateBuffer (PayloadSize);\r
+\r
+Done:\r
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Variable property get.\r
+\r
+ @param[in] Name Pointer to the variable name.\r
+ @param[in] Guid Pointer to the vendor GUID.\r
+ @param[out] VariableProperty Pointer to the output variable property.\r
+\r
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.\r
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.\r
+ @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VarCheckVariablePropertyGet (\r
+ IN CHAR16 *Name,\r
+ IN EFI_GUID *Guid,\r
+ OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN VariableNameSize;\r
+ UINTN PayloadSize;\r
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;\r
+\r
+ if (Name == NULL || Name[0] == 0 || Guid == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (VariableProperty == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ VariableNameSize = StrSize (Name);\r
+ CommVariableProperty = NULL;\r
+\r
+ //\r
+ // If VariableName exceeds SMM payload limit. Return failure\r
+ //\r
+ if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
+\r
+ //\r
+ // Init the communicate buffer. The buffer data size is:\r
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
+ //\r
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;\r
+ Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ ASSERT (CommVariableProperty != NULL);\r
+\r
+ CopyGuid (&CommVariableProperty->Guid, Guid);\r
+ CommVariableProperty->NameSize = VariableNameSize;\r
+ CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);\r
+\r
+ //\r
+ // Send data to SMM.\r
+ //\r
+ Status = SendCommunicateBuffer (PayloadSize);\r
+ if (Status == EFI_SUCCESS) {\r
+ CopyMem (VariableProperty, &CommVariableProperty->VariableProperty, sizeof (*VariableProperty));\r
+ }\r
+\r
+Done:\r
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+ return Status;\r
+}\r
\r
/**\r
This code finds variable in storage blocks (Volatile or Non-Volatile).\r
\r
+ Caution: This function may receive untrusted input.\r
+ The data size is external input, so this function will validate it carefully to avoid buffer overflow.\r
+\r
@param[in] VariableName Name of Variable to be found.\r
@param[in] VendorGuid Variable vendor GUID.\r
@param[out] Attributes Attribute value of the variable found.\r
@param[in, out] DataSize Size of Data found. If size is less than the\r
data, this value contains the required size.\r
@param[out] Data Data pointer.\r
- \r
+\r
@retval EFI_INVALID_PARAMETER Invalid parameter.\r
@retval EFI_SUCCESS Find the specified variable.\r
@retval EFI_NOT_FOUND Not found.\r
EFI_STATUS Status;\r
UINTN PayloadSize;\r
SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
+ UINTN TempDataSize;\r
+ UINTN VariableNameSize;\r
\r
if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if ((*DataSize != 0) && (Data == NULL)) {\r
+ TempDataSize = *DataSize;\r
+ VariableNameSize = StrSize (VariableName);\r
+ SmmVariableHeader = NULL;\r
+\r
+ //\r
+ // If VariableName exceeds SMM payload limit. Return failure\r
+ //\r
+ if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- \r
+\r
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
+\r
//\r
// Init the communicate buffer. The buffer data size is:\r
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
//\r
- PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + StrSize (VariableName);\r
- Status = InitCommunicateBuffer (&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
+ if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {\r
+ //\r
+ // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
+ //\r
+ TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;\r
+ }\r
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;\r
+\r
+ Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
if (EFI_ERROR (Status)) {\r
- return Status;\r
+ goto Done;\r
}\r
ASSERT (SmmVariableHeader != NULL);\r
\r
CopyGuid (&SmmVariableHeader->Guid, VendorGuid);\r
- SmmVariableHeader->DataSize = *DataSize;\r
- SmmVariableHeader->NameSize = StrSize (VariableName);\r
+ SmmVariableHeader->DataSize = TempDataSize;\r
+ SmmVariableHeader->NameSize = VariableNameSize;\r
if (Attributes == NULL) {\r
SmmVariableHeader->Attributes = 0;\r
} else {\r
//\r
// Get data from SMM.\r
//\r
- *DataSize = SmmVariableHeader->DataSize;\r
+ if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
+ //\r
+ // SMM CommBuffer DataSize can be a trimed value\r
+ // Only update DataSize when needed\r
+ //\r
+ *DataSize = SmmVariableHeader->DataSize;\r
+ }\r
if (Attributes != NULL) {\r
*Attributes = SmmVariableHeader->Attributes;\r
}\r
\r
if (EFI_ERROR (Status)) {\r
- return Status;\r
+ goto Done;\r
}\r
\r
- CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);\r
+ if (Data != NULL) {\r
+ CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);\r
+ } else {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
\r
+Done:\r
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
return Status;\r
}\r
\r
EFI_STATUS Status;\r
UINTN PayloadSize;\r
SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;\r
+ UINTN OutVariableNameSize;\r
+ UINTN InVariableNameSize;\r
\r
if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- \r
+\r
+ OutVariableNameSize = *VariableNameSize;\r
+ InVariableNameSize = StrSize (VariableName);\r
+ SmmGetNextVariableName = NULL;\r
+\r
+ //\r
+ // If input string exceeds SMM payload limit. Return failure\r
+ //\r
+ if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
+\r
//\r
// Init the communicate buffer. The buffer data size is:\r
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
//\r
- PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + *VariableNameSize; \r
- Status = InitCommunicateBuffer (&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);\r
+ if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
+ //\r
+ // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
+ //\r
+ OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);\r
+ }\r
+ //\r
+ // Payload should be Guid + NameSize + MAX of Input & Output buffer\r
+ //\r
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);\r
+\r
+ Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);\r
if (EFI_ERROR (Status)) {\r
- return Status;\r
+ goto Done;\r
}\r
ASSERT (SmmGetNextVariableName != NULL);\r
\r
- SmmGetNextVariableName->NameSize = *VariableNameSize;\r
+ //\r
+ // SMM comm buffer->NameSize is buffer size for return string\r
+ //\r
+ SmmGetNextVariableName->NameSize = OutVariableNameSize;\r
+\r
CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);\r
- CopyMem (SmmGetNextVariableName->Name, VariableName, *VariableNameSize);\r
+ //\r
+ // Copy whole string\r
+ //\r
+ CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);\r
+ if (OutVariableNameSize > InVariableNameSize) {\r
+ ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);\r
+ }\r
\r
//\r
// Send data to SMM\r
//\r
// Get data from SMM.\r
//\r
- *VariableNameSize = SmmGetNextVariableName->NameSize; \r
+ if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
+ //\r
+ // SMM CommBuffer NameSize can be a trimed value\r
+ // Only update VariableNameSize when needed\r
+ //\r
+ *VariableNameSize = SmmGetNextVariableName->NameSize;\r
+ }\r
if (EFI_ERROR (Status)) {\r
- return Status;\r
+ goto Done;\r
}\r
- \r
+\r
CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);\r
- CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize); \r
+ CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);\r
\r
+Done:\r
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
return Status;\r
}\r
\r
/**\r
This code sets variable in storage blocks (Volatile or Non-Volatile).\r
\r
+ Caution: This function may receive untrusted input.\r
+ The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.\r
+\r
@param[in] VariableName Name of Variable to be found.\r
@param[in] VendorGuid Variable vendor GUID.\r
@param[in] Attributes Attribute value of the variable found\r
)\r
{\r
EFI_STATUS Status;\r
- UINTN PayloadSize; \r
+ UINTN PayloadSize;\r
SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
- \r
+ UINTN VariableNameSize;\r
+\r
//\r
// Check input parameters.\r
//\r
if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
return EFI_INVALID_PARAMETER;\r
- } \r
+ }\r
\r
if (DataSize != 0 && Data == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- \r
+\r
+ VariableNameSize = StrSize (VariableName);\r
+ SmmVariableHeader = NULL;\r
+\r
+ //\r
+ // If VariableName or DataSize exceeds SMM payload limit. Return failure\r
+ //\r
+ if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||\r
+ (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
+\r
//\r
// Init the communicate buffer. The buffer data size is:\r
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
//\r
- PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + StrSize (VariableName) + DataSize;\r
- Status = InitCommunicateBuffer (&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);\r
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;\r
+ Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);\r
if (EFI_ERROR (Status)) {\r
- return Status;\r
+ goto Done;\r
}\r
ASSERT (SmmVariableHeader != NULL);\r
\r
CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);\r
SmmVariableHeader->DataSize = DataSize;\r
- SmmVariableHeader->NameSize = StrSize (VariableName);\r
+ SmmVariableHeader->NameSize = VariableNameSize;\r
SmmVariableHeader->Attributes = Attributes;\r
CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);\r
// Send data to SMM.\r
//\r
Status = SendCommunicateBuffer (PayloadSize);\r
- \r
+\r
+Done:\r
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+\r
+ if (!EfiAtRuntime ()) {\r
+ if (!EFI_ERROR (Status)) {\r
+ SecureBootHook (\r
+ VariableName,\r
+ VendorGuid\r
+ );\r
+ }\r
+ }\r
return Status;\r
}\r
\r
UINTN PayloadSize;\r
SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;\r
\r
+ SmmQueryVariableInfo = NULL;\r
+\r
if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- \r
+\r
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
+\r
//\r
// Init the communicate buffer. The buffer data size is:\r
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;\r
//\r
- PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY);\r
- Status = InitCommunicateBuffer (&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);\r
+ PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);\r
+ Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);\r
if (EFI_ERROR (Status)) {\r
- return Status;\r
+ goto Done;\r
}\r
ASSERT (SmmQueryVariableInfo != NULL);\r
\r
//\r
Status = SendCommunicateBuffer (PayloadSize);\r
if (EFI_ERROR (Status)) {\r
- return Status;\r
+ goto Done;\r
}\r
\r
//\r
//\r
*MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize;\r
*MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize;\r
- *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize; \r
- \r
- return EFI_SUCCESS;\r
+ *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;\r
+\r
+Done:\r
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+ return Status;\r
}\r
\r
\r
// Init the communicate buffer. The buffer data size is:\r
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
//\r
- InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE); \r
+ InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);\r
\r
//\r
// Send data to SMM.\r
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
//\r
InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);\r
- \r
+\r
//\r
// Send data to SMM.\r
//\r
SendCommunicateBuffer (0);\r
+\r
+ gBS->CloseEvent (Event);\r
}\r
\r
\r
EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);\r
}\r
\r
+/**\r
+ This code gets variable payload size.\r
+\r
+ @param[out] VariablePayloadSize Output pointer to variable payload size.\r
+\r
+ @retval EFI_SUCCESS Get successfully.\r
+ @retval Others Get unsuccessfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetVariablePayloadSize (\r
+ OUT UINTN *VariablePayloadSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *SmmGetPayloadSize;\r
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
+ UINTN CommSize;\r
+ UINT8 *CommBuffer;\r
+\r
+ SmmGetPayloadSize = NULL;\r
+ CommBuffer = NULL;\r
+\r
+ if(VariablePayloadSize == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
+\r
+ //\r
+ // Init the communicate buffer. The buffer data size is:\r
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
+ //\r
+ CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
+ CommBuffer = AllocateZeroPool (CommSize);\r
+ if (CommBuffer == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;\r
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
+ SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
+\r
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
+ SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE;\r
+ SmmGetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data;\r
+\r
+ //\r
+ // Send data to SMM.\r
+ //\r
+ Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = SmmVariableFunctionHeader->ReturnStatus;\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Get data from SMM.\r
+ //\r
+ *VariablePayloadSize = SmmGetPayloadSize->VariablePayloadSize;\r
+\r
+Done:\r
+ if (CommBuffer != NULL) {\r
+ FreePool (CommBuffer);\r
+ }\r
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+ return Status;\r
+}\r
\r
/**\r
Initialize variable service and install Variable Architectural protocol.\r
\r
@param[in] Event Event whose notification function is being invoked.\r
@param[in] Context Pointer to the notification function's context.\r
- \r
+\r
**/\r
VOID\r
EFIAPI\r
if (EFI_ERROR (Status)) {\r
return;\r
}\r
- \r
+\r
Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);\r
ASSERT_EFI_ERROR (Status);\r
- \r
+\r
//\r
- // Allocate memory for variable store.\r
+ // Allocate memory for variable communicate buffer.\r
//\r
- mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
- mVariableBufferSize += MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
+ Status = GetVariablePayloadSize (&mVariableBufferPayloadSize);\r
+ ASSERT_EFI_ERROR (Status);\r
+ mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;\r
mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);\r
ASSERT (mVariableBuffer != NULL);\r
\r
gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
gRT->SetVariable = RuntimeServiceSetVariable;\r
gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo;\r
- \r
+\r
//\r
// Install the Variable Architectural Protocol on a new handle.\r
//\r
Status = gBS->InstallProtocolInterface (\r
&mHandle,\r
- &gEfiVariableArchProtocolGuid, \r
+ &gEfiVariableArchProtocolGuid,\r
EFI_NATIVE_INTERFACE,\r
NULL\r
);\r
ASSERT_EFI_ERROR (Status);\r
+\r
+ mVariableLock.RequestToLock = VariableLockRequestToLock;\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mHandle,\r
+ &gEdkiiVariableLockProtocolGuid,\r
+ &mVariableLock,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ mVarCheck.RegisterSetVariableCheckHandler = VarCheckRegisterSetVariableCheckHandler;\r
+ mVarCheck.VariablePropertySet = VarCheckVariablePropertySet;\r
+ mVarCheck.VariablePropertyGet = VarCheckVariablePropertyGet;\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mHandle,\r
+ &gEdkiiVarCheckProtocolGuid,\r
+ &mVarCheck,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ gBS->CloseEvent (Event);\r
}\r
\r
\r
\r
@param[in] Event Event whose notification function is being invoked.\r
@param[in] Context Pointer to the notification function's context.\r
- \r
+\r
**/\r
VOID\r
EFIAPI\r
//\r
// Check whether the protocol is installed or not.\r
//\r
- Status = gBS->LocateProtocol (&mSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);\r
+ Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);\r
if (EFI_ERROR (Status)) {\r
return;\r
}\r
- \r
+\r
+ //\r
+ // Some Secure Boot Policy Var (SecureBoot, etc) updates following other\r
+ // Secure Boot Policy Variable change. Record their initial value.\r
+ //\r
+ RecordSecureBootPolicyVarData();\r
+\r
Status = gBS->InstallProtocolInterface (\r
&mHandle,\r
- &gEfiVariableWriteArchProtocolGuid, \r
+ &gEfiVariableWriteArchProtocolGuid,\r
EFI_NATIVE_INTERFACE,\r
NULL\r
);\r
- ASSERT_EFI_ERROR (Status); \r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ gBS->CloseEvent (Event);\r
}\r
\r
\r
/**\r
Variable Driver main entry point. The Variable driver places the 4 EFI\r
- runtime services in the EFI System Table and installs arch protocols \r
- for variable read and write services being availible. It also registers\r
+ runtime services in the EFI System Table and installs arch protocols\r
+ for variable read and write services being available. It also registers\r
a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
\r
- @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
@param[in] SystemTable A pointer to the EFI System Table.\r
- \r
+\r
@retval EFI_SUCCESS Variable service successfully initialized.\r
\r
**/\r
VOID *SmmVariableWriteRegistration;\r
EFI_EVENT OnReadyToBootEvent;\r
EFI_EVENT ExitBootServiceEvent;\r
- \r
+ EFI_EVENT LegacyBootEvent;\r
+\r
+ EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);\r
+\r
//\r
// Smm variable service is ready\r
//\r
EfiCreateProtocolNotifyEvent (\r
- &gEfiSmmVariableProtocolGuid, \r
- TPL_CALLBACK, \r
- SmmVariableReady, \r
- NULL, \r
+ &gEfiSmmVariableProtocolGuid,\r
+ TPL_CALLBACK,\r
+ SmmVariableReady,\r
+ NULL,\r
&SmmVariableRegistration\r
);\r
\r
// Smm Non-Volatile variable write service is ready\r
//\r
EfiCreateProtocolNotifyEvent (\r
- &mSmmVariableWriteGuid, \r
- TPL_CALLBACK, \r
- SmmVariableWriteReady, \r
- NULL, \r
+ &gSmmVariableWriteGuid,\r
+ TPL_CALLBACK,\r
+ SmmVariableWriteReady,\r
+ NULL,\r
&SmmVariableWriteRegistration\r
);\r
\r
// Register the event to reclaim variable for OS usage.\r
//\r
EfiCreateEventReadyToBootEx (\r
- TPL_NOTIFY, \r
- OnReadyToBoot, \r
- NULL, \r
+ TPL_NOTIFY,\r
+ OnReadyToBoot,\r
+ NULL,\r
&OnReadyToBootEvent\r
- ); \r
+ );\r
\r
//\r
// Register the event to inform SMM variable that it is at runtime.\r
NULL,\r
&gEfiEventExitBootServicesGuid,\r
&ExitBootServiceEvent\r
- ); \r
+ );\r
+\r
+ //\r
+ // Register the event to inform SMM variable that it is at runtime for legacy boot.\r
+ // Reuse OnExitBootServices() here.\r
+ //\r
+ EfiCreateEventLegacyBootEx(\r
+ TPL_NOTIFY,\r
+ OnExitBootServices,\r
+ NULL,\r
+ &LegacyBootEvent\r
+ );\r
\r
//\r
// Register the event to convert the pointer for runtime.\r
&gEfiEventVirtualAddressChangeGuid,\r
&mVirtualAddressChangeEvent\r
);\r
- \r
+\r
return EFI_SUCCESS;\r
}\r
\r