summaryrefslogtreecommitdiff
path: root/SecurityPkg/VariableAuthenticated/RuntimeDxe
diff options
context:
space:
mode:
authorStar Zeng <star.zeng@intel.com>2013-07-03 09:09:42 +0000
committerlzeng14 <lzeng14@6f19259b-4bc3-4df7-8a09-765794883524>2013-07-03 09:09:42 +0000
commit039a40aa3b4eefbb4a149da4977ab3ef6c483a0f (patch)
treefbb49cb35f0c0d737daf0a84371ba243ed49d1e9 /SecurityPkg/VariableAuthenticated/RuntimeDxe
parent3e02ebb2bbe0fd4da880511b1f35951e1c4b8404 (diff)
downloadedk2-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')
-rw-r--r--SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c231
-rw-r--r--SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h1
-rw-r--r--SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf3
-rw-r--r--SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf3
4 files changed, 155 insertions, 83 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);
}
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h
index f394414b3f..ebd0b50b14 100644
--- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h
+++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h
@@ -41,6 +41,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Guid/AuthenticatedVariableFormat.h>
#include <Guid/ImageAuthentication.h>
#include <Guid/SystemNvDataGuid.h>
+#include <Guid/FaultTolerantWrite.h>
#include <Guid/HardwareErrorVariable.h>
#define VARIABLE_RECLAIM_THRESHOLD (1024)
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf
index dbd7d6e470..4904adae2e 100644
--- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf
+++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf
@@ -6,7 +6,7 @@
# This external input must be validated carefully to avoid security issue like
# buffer overflow, integer overflow.
#
-# Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
@@ -84,6 +84,7 @@
gEfiCertDbGuid
gEfiHardwareErrorVariableGuid ## SOMETIMES_CONSUMES
gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
+ gEdkiiFaultTolerantWriteGuid ## CONSUMES
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf
index a9a10976eb..4180309c7f 100644
--- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf
+++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf
@@ -14,7 +14,7 @@
# This external input must be validated carefully to avoid security issue like
# buffer overflow, integer overflow.
#
-# Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
@@ -89,6 +89,7 @@
gEfiSystemNvDataFvGuid ## CONSUMES
gEfiCertDbGuid
gEfiHardwareErrorVariableGuid ## SOMETIMES_CONSUMES
+ gEdkiiFaultTolerantWriteGuid ## CONSUMES
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize