]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
Calculate enough space for 2 variables (public key and variable data) instead of...
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableSmmRuntimeDxe.c
index 2a59ac16f9cd08eac39ab1377eb0764e68bb11fd..e7b10149fb15fc791577dff78e521c87e3eaa2e6 100644 (file)
@@ -19,6 +19,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Protocol/Variable.h>\r
 #include <Protocol/SmmCommunication.h>\r
 #include <Protocol/SmmVariable.h>\r
+#include <Protocol/VariableLock.h>\r
 \r
 #include <Library/UefiBootServicesTableLib.h>\r
 #include <Library/UefiRuntimeServicesTableLib.h>\r
@@ -42,7 +43,9 @@ EFI_SMM_COMMUNICATION_PROTOCOL  *mSmmCommunication          = NULL;
 UINT8                           *mVariableBuffer            = NULL;\r
 UINT8                           *mVariableBufferPhysical    = NULL;\r
 UINTN                            mVariableBufferSize;\r
+UINTN                            mVariableBufferPayloadSize;\r
 EFI_LOCK                         mVariableServicesLock;\r
+EDKII_VARIABLE_LOCK_PROTOCOL     mVariableLock;\r
 \r
 /**\r
   Acquires lock only at boot time. Simply returns at runtime.\r
@@ -159,6 +162,73 @@ SendCommunicateBuffer (
   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
+\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
   This code finds variable in storage blocks (Volatile or Non-Volatile).\r
@@ -189,6 +259,8 @@ RuntimeServiceGetVariable (
   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
@@ -198,13 +270,30 @@ RuntimeServiceGetVariable (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  TempDataSize          = *DataSize;\r
+  VariableNameSize      = StrSize (VariableName);\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
   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
+  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
     goto Done;\r
@@ -212,8 +301,8 @@ RuntimeServiceGetVariable (
   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
@@ -229,7 +318,13 @@ RuntimeServiceGetVariable (
   //\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
@@ -270,27 +365,60 @@ RuntimeServiceGetNextVariableName (
   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
+  OutVariableNameSize   = *VariableNameSize;\r
+  InVariableNameSize    = StrSize (VariableName);\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
+  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
+\r
   Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);\r
   if (EFI_ERROR (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
@@ -300,7 +428,13 @@ RuntimeServiceGetNextVariableName (
   //\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
     goto Done;\r
   }\r
@@ -343,6 +477,7 @@ RuntimeServiceSetVariable (
   EFI_STATUS                                Status;\r
   UINTN                                     PayloadSize; \r
   SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE  *SmmVariableHeader;\r
+  UINTN                                     VariableNameSize;\r
     \r
   //\r
   // Check input parameters.\r
@@ -355,13 +490,23 @@ RuntimeServiceSetVariable (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  VariableNameSize      = StrSize (VariableName);\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
+  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
     goto Done;\r
@@ -370,7 +515,7 @@ RuntimeServiceSetVariable (
 \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
@@ -561,10 +706,11 @@ SmmVariableReady (
   ASSERT_EFI_ERROR (Status);\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
+  mVariableBufferPayloadSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) +\r
+                               OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - sizeof (VARIABLE_HEADER);\r
+  mVariableBufferSize  = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;\r
   mVariableBuffer      = AllocateRuntimePool (mVariableBufferSize);\r
   ASSERT (mVariableBuffer != NULL);\r
 \r
@@ -645,6 +791,7 @@ VariableSmmRuntimeInitialize (
   IN EFI_SYSTEM_TABLE                       *SystemTable\r
   )\r
 {\r
+  EFI_STATUS                                Status;\r
   VOID                                      *SmmVariableRegistration;\r
   VOID                                      *SmmVariableWriteRegistration;\r
   EFI_EVENT                                 OnReadyToBootEvent;\r
@@ -652,6 +799,15 @@ VariableSmmRuntimeInitialize (
 \r
   EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);\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
   //\r
   // Smm variable service is ready\r
   //\r