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) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<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
///\r
VARIABLE_STORE_HEADER *mNvVariableCache = NULL;\r
\r
+///\r
+/// Memory cache of Fv Header.\r
+///\r
+EFI_FIRMWARE_VOLUME_HEADER *mNvFvHeaderCache = NULL;\r
+\r
///\r
/// The memory entry used for variable statistics data.\r
///\r
IN EFI_GUID *VendorGuid\r
);\r
\r
+/**\r
+ Initialization for MOR Lock Control.\r
+\r
+ @retval EFI_SUCEESS MorLock initialization success.\r
+ @return Others Some error occurs.\r
+**/\r
+EFI_STATUS\r
+MorLockInit (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ This service is an MOR/MorLock checker handler for the SetVariable().\r
+\r
+ @param VariableName the name of the vendor's variable, as a\r
+ Null-Terminated Unicode String\r
+ @param VendorGuid Unify identifier for vendor.\r
+ @param Attributes Point to memory location to return the attributes of variable. If the point\r
+ is NULL, the parameter would be ignored.\r
+ @param DataSize The size in bytes of Data-Buffer.\r
+ @param Data Point to the content of the variable.\r
+\r
+ @retval EFI_SUCCESS The MOR/MorLock check pass, and Variable driver can store the variable data.\r
+ @retval EFI_INVALID_PARAMETER The MOR/MorLock data or data size or attributes is not allowed for MOR variable.\r
+ @retval EFI_ACCESS_DENIED The MOR/MorLock is locked.\r
+ @retval EFI_ALREADY_STARTED The MorLock variable is handled inside this function.\r
+ Variable driver can just return EFI_SUCCESS.\r
+**/\r
+EFI_STATUS\r
+SetVariableCheckHandlerMor (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN UINT32 Attributes,\r
+ IN UINTN DataSize,\r
+ IN VOID *Data\r
+ );\r
+\r
/**\r
Routine used to track statistical information about variable usage.\r
The data is stored in the EFI system table so it can be accessed later.\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
+ for (PtrBlockMapEntry = mNvFvHeaderCache->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
//\r
// Check to see if the Variable Writes are spanning through multiple\r
//\r
// Update the data in NV cache.\r
//\r
- *VarErrFlag = Flag;\r
+ *VarErrFlag = TempFlag;\r
}\r
}\r
}\r
mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;\r
} else {\r
+ mVariableModuleGlobal->HwErrVariableTotalSize = 0;\r
+ mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
+ mVariableModuleGlobal->CommonUserVariableTotalSize = 0;\r
Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);\r
while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase))) {\r
NextVariable = GetNextVariablePtr (Variable);\r
ASSERT_EFI_ERROR (Status);\r
\r
TotalNeededSize = 0;\r
- Args = Marker;\r
+ VA_COPY (Args, Marker);\r
VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
while (VariableEntry != NULL) {\r
//\r
return FALSE;\r
}\r
\r
- Args = Marker;\r
+ VA_COPY (Args, Marker);\r
VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
while (VariableEntry != NULL) {\r
//\r
// go to delete this variable in variable HOB and\r
// try to flush other variables from HOB to flash.\r
//\r
+ UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, FALSE, TRUE, FALSE);\r
FlushHobVariableToFlash (VariableName, VendorGuid);\r
return EFI_SUCCESS;\r
}\r
VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
Variable = &NvVariable;\r
Variable->StartPtr = GetStartPointer (VariableStoreHeader);\r
- Variable->EndPtr = GetEndPointer (VariableStoreHeader);\r
+ Variable->EndPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->EndPtr - (UINTN)CacheVariable->StartPtr));\r
+\r
Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));\r
if (CacheVariable->InDeletedTransitionPtr != NULL) {\r
Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr - (UINTN)CacheVariable->StartPtr));\r
//\r
// Only variable that have NV attributes can be updated/deleted in Runtime.\r
//\r
- if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+ if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
Status = EFI_INVALID_PARAMETER;\r
goto Done;\r
}\r
//\r
// Only variable that have RT attributes can be updated/deleted in Runtime.\r
//\r
- if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {\r
+ if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {\r
Status = EFI_INVALID_PARAMETER;\r
goto Done;\r
}\r
// Both ADDED and IN_DELETED_TRANSITION variable are present,\r
// set IN_DELETED_TRANSITION one to DELETED state first.\r
//\r
- State = Variable->InDeletedTransitionPtr->State;\r
+ ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
+ State = CacheVariable->InDeletedTransitionPtr->State;\r
State &= VAR_DELETED;\r
Status = UpdateVariableStore (\r
&mVariableModuleGlobal->VariableGlobal,\r
);\r
if (!EFI_ERROR (Status)) {\r
if (!Variable->Volatile) {\r
- ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
CacheVariable->InDeletedTransitionPtr->State = State;\r
}\r
} else {\r
}\r
}\r
\r
- State = Variable->CurrPtr->State;\r
+ State = CacheVariable->CurrPtr->State;\r
State &= VAR_DELETED;\r
\r
Status = UpdateVariableStore (\r
// If the variable is marked valid, and the same data has been passed in,\r
// then return to the caller immediately.\r
//\r
- if (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&\r
- (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0) &&\r
+ if (DataSizeOfVariable (CacheVariable->CurrPtr) == DataSize &&\r
+ (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr), DataSize) == 0) &&\r
((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) &&\r
(TimeStamp == NULL)) {\r
//\r
UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);\r
Status = EFI_SUCCESS;\r
goto Done;\r
- } else if ((Variable->CurrPtr->State == VAR_ADDED) ||\r
- (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
+ } else if ((CacheVariable->CurrPtr->State == VAR_ADDED) ||\r
+ (CacheVariable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
\r
//\r
// EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.\r
// NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.\r
// From DataOffset of NextVariable is to save the existing variable data.\r
//\r
- DataOffset = GetVariableDataOffset (Variable->CurrPtr);\r
+ DataOffset = GetVariableDataOffset (CacheVariable->CurrPtr);\r
BufferForMerge = (UINT8 *) ((UINTN) NextVariable + DataOffset);\r
- CopyMem (BufferForMerge, (UINT8 *) ((UINTN) Variable->CurrPtr + DataOffset), DataSizeOfVariable (Variable->CurrPtr));\r
+ CopyMem (BufferForMerge, (UINT8 *) ((UINTN) CacheVariable->CurrPtr + DataOffset), DataSizeOfVariable (CacheVariable->CurrPtr));\r
\r
//\r
// Set Max Common/Auth Variable Data Size as default MaxDataSize.\r
MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - DataOffset;\r
}\r
\r
- if (DataSizeOfVariable (Variable->CurrPtr) + DataSize > MaxDataSize) {\r
+ if (DataSizeOfVariable (CacheVariable->CurrPtr) + DataSize > MaxDataSize) {\r
//\r
// Existing data size + new data size exceed maximum variable size limitation.\r
//\r
Status = EFI_INVALID_PARAMETER;\r
goto Done;\r
}\r
- CopyMem ((UINT8*) ((UINTN) BufferForMerge + DataSizeOfVariable (Variable->CurrPtr)), Data, DataSize);\r
- MergedBufSize = DataSizeOfVariable (Variable->CurrPtr) + DataSize;\r
+ CopyMem ((UINT8*) ((UINTN) BufferForMerge + DataSizeOfVariable (CacheVariable->CurrPtr)), Data, DataSize);\r
+ MergedBufSize = DataSizeOfVariable (CacheVariable->CurrPtr) + DataSize;\r
\r
//\r
// BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.\r
//\r
// Mark the old variable as in delete transition.\r
//\r
- State = Variable->CurrPtr->State;\r
+ State = CacheVariable->CurrPtr->State;\r
State &= VAR_IN_DELETED_TRANSITION;\r
\r
Status = UpdateVariableStore (\r
// with the variable, we need associate the new timestamp with the updated value.\r
//\r
if (Variable->CurrPtr != NULL) {\r
- if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER *) Variable->CurrPtr)->TimeStamp), TimeStamp)) {\r
+ if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER *) CacheVariable->CurrPtr)->TimeStamp), TimeStamp)) {\r
CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));\r
}\r
}\r
// Both ADDED and IN_DELETED_TRANSITION old variable are present,\r
// set IN_DELETED_TRANSITION one to DELETED state first.\r
//\r
- State = Variable->InDeletedTransitionPtr->State;\r
+ ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
+ State = CacheVariable->InDeletedTransitionPtr->State;\r
State &= VAR_DELETED;\r
Status = UpdateVariableStore (\r
&mVariableModuleGlobal->VariableGlobal,\r
);\r
if (!EFI_ERROR (Status)) {\r
if (!Variable->Volatile) {\r
- ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
CacheVariable->InDeletedTransitionPtr->State = State;\r
}\r
} else {\r
}\r
}\r
\r
+ //\r
+ // Special Handling for MOR Lock variable.\r
+ //\r
+ Status = SetVariableCheckHandlerMor (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize));\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ //\r
+ // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().\r
+ // Variable driver can just return SUCCESS.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
Status = VarCheckLibSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize), mRequestSource);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
UINT32 HwErrStorageSize;\r
UINT32 MaxUserNvVariableSpaceSize;\r
UINT32 BoottimeReservedNvVariableSpaceSize;\r
+ EFI_STATUS Status;\r
+ VOID *FtwProtocol;\r
\r
mVariableModuleGlobal->FvbInstance = NULL;\r
\r
//\r
CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize);\r
\r
+ Status = GetFtwProtocol ((VOID **)&FtwProtocol);\r
//\r
- // Check the FTW last write data hob.\r
+ // If FTW protocol has been installed, no need to check FTW last write data hob.\r
//\r
- GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);\r
- if (GuidHob != NULL) {\r
- FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);\r
- if (FtwLastWriteData->TargetAddress == NvStorageBase) {\r
- DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));\r
- //\r
- // Copy the backed up NV storage data to the memory buffer from spare block.\r
- //\r
- CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize);\r
- } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&\r
- (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {\r
- //\r
- // Flash NV storage from the Offset is backed up in spare block.\r
- //\r
- BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);\r
- BackUpSize = NvStorageSize - BackUpOffset;\r
- DEBUG ((EFI_D_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));\r
- //\r
- // Copy the partial backed up NV storage data to the memory buffer from spare block.\r
- //\r
- CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Check the FTW last write data hob.\r
+ //\r
+ GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);\r
+ if (GuidHob != NULL) {\r
+ FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);\r
+ if (FtwLastWriteData->TargetAddress == NvStorageBase) {\r
+ DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));\r
+ //\r
+ // Copy the backed up NV storage data to the memory buffer from spare block.\r
+ //\r
+ CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize);\r
+ } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&\r
+ (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {\r
+ //\r
+ // Flash NV storage from the Offset is backed up in spare block.\r
+ //\r
+ BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);\r
+ BackUpSize = NvStorageSize - BackUpOffset;\r
+ DEBUG ((EFI_D_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));\r
+ //\r
+ // Copy the partial backed up NV storage data to the memory buffer from spare block.\r
+ //\r
+ CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize);\r
+ }\r
}\r
}\r
\r
VariableStoreBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) FvHeader + FvHeader->HeaderLength);\r
VariableStoreLength = (UINT64) (NvStorageSize - FvHeader->HeaderLength);\r
\r
+ mNvFvHeaderCache = FvHeader;\r
mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;\r
if (GetVariableStoreStatus (mNvVariableCache) != EfiValid) {\r
FreePool (NvStorageData);\r
+ mNvFvHeaderCache = NULL;\r
+ mNvVariableCache = NULL;\r
DEBUG((EFI_D_ERROR, "Variable Store header is corrupted\n"));\r
return EFI_VOLUME_CORRUPTED;\r
}\r
)\r
{\r
EFI_STATUS Status;\r
- VARIABLE_STORE_HEADER *VariableStoreHeader;\r
UINTN Index;\r
UINT8 Data;\r
EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
if (NvStorageBase == 0) {\r
NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
}\r
- VariableStoreBase = NvStorageBase + (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(NvStorageBase))->HeaderLength);\r
+ VariableStoreBase = NvStorageBase + (mNvFvHeaderCache->HeaderLength);\r
\r
//\r
// Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.\r
//\r
mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
- VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
\r
//\r
// Check if the free area is really free.\r
//\r
- for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
+ for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < mNvVariableCache->Size; Index++) {\r
Data = ((UINT8 *) mNvVariableCache)[Index];\r
if (Data != 0xff) {\r
//\r
}\r
\r
ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+\r
+ //\r
+ // Initialize MOR Lock variable.\r
+ //\r
+ MorLockInit ();\r
+\r
return Status;\r
}\r
\r