/** @file\r
- The common variable operation routines shared by DXE_RINTIME variable\r
+ The common variable operation routines shared by DXE_RUNTIME variable\r
module and DXE_SMM variable module.\r
\r
-Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
+ Caution: This module requires additional review when modified.\r
+ This driver will have external input - variable data. They may be input in SMM mode.\r
+ This external input must be validated carefully to avoid security issue like\r
+ buffer overflow, integer overflow.\r
+\r
+ VariableServiceGetNextVariableName () and VariableServiceQueryVariableInfo() are external API.\r
+ They need check input parameter.\r
+\r
+ VariableServiceGetVariable() and VariableServiceSetVariable() are external API\r
+ to receive datasize and data buffer. The size should be checked carefully.\r
+\r
+ VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,\r
+ integer overflow. It should also check attribute to avoid authentication bypass.\r
+\r
+Copyright (c) 2009 - 2013, 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
return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
}\r
\r
+/**\r
+\r
+ Check the PubKeyIndex is a valid key or not.\r
+\r
+ This function will iterate the NV storage to see if this PubKeyIndex is still referenced \r
+ by any valid count-based auth variabe.\r
+ \r
+ @param[in] PubKeyIndex Index of the public key in public key store.\r
+\r
+ @retval TRUE The PubKeyIndex is still in use.\r
+ @retval FALSE The PubKeyIndex is not referenced by any count-based auth variabe.\r
+ \r
+**/\r
+BOOLEAN\r
+IsValidPubKeyIndex (\r
+ IN UINT32 PubKeyIndex\r
+ )\r
+{\r
+ VARIABLE_HEADER *Variable;\r
+\r
+ if (PubKeyIndex > mPubKeyNumber) {\r
+ return FALSE;\r
+ }\r
+ \r
+ Variable = GetStartPointer (mNvVariableCache);\r
+ \r
+ while (IsValidVariableHeader (Variable)) {\r
+ if ((Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) && \r
+ Variable->PubKeyIndex == PubKeyIndex) {\r
+ return TRUE;\r
+ }\r
+ Variable = GetNextVariablePtr (Variable);\r
+ }\r
+ \r
+ return FALSE;\r
+}\r
+\r
+/**\r
+\r
+ Get the number of valid public key in PubKeyStore.\r
+ \r
+ @param[in] PubKeyNumber Number of the public key in public key store.\r
+\r
+ @return Number of valid public key in PubKeyStore.\r
+\r
+**/\r
+UINT32\r
+GetValidPubKeyNumber (\r
+ IN UINT32 PubKeyNumber\r
+ )\r
+{\r
+ UINT32 PubKeyIndex;\r
+ UINT32 Counter;\r
+\r
+ Counter = 0;\r
+ \r
+ for (PubKeyIndex = 1; PubKeyIndex <= PubKeyNumber; PubKeyIndex++) {\r
+ if (IsValidPubKeyIndex (PubKeyIndex)) {\r
+ Counter++;\r
+ }\r
+ }\r
+ \r
+ return Counter;\r
+}\r
\r
/**\r
\r
- Variable store garbage collection and reclaim operation.\r
+ Filter the useless key in public key store.\r
\r
- @param VariableBase Base address of variable store.\r
- @param LastVariableOffset Offset of last variable.\r
- @param IsVolatile The variable store is volatile or not;\r
- if it is non-volatile, need FTW.\r
- @param UpdatingVariable Pointer to updating variable.\r
+ This function will find out all valid public keys in public key database, save them in new allocated \r
+ buffer NewPubKeyStore, and give the new PubKeyIndex. The caller is responsible for freeing buffer\r
+ NewPubKeyIndex and NewPubKeyStore with FreePool().\r
\r
- @return EFI_OUT_OF_RESOURCES\r
- @return EFI_SUCCESS\r
- @return Others\r
+ @param[in] PubKeyStore Point to the public key database.\r
+ @param[in] PubKeyNumber Number of the public key in PubKeyStore.\r
+ @param[out] NewPubKeyIndex Point to an array of new PubKeyIndex corresponds to NewPubKeyStore.\r
+ @param[out] NewPubKeyStore Saved all valid public keys in PubKeyStore.\r
+ @param[out] NewPubKeySize Buffer size of the NewPubKeyStore.\r
+ \r
+ @retval EFI_SUCCESS Trim operation is complete successfully.\r
+ @retval EFI_OUT_OF_RESOURCES No enough memory resources, or no useless key in PubKeyStore.\r
+ \r
+**/\r
+EFI_STATUS\r
+PubKeyStoreFilter (\r
+ IN UINT8 *PubKeyStore,\r
+ IN UINT32 PubKeyNumber,\r
+ OUT UINT32 **NewPubKeyIndex,\r
+ OUT UINT8 **NewPubKeyStore,\r
+ OUT UINT32 *NewPubKeySize\r
+ )\r
+{\r
+ UINT32 PubKeyIndex;\r
+ UINT32 CopiedKey;\r
+ UINT32 NewPubKeyNumber;\r
+ \r
+ NewPubKeyNumber = GetValidPubKeyNumber (PubKeyNumber);\r
+ if (NewPubKeyNumber == PubKeyNumber) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (NewPubKeyNumber != 0) {\r
+ *NewPubKeySize = NewPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE;\r
+ } else {\r
+ *NewPubKeySize = sizeof (UINT8);\r
+ }\r
+\r
+ *NewPubKeyStore = AllocatePool (*NewPubKeySize);\r
+ if (*NewPubKeyStore == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ *NewPubKeyIndex = AllocateZeroPool ((PubKeyNumber + 1) * sizeof (UINT32));\r
+ if (*NewPubKeyIndex == NULL) {\r
+ FreePool (*NewPubKeyStore);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ CopiedKey = 0;\r
+ for (PubKeyIndex = 1; PubKeyIndex <= PubKeyNumber; PubKeyIndex++) {\r
+ if (IsValidPubKeyIndex (PubKeyIndex)) {\r
+ CopyMem (\r
+ *NewPubKeyStore + CopiedKey * EFI_CERT_TYPE_RSA2048_SIZE,\r
+ PubKeyStore + (PubKeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE,\r
+ EFI_CERT_TYPE_RSA2048_SIZE\r
+ );\r
+ (*NewPubKeyIndex)[PubKeyIndex] = ++CopiedKey;\r
+ }\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Variable store garbage collection and reclaim operation.\r
+\r
+ If ReclaimPubKeyStore is FALSE, reclaim variable space by deleting the obsoleted varaibles.\r
+ If ReclaimPubKeyStore is TRUE, reclaim invalid key in public key database and update the PubKeyIndex\r
+ for all the count-based authenticate variable in NV storage.\r
+\r
+ @param[in] VariableBase Base address of variable store.\r
+ @param[out] LastVariableOffset Offset of last variable.\r
+ @param[in] IsVolatile The variable store is volatile or not;\r
+ if it is non-volatile, need FTW.\r
+ @param[in] UpdatingVariable Pointer to updating variable.\r
+ @param[in] ReclaimPubKeyStore Reclaim for public key database or not.\r
+ @param[in] ReclaimAnyway If TRUE, do reclaim anyway.\r
+ \r
+ @return EFI_OUT_OF_RESOURCES No enough memory resources.\r
+ @return EFI_SUCCESS Reclaim operation has finished successfully.\r
+ @return Others Unexpect error happened during reclaim operation.\r
\r
**/\r
EFI_STATUS\r
IN EFI_PHYSICAL_ADDRESS VariableBase,\r
OUT UINTN *LastVariableOffset,\r
IN BOOLEAN IsVolatile,\r
- IN VARIABLE_HEADER *UpdatingVariable\r
+ IN VARIABLE_HEADER *UpdatingVariable,\r
+ IN BOOLEAN ReclaimPubKeyStore,\r
+ IN BOOLEAN ReclaimAnyway\r
)\r
{\r
VARIABLE_HEADER *Variable;\r
EFI_STATUS Status;\r
CHAR16 *VariableNamePtr;\r
CHAR16 *UpdatingVariableNamePtr;\r
-\r
+ UINTN CommonVariableTotalSize;\r
+ UINTN HwErrVariableTotalSize;\r
+ UINT32 *NewPubKeyIndex;\r
+ UINT8 *NewPubKeyStore;\r
+ UINT32 NewPubKeySize;\r
+ VARIABLE_HEADER *PubKeyHeader;\r
+ BOOLEAN NeedDoReclaim;\r
+\r
+ NeedDoReclaim = FALSE;\r
VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
- //\r
- // Recalculate the total size of Common/HwErr type variables in non-volatile area.\r
- //\r
- if (!IsVolatile) {\r
- mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
- mVariableModuleGlobal->HwErrVariableTotalSize = 0;\r
- }\r
\r
+ CommonVariableTotalSize = 0;\r
+ HwErrVariableTotalSize = 0;\r
+ NewPubKeyIndex = NULL;\r
+ NewPubKeyStore = NULL;\r
+ NewPubKeySize = 0;\r
+ PubKeyHeader = NULL;\r
+ \r
//\r
// Start Pointers for the variable.\r
//\r
) {\r
VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
MaximumBufferSize += VariableSize;\r
+ } else {\r
+ NeedDoReclaim = TRUE;\r
}\r
\r
Variable = NextVariable;\r
}\r
\r
+ if (!ReclaimAnyway && !NeedDoReclaim) {\r
+ DEBUG ((EFI_D_INFO, "Variable driver: no DELETED variable found, so no variable space could be reclaimed.\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
//\r
// Reserve the 1 Bytes with Oxff to identify the\r
// end of the variable buffer.\r
CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
\r
- //\r
- // Reinstall all ADDED variables as long as they are not identical to Updating Variable.\r
- //\r
- Variable = GetStartPointer (VariableStoreHeader);\r
- while (IsValidVariableHeader (Variable)) {\r
- NextVariable = GetNextVariablePtr (Variable);\r
- if (Variable->State == VAR_ADDED) {\r
- if (UpdatingVariable != NULL) {\r
- if (UpdatingVariable == Variable) {\r
- Variable = NextVariable;\r
- continue;\r
- }\r
-\r
- VariableNameSize = NameSizeOfVariable(Variable);\r
- UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable);\r
+ if (ReclaimPubKeyStore) {\r
+ //\r
+ // Trim the PubKeyStore and get new PubKeyIndex.\r
+ //\r
+ Status = PubKeyStoreFilter (\r
+ mPubKeyStore,\r
+ mPubKeyNumber,\r
+ &NewPubKeyIndex,\r
+ &NewPubKeyStore,\r
+ &NewPubKeySize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (ValidBuffer);\r
+ return Status;\r
+ }\r
\r
- VariableNamePtr = GetVariableNamePtr (Variable);\r
- UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable);\r
- if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid) &&\r
- VariableNameSize == UpdatingVariableNameSize &&\r
- CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) {\r
+ //\r
+ // Refresh the PubKeyIndex for all valid variables (ADDED and IN_DELETED_TRANSITION).\r
+ //\r
+ Variable = GetStartPointer (mNvVariableCache);\r
+ while (IsValidVariableHeader (Variable)) {\r
+ NextVariable = GetNextVariablePtr (Variable);\r
+ if (Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+ if ((StrCmp (GetVariableNamePtr (Variable), AUTHVAR_KEYDB_NAME) == 0) && \r
+ (CompareGuid (&Variable->VendorGuid, &gEfiAuthenticatedVariableGuid))) {\r
+ //\r
+ // Skip the public key database, it will be reinstalled later.\r
+ //\r
+ PubKeyHeader = Variable;\r
Variable = NextVariable;\r
continue;\r
}\r
+ \r
+ VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
+ CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
+ ((VARIABLE_HEADER*) CurrPtr)->PubKeyIndex = NewPubKeyIndex[Variable->PubKeyIndex];\r
+ CurrPtr += VariableSize;\r
+ if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ HwErrVariableTotalSize += VariableSize;\r
+ } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ CommonVariableTotalSize += VariableSize;\r
+ }\r
}\r
- VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
- CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
- CurrPtr += VariableSize;\r
- if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
- } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
- }\r
- }\r
- Variable = NextVariable;\r
- }\r
-\r
- //\r
- // Reinstall the variable being updated if it is not NULL.\r
- //\r
- if (UpdatingVariable != NULL) {\r
- VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;\r
- CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);\r
- CurrPtr += VariableSize;\r
- if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
- } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+ Variable = NextVariable;\r
}\r
- }\r
\r
- //\r
- // Reinstall all in delete transition variables.\r
- //\r
- Variable = GetStartPointer (VariableStoreHeader);\r
- while (IsValidVariableHeader (Variable)) {\r
- NextVariable = GetNextVariablePtr (Variable);\r
- if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+ //\r
+ // Reinstall the new public key database.\r
+ //\r
+ CopyMem (CurrPtr, (UINT8*) PubKeyHeader, sizeof (VARIABLE_HEADER));\r
+ Variable = (VARIABLE_HEADER*) CurrPtr;\r
+ Variable->DataSize = NewPubKeySize;\r
+ StrCpy (GetVariableNamePtr (Variable), GetVariableNamePtr (PubKeyHeader));\r
+ CopyMem (GetVariableDataPtr (Variable), NewPubKeyStore, NewPubKeySize);\r
+ CurrPtr = (UINT8*) GetNextVariablePtr (Variable); \r
+ CommonVariableTotalSize += (UINTN) CurrPtr - (UINTN) Variable;\r
+ } else {\r
+ //\r
+ // Reinstall all ADDED variables as long as they are not identical to Updating Variable.\r
+ //\r
+ Variable = GetStartPointer (VariableStoreHeader);\r
+ while (IsValidVariableHeader (Variable)) {\r
+ NextVariable = GetNextVariablePtr (Variable);\r
+ if (Variable->State == VAR_ADDED) {\r
+ if (UpdatingVariable != NULL) {\r
+ if (UpdatingVariable == Variable) {\r
+ Variable = NextVariable;\r
+ continue;\r
+ }\r
\r
- //\r
- // Buffer has cached all ADDED variable.\r
- // Per IN_DELETED variable, we have to guarantee that\r
- // no ADDED one in previous buffer.\r
- //\r
+ VariableNameSize = NameSizeOfVariable(Variable);\r
+ UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable);\r
\r
- FoundAdded = FALSE;\r
- AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
- while (IsValidVariableHeader (AddedVariable)) {\r
- NextAddedVariable = GetNextVariablePtr (AddedVariable);\r
- NameSize = NameSizeOfVariable (AddedVariable);\r
- if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&\r
- NameSize == NameSizeOfVariable (Variable)\r
- ) {\r
- Point0 = (VOID *) GetVariableNamePtr (AddedVariable);\r
- Point1 = (VOID *) GetVariableNamePtr (Variable);\r
- if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) {\r
- FoundAdded = TRUE;\r
- break;\r
+ VariableNamePtr = GetVariableNamePtr (Variable);\r
+ UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable);\r
+ if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid) &&\r
+ VariableNameSize == UpdatingVariableNameSize &&\r
+ CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) {\r
+ Variable = NextVariable;\r
+ continue;\r
}\r
}\r
- AddedVariable = NextAddedVariable;\r
- }\r
- if (!FoundAdded) {\r
- //\r
- // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.\r
- //\r
VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
- ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
CurrPtr += VariableSize;\r
if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+ HwErrVariableTotalSize += VariableSize;\r
} else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+ CommonVariableTotalSize += VariableSize;\r
}\r
}\r
+ Variable = NextVariable;\r
}\r
\r
- Variable = NextVariable;\r
+ //\r
+ // Reinstall the variable being updated if it is not NULL.\r
+ //\r
+ if (UpdatingVariable != NULL) {\r
+ VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;\r
+ CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);\r
+ CurrPtr += VariableSize;\r
+ if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ HwErrVariableTotalSize += VariableSize;\r
+ } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ CommonVariableTotalSize += VariableSize;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Reinstall all in delete transition variables.\r
+ //\r
+ Variable = GetStartPointer (VariableStoreHeader);\r
+ while (IsValidVariableHeader (Variable)) {\r
+ NextVariable = GetNextVariablePtr (Variable);\r
+ if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+\r
+ //\r
+ // Buffer has cached all ADDED variable.\r
+ // Per IN_DELETED variable, we have to guarantee that\r
+ // no ADDED one in previous buffer.\r
+ //\r
+\r
+ FoundAdded = FALSE;\r
+ AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
+ while (IsValidVariableHeader (AddedVariable)) {\r
+ NextAddedVariable = GetNextVariablePtr (AddedVariable);\r
+ NameSize = NameSizeOfVariable (AddedVariable);\r
+ if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&\r
+ NameSize == NameSizeOfVariable (Variable)\r
+ ) {\r
+ Point0 = (VOID *) GetVariableNamePtr (AddedVariable);\r
+ Point1 = (VOID *) GetVariableNamePtr (Variable);\r
+ if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) {\r
+ FoundAdded = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ AddedVariable = NextAddedVariable;\r
+ }\r
+ if (!FoundAdded) {\r
+ //\r
+ // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.\r
+ //\r
+ VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
+ CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
+ ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
+ CurrPtr += VariableSize;\r
+ if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ HwErrVariableTotalSize += VariableSize;\r
+ } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ CommonVariableTotalSize += VariableSize;\r
+ }\r
+ }\r
+ }\r
+\r
+ Variable = NextVariable;\r
+ }\r
}\r
\r
if (IsVolatile) {\r
}\r
if (!EFI_ERROR (Status)) {\r
*LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
+ if (!IsVolatile) {\r
+ mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
+ mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
+ }\r
} else {\r
- *LastVariableOffset = 0;\r
+ NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);\r
+ while (IsValidVariableHeader (NextVariable)) {\r
+ VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
+ if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+ } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+ }\r
+\r
+ NextVariable = GetNextVariablePtr (NextVariable);\r
+ }\r
+ *LastVariableOffset = (UINTN) NextVariable - (UINTN) VariableBase;\r
}\r
\r
+ if (NewPubKeyStore != NULL) {\r
+ FreePool (NewPubKeyStore);\r
+ }\r
+\r
+ if (NewPubKeyIndex != NULL) {\r
+ FreePool (NewPubKeyIndex);\r
+ }\r
+ \r
FreePool (ValidBuffer);\r
\r
return Status;\r
UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);\r
if (!Variable->Volatile) {\r
CacheVariable->CurrPtr->State = State;\r
+ FlushHobVariableToFlash (VariableName, VendorGuid);\r
}\r
}\r
goto Done;\r
//\r
// Perform garbage collection & reclaim operation.\r
//\r
- Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
- &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr);\r
+ Status = Reclaim (\r
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
+ &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+ FALSE,\r
+ Variable->CurrPtr,\r
+ FALSE,\r
+ FALSE\r
+ );\r
if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
//\r
// Perform garbage collection & reclaim operation.\r
//\r
- Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,\r
- &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr);\r
+ Status = Reclaim (\r
+ mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,\r
+ &mVariableModuleGlobal->VolatileLastVariableOffset,\r
+ TRUE,\r
+ Variable->CurrPtr,\r
+ FALSE,\r
+ FALSE\r
+ );\r
if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
\r
if (!EFI_ERROR (Status)) {\r
UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
+ if (!Volatile) {\r
+ FlushHobVariableToFlash (VariableName, VendorGuid);\r
+ }\r
}\r
\r
Done:\r
return Status;\r
}\r
\r
+/**\r
+ Check if a Unicode character is a hexadecimal character.\r
+\r
+ This function checks if a Unicode character is a \r
+ hexadecimal character. The valid hexadecimal character is \r
+ L'0' to L'9', L'a' to L'f', or L'A' to L'F'.\r
+\r
+\r
+ @param Char The character to check against.\r
+\r
+ @retval TRUE If the Char is a hexadecmial character.\r
+ @retval FALSE If the Char is not a hexadecmial character.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsHexaDecimalDigitCharacter (\r
+ IN CHAR16 Char\r
+ )\r
+{\r
+ return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));\r
+}\r
+\r
+/**\r
+\r
+ This code checks if variable is hardware error record variable or not.\r
+\r
+ According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid\r
+ and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.\r
+\r
+ @param VariableName Pointer to variable name.\r
+ @param VendorGuid Variable Vendor Guid.\r
+\r
+ @retval TRUE Variable is hardware error record variable.\r
+ @retval FALSE Variable is not hardware error record variable.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsHwErrRecVariable (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
+ )\r
+{\r
+ if (!CompareGuid (VendorGuid, &gEfiHardwareErrorVariableGuid) ||\r
+ (StrLen (VariableName) != StrLen (L"HwErrRec####")) ||\r
+ (StrnCmp(VariableName, L"HwErrRec", StrLen (L"HwErrRec")) != 0) ||\r
+ !IsHexaDecimalDigitCharacter (VariableName[0x8]) ||\r
+ !IsHexaDecimalDigitCharacter (VariableName[0x9]) ||\r
+ !IsHexaDecimalDigitCharacter (VariableName[0xA]) ||\r
+ !IsHexaDecimalDigitCharacter (VariableName[0xB])) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ This code checks if variable should be treated as read-only variable.\r
+\r
+ @param[in] VariableName Name of the Variable.\r
+ @param[in] VendorGuid GUID of the Variable.\r
+\r
+ @retval TRUE This variable is read-only variable.\r
+ @retval FALSE This variable is NOT read-only variable.\r
+ \r
+**/\r
+BOOLEAN\r
+IsReadOnlyVariable (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
+ )\r
+{\r
+ if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) {\r
+ if ((StrCmp (VariableName, EFI_SETUP_MODE_NAME) == 0) ||\r
+ (StrCmp (VariableName, EFI_SIGNATURE_SUPPORT_NAME) == 0) ||\r
+ (StrCmp (VariableName, EFI_SECURE_BOOT_MODE_NAME) == 0)) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ \r
+ return FALSE;\r
+}\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
+ This function may be invoked in SMM mode, and datasize is external input.\r
+ This function will do basic validation, before parse the data.\r
+\r
@param VariableName Name of Variable to be found.\r
@param VendorGuid Variable vendor GUID.\r
@param Attributes Attribute value of the variable found.\r
\r
This code Finds the Next available variable.\r
\r
+ Caution: This function may receive untrusted input.\r
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.\r
+\r
@param VariableNameSize Size of the variable name.\r
@param VariableName Pointer to variable name.\r
@param VendorGuid Variable Vendor Guid.\r
\r
This code sets variable in storage blocks (Volatile or Non-Volatile).\r
\r
+ Caution: This function may receive untrusted input.\r
+ This function may be invoked in SMM mode, and datasize and data are external input.\r
+ This function will do basic validation, before parse the data.\r
+ This function will parse the authentication carefully to avoid security issues, like\r
+ buffer overflow, integer overflow.\r
+ This function will check attribute carefully to avoid authentication bypass.\r
+\r
@param VariableName Name of Variable to be found.\r
@param VendorGuid Variable vendor GUID.\r
@param Attributes Attribute value of the variable found\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ if (IsReadOnlyVariable (VariableName, VendorGuid)) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
if (DataSize != 0 && Data == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ //\r
+ // Check for reserverd bit in variable attribute.\r
+ //\r
+ if ((Attributes & (~EFI_VARIABLE_ATTRIBUTES_MASK)) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
//\r
// Make sure if runtime bit is set, boot service bit is set also.\r
//\r
(sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- //\r
- // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX".\r
- //\r
- if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {\r
+ if (!IsHwErrRecVariable(VariableName, VendorGuid)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
} else {\r
}\r
}\r
\r
+ if (AtRuntime ()) {\r
+ //\r
+ // HwErrRecSupport Global Variable identifies the level of hardware error record persistence\r
+ // support implemented by the platform. This variable is only modified by firmware and is read-only to the OS.\r
+ //\r
+ if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, L"HwErrRecSupport") == 0)) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+ }\r
+\r
AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
\r
//\r
Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE);\r
} else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && \r
((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0))) {\r
- Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
+ Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
+ }\r
} else {\r
Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
}\r
\r
This code returns information about the EFI variables.\r
\r
+ Caution: This function may receive untrusted input.\r
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.\r
+\r
@param Attributes Attributes bitmask to specify the type of variables\r
on which to return information.\r
@param MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
/**\r
This function reclaims variable storage if free size is below the threshold.\r
\r
+ Caution: This function may be invoked at SMM mode.\r
+ Care must be taken to make sure not security issue.\r
+\r
**/\r
VOID\r
ReclaimForOS(\r
mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
&mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
FALSE,\r
- NULL\r
+ NULL,\r
+ FALSE,\r
+ FALSE\r
);\r
ASSERT_EFI_ERROR (Status);\r
}\r
}\r
\r
+/**\r
+ Flush the HOB variable to flash.\r
+\r
+ @param[in] VariableName Name of variable has been updated or deleted.\r
+ @param[in] VendorGuid Guid of variable has been updated or deleted.\r
+\r
+**/\r
+VOID\r
+FlushHobVariableToFlash (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VARIABLE_STORE_HEADER *VariableStoreHeader;\r
+ VARIABLE_HEADER *Variable;\r
+ VOID *VariableData;\r
+ BOOLEAN ErrorFlag;\r
+\r
+ ErrorFlag = FALSE;\r
+\r
+ //\r
+ // Flush the HOB variable to flash.\r
+ //\r
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
+ //\r
+ // Set HobVariableBase to 0, it can avoid SetVariable to call back.\r
+ //\r
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;\r
+ for ( Variable = GetStartPointer (VariableStoreHeader)\r
+ ; (Variable < GetEndPointer (VariableStoreHeader) && IsValidVariableHeader (Variable))\r
+ ; Variable = GetNextVariablePtr (Variable)\r
+ ) {\r
+ if (Variable->State != VAR_ADDED) {\r
+ //\r
+ // The HOB variable has been set to DELETED state in local.\r
+ //\r
+ continue;\r
+ }\r
+ ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);\r
+ if (VendorGuid == NULL || VariableName == NULL ||\r
+ !CompareGuid (VendorGuid, &Variable->VendorGuid) ||\r
+ StrCmp (VariableName, GetVariableNamePtr (Variable)) != 0) {\r
+ VariableData = GetVariableDataPtr (Variable);\r
+ Status = VariableServiceSetVariable (\r
+ GetVariableNamePtr (Variable),\r
+ &Variable->VendorGuid,\r
+ Variable->Attributes,\r
+ Variable->DataSize,\r
+ VariableData\r
+ );\r
+ DEBUG ((EFI_D_INFO, "Variable driver flush the HOB variable to flash: %g %s %r\n", &Variable->VendorGuid, GetVariableNamePtr (Variable), Status));\r
+ } else {\r
+ //\r
+ // The updated or deleted variable is matched with the HOB variable.\r
+ // Don't break here because we will try to set other HOB variables\r
+ // since this variable could be set successfully.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // If set variable successful, or the updated or deleted variable is matched with the HOB variable,\r
+ // set the HOB variable to DELETED state in local.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", &Variable->VendorGuid, GetVariableNamePtr (Variable)));\r
+ Variable->State &= VAR_DELETED;\r
+ } else {\r
+ ErrorFlag = TRUE;\r
+ }\r
+ }\r
+ if (ErrorFlag) {\r
+ //\r
+ // We still have HOB variable(s) not flushed in flash.\r
+ //\r
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;\r
+ } else {\r
+ //\r
+ // All HOB variables have been flushed in flash.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "Variable driver: all HOB variables have been flushed in flash.\n"));\r
+ if (!AtRuntime ()) {\r
+ FreePool ((VOID *) VariableStoreHeader);\r
+ }\r
+ }\r
+ }\r
+\r
+}\r
\r
/**\r
Initializes variable write service after FVB was ready.\r
UINTN Index;\r
UINT8 Data;\r
EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
- VARIABLE_HEADER *Variable;\r
- VOID *VariableData;\r
\r
VariableStoreBase = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
&mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
FALSE,\r
- NULL\r
+ NULL,\r
+ FALSE,\r
+ TRUE\r
);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
}\r
\r
-\r
- //\r
- // Flush the HOB variable to flash and invalidate HOB variable.\r
- //\r
- if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
- //\r
- // Clear the HobVariableBase to avoid SetVariable() updating the variable in HOB\r
- //\r
- VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
- mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;\r
-\r
- for ( Variable = GetStartPointer (VariableStoreHeader)\r
- ; (Variable < GetEndPointer (VariableStoreHeader) && IsValidVariableHeader (Variable))\r
- ; Variable = GetNextVariablePtr (Variable)\r
- ) {\r
- ASSERT (Variable->State == VAR_ADDED);\r
- ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);\r
- VariableData = GetVariableDataPtr (Variable);\r
- Status = VariableServiceSetVariable (\r
- GetVariableNamePtr (Variable),\r
- &Variable->VendorGuid,\r
- Variable->Attributes,\r
- Variable->DataSize,\r
- VariableData\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
- }\r
+ FlushHobVariableToFlash (NULL, NULL);\r
\r
//\r
// Authenticated variable initialize.\r
GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);\r
if (GuidHob != NULL) {\r
VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);\r
+ VariableStoreLength = (UINT64) (GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE));\r
if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
- mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;\r
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);\r
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
} else {\r
DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));\r
}\r