diff options
author | Star Zeng <star.zeng@intel.com> | 2013-07-03 09:09:42 +0000 |
---|---|---|
committer | lzeng14 <lzeng14@6f19259b-4bc3-4df7-8a09-765794883524> | 2013-07-03 09:09:42 +0000 |
commit | 039a40aa3b4eefbb4a149da4977ab3ef6c483a0f (patch) | |
tree | fbb49cb35f0c0d737daf0a84371ba243ed49d1e9 /SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c | |
parent | 3e02ebb2bbe0fd4da880511b1f35951e1c4b8404 (diff) | |
download | edk2-platforms-039a40aa3b4eefbb4a149da4977ab3ef6c483a0f.tar.xz |
SecurityPkg: Variable drivers robustly handle crashes during Reclaim().
PEI variable implementation checks only the variable header signature for validity. This does not seem robust if system crash occurred during previous Reclaim() operation. If the crash occurred while FTW was rewriting the variable FV, the signature could be valid even though the rest of the FV isn't valid.
Solution: PEI variable and early phase(before FTW protocol ready) of DXE variable can check the FTW last write status provided by FaultTolerantWritePei and determine if all or partial variable data has been backed up in spare block, and then use the backed up data.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Star Zeng <star.zeng@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14455 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c')
-rw-r--r-- | SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c | 231 |
1 files changed, 150 insertions, 81 deletions
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c index 576623e88b..ef123d2d5c 100644 --- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c @@ -3069,6 +3069,135 @@ ReclaimForOS( }
/**
+ Init non-volatile variable store.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
+ @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
+
+**/
+EFI_STATUS
+InitNonVolatileVariableStore (
+ VOID
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ VARIABLE_HEADER *NextVariable;
+ EFI_PHYSICAL_ADDRESS VariableStoreBase;
+ UINT64 VariableStoreLength;
+ UINTN VariableSize;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_PHYSICAL_ADDRESS NvStorageBase;
+ UINT8 *NvStorageData;
+ UINT32 NvStorageSize;
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
+ UINT32 BackUpOffset;
+ UINT32 BackUpSize;
+
+ mVariableModuleGlobal->FvbInstance = NULL;
+
+ //
+ // Note that in EdkII variable driver implementation, Hardware Error Record type variable
+ // is stored with common variable in the same NV region. So the platform integrator should
+ // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of
+ // PcdFlashNvStorageVariableSize.
+ //
+ ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));
+
+ //
+ // Allocate runtime memory used for a memory copy of the FLASH region.
+ // Keep the memory and the FLASH in sync as updates occur.
+ //
+ NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
+ NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);
+ if (NvStorageData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);
+ if (NvStorageBase == 0) {
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
+ }
+ //
+ // Copy NV storage data to the memory buffer.
+ //
+ CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize);
+
+ //
+ // Check the FTW last write data hob.
+ //
+ GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
+ if (GuidHob != NULL) {
+ FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);
+ if (FtwLastWriteData->TargetAddress == NvStorageBase) {
+ DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));
+ //
+ // Copy the backed up NV storage data to the memory buffer from spare block.
+ //
+ CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize);
+ } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&
+ (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {
+ //
+ // Flash NV storage from the Offset is backed up in spare block.
+ //
+ BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);
+ BackUpSize = NvStorageSize - BackUpOffset;
+ 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));
+ //
+ // Copy the partial backed up NV storage data to the memory buffer from spare block.
+ //
+ CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize);
+ }
+ }
+
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) NvStorageData;
+
+ //
+ // Check if the Firmware Volume is not corrupted
+ //
+ if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {
+ FreePool (NvStorageData);
+ DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ VariableStoreBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) FvHeader + FvHeader->HeaderLength);
+ VariableStoreLength = (UINT64) (NvStorageSize - FvHeader->HeaderLength);
+
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
+ mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;
+ if (GetVariableStoreStatus (mNvVariableCache) != EfiValid) {
+ FreePool (NvStorageData);
+ DEBUG((EFI_D_ERROR, "Variable Store header is corrupted\n"));
+ return EFI_VOLUME_CORRUPTED;
+ }
+ ASSERT(mNvVariableCache->Size == VariableStoreLength);
+
+ //
+ // The max variable or hardware error variable size should be < variable store size.
+ //
+ ASSERT(MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) < VariableStoreLength);
+
+ //
+ // Parse non-volatile variable data and get last variable offset.
+ //
+ NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);
+ while (IsValidVariableHeader (NextVariable)) {
+ VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);
+ if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);
+ } else {
+ mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);
+ }
+
+ NextVariable = GetNextVariablePtr (NextVariable);
+ }
+ mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;
+
+ return EFI_SUCCESS;
+}
+
+/**
Flush the HOB variable to flash.
@param[in] VariableName Name of variable has been updated or deleted.
@@ -3159,7 +3288,7 @@ FlushHobVariableToFlash ( }
/**
- Initializes variable write service after FVB was ready.
+ Initializes variable write service after FTW was ready.
@retval EFI_SUCCESS Function successfully executed.
@retval Others Fail to initialize the variable service.
@@ -3175,8 +3304,18 @@ VariableWriteServiceInitialize ( UINTN Index;
UINT8 Data;
EFI_PHYSICAL_ADDRESS VariableStoreBase;
+ EFI_PHYSICAL_ADDRESS NvStorageBase;
+
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);
+ if (NvStorageBase == 0) {
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
+ }
+ VariableStoreBase = NvStorageBase + (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(NvStorageBase))->HeaderLength);
- VariableStoreBase = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
+ //
+ // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.
+ //
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;
//
@@ -3229,12 +3368,8 @@ VariableCommonInitialize ( EFI_STATUS Status;
VARIABLE_STORE_HEADER *VolatileVariableStore;
VARIABLE_STORE_HEADER *VariableStoreHeader;
- VARIABLE_HEADER *NextVariable;
- EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;
- EFI_PHYSICAL_ADDRESS VariableStoreBase;
UINT64 VariableStoreLength;
UINTN ScratchSize;
- UINTN VariableSize;
EFI_HOB_GUID_TYPE *GuidHob;
//
@@ -3248,14 +3383,6 @@ VariableCommonInitialize ( InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);
//
- // Note that in EdkII variable driver implementation, Hardware Error Record type variable
- // is stored with common variable in the same NV region. So the platform integrator should
- // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of
- // PcdFlashNvStorageVariableSize.
- //
- ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));
-
- //
// Get HOB variable store.
//
GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
@@ -3265,6 +3392,7 @@ VariableCommonInitialize ( if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);
if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {
+ FreePool (mVariableModuleGlobal);
return EFI_OUT_OF_RESOURCES;
}
} else {
@@ -3278,6 +3406,9 @@ VariableCommonInitialize ( ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));
VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
if (VolatileVariableStore == NULL) {
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
+ FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);
+ }
FreePool (mVariableModuleGlobal);
return EFI_OUT_OF_RESOURCES;
}
@@ -3289,7 +3420,6 @@ VariableCommonInitialize ( //
mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;
- mVariableModuleGlobal->FvbInstance = NULL;
CopyGuid (&VolatileVariableStore->Signature, &gEfiAuthenticatedVariableGuid);
VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);
@@ -3299,74 +3429,13 @@ VariableCommonInitialize ( VolatileVariableStore->Reserved1 = 0;
//
- // Get non-volatile variable store.
- //
-
- TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);
- if (TempVariableStoreHeader == 0) {
- TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
- }
-
- //
- // Check if the Firmware Volume is not corrupted
- //
- if ((((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->Signature != EFI_FVH_SIGNATURE) ||
- (!CompareGuid (&gEfiSystemNvDataFvGuid, &((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->FileSystemGuid))) {
- Status = EFI_VOLUME_CORRUPTED;
- DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
- goto Done;
- }
-
- VariableStoreBase = TempVariableStoreHeader + \
- (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);
- VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \
- (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);
-
- mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
- VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;
- if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
- Status = EFI_VOLUME_CORRUPTED;
- DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));
- goto Done;
- }
- ASSERT(VariableStoreHeader->Size == VariableStoreLength);
-
- //
- // The max variable or hardware error variable size should be < variable store size.
- //
- ASSERT(MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) < VariableStoreLength);
-
- //
- // Parse non-volatile variable data and get last variable offset.
+ // Init non-volatile variable store.
//
- NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);
- while (IsValidVariableHeader (NextVariable)) {
- VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);
- if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
- mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);
- } else {
- mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);
- }
-
- NextVariable = GetNextVariablePtr (NextVariable);
- }
-
- mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;
-
- //
- // Allocate runtime memory used for a memory copy of the FLASH region.
- // Keep the memory and the FLASH in sync as updates occur
- //
- mNvVariableCache = AllocateRuntimeZeroPool ((UINTN)VariableStoreLength);
- if (mNvVariableCache == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableStoreBase, (UINTN)VariableStoreLength);
- Status = EFI_SUCCESS;
-
-Done:
+ Status = InitNonVolatileVariableStore ();
if (EFI_ERROR (Status)) {
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
+ FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);
+ }
FreePool (mVariableModuleGlobal);
FreePool (VolatileVariableStore);
}
|