summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--IntelFrameworkModulePkg/Universal/BdsDxe/Bds.h3
-rw-r--r--IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf3
-rw-r--r--IntelFrameworkModulePkg/Universal/BdsDxe/BdsEntry.c37
-rw-r--r--MdeModulePkg/Include/Guid/SmmVariableCommon.h6
-rw-r--r--MdeModulePkg/Include/Protocol/VariableLock.h63
-rw-r--r--MdeModulePkg/MdeModulePkg.dec10
-rw-r--r--MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.h1
-rw-r--r--MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf1
-rw-r--r--MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf1
-rw-r--r--MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c18
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c105
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h32
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c82
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf6
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c105
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf3
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c79
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf3
-rw-r--r--SecurityPkg/Include/Guid/PhysicalPresenceData.h25
-rw-r--r--SecurityPkg/Include/Guid/TcgEventHob.h4
-rw-r--r--SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.c98
-rw-r--r--SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.inf3
-rw-r--r--SecurityPkg/SecurityPkg.dec4
-rw-r--r--SecurityPkg/Tcg/TcgDxe/TpmComm.c13
-rw-r--r--SecurityPkg/Tcg/TcgSmm/TcgSmm.c19
-rw-r--r--SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c105
-rw-r--r--SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h32
-rw-r--r--SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableDxe.c88
-rw-r--r--SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf4
-rw-r--r--SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.c105
-rw-r--r--SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf1
-rw-r--r--SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.c79
-rw-r--r--SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.inf1
-rw-r--r--SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfig.vfr29
-rw-r--r--SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c87
-rw-r--r--SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigNvData.h1
36 files changed, 1142 insertions, 114 deletions
diff --git a/IntelFrameworkModulePkg/Universal/BdsDxe/Bds.h b/IntelFrameworkModulePkg/Universal/BdsDxe/Bds.h
index 0929f1d..14996f6 100644
--- a/IntelFrameworkModulePkg/Universal/BdsDxe/Bds.h
+++ b/IntelFrameworkModulePkg/Universal/BdsDxe/Bds.h
@@ -1,7 +1,7 @@
/** @file
Head file for BDS Architectural Protocol implementation
-Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2004 - 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
@@ -47,6 +47,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Protocol/SimpleTextInEx.h>
#include <Protocol/DriverHealth.h>
#include <Protocol/BootLogo.h>
+#include <Protocol/VariableLock.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/PrintLib.h>
diff --git a/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf b/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf
index a60738e..2424a8a 100644
--- a/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf
+++ b/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf
@@ -14,7 +14,7 @@
# BDSDxe also maintain the UI for "Boot Manager, Boot Maintaince Manager, Device Manager" which
# is used for user to configure boot option or maintain hardware device.
#
-# Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2008 - 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
@@ -160,6 +160,7 @@
gEfiDriverHealthProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES
gEfiPciIoProtocolGuid ## PROTOCOL CONSUMES
gEfiBootLogoProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES
+ gEdkiiVariableLockProtocolGuid ## PROTOCOL CONSUMES
[FeaturePcd]
gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate
diff --git a/IntelFrameworkModulePkg/Universal/BdsDxe/BdsEntry.c b/IntelFrameworkModulePkg/Universal/BdsDxe/BdsEntry.c
index 2b62ac5..f5953c3 100644
--- a/IntelFrameworkModulePkg/Universal/BdsDxe/BdsEntry.c
+++ b/IntelFrameworkModulePkg/Universal/BdsDxe/BdsEntry.c
@@ -38,6 +38,17 @@ EFI_BDS_ARCH_PROTOCOL gBds = {
UINT16 *mBootNext = NULL;
+///
+/// The read-only variables defined in UEFI Spec.
+///
+CHAR16 *mReadOnlyVariables[] = {
+ L"PlatformLangCodes",
+ L"LangCodes",
+ L"BootOptionSupport",
+ L"HwErrRecSupport",
+ L"OsIndicationsSupported"
+ };
+
/**
Install Boot Device Selection Protocol
@@ -459,6 +470,8 @@ BdsEntry (
CHAR16 *FirmwareVendor;
EFI_STATUS Status;
UINT16 BootTimeOut;
+ UINTN Index;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
//
// Insert the performance probe
@@ -496,6 +509,18 @@ BdsEntry (
BdsFormalizeEfiGlobalVariable();
//
+ // Mark the read-only variables if the Variable Lock protocol exists
+ //
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
+ DEBUG ((EFI_D_INFO, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status));
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < sizeof (mReadOnlyVariables) / sizeof (mReadOnlyVariables[0]); Index++) {
+ Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ //
// Report Status Code to indicate connecting drivers will happen
//
REPORT_STATUS_CODE (
@@ -503,12 +528,6 @@ BdsEntry (
(EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS)
);
- //
- // Do the platform init, can be customized by OEM/IBV
- //
- PERF_START (NULL, "PlatformBds", "BDS", 0);
- PlatformBdsInit ();
-
InitializeHwErrRecSupport();
//
@@ -539,6 +558,12 @@ BdsEntry (
InitializeFrontPage (TRUE);
//
+ // Do the platform init, can be customized by OEM/IBV
+ //
+ PERF_START (NULL, "PlatformBds", "BDS", 0);
+ PlatformBdsInit ();
+
+ //
// Set up the device list based on EFI 1.1 variables
// process Driver#### and Load the driver's in the
// driver option list
diff --git a/MdeModulePkg/Include/Guid/SmmVariableCommon.h b/MdeModulePkg/Include/Guid/SmmVariableCommon.h
index 478fd05..a2daae8 100644
--- a/MdeModulePkg/Include/Guid/SmmVariableCommon.h
+++ b/MdeModulePkg/Include/Guid/SmmVariableCommon.h
@@ -60,6 +60,10 @@ typedef struct {
// is gEfiSmmVariableProtocolGuid.
//
#define SMM_VARIABLE_FUNCTION_GET_STATISTICS 7
+//
+// The payload for this function is SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
+//
+#define SMM_VARIABLE_FUNCTION_LOCK_VARIABLE 8
///
/// Size of SMM communicate header, without including the payload.
@@ -101,4 +105,6 @@ typedef struct {
UINT32 Attributes;
} SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO;
+typedef SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE;
+
#endif // _SMM_VARIABLE_COMMON_H_ \ No newline at end of file
diff --git a/MdeModulePkg/Include/Protocol/VariableLock.h b/MdeModulePkg/Include/Protocol/VariableLock.h
new file mode 100644
index 0000000..a2a73bc
--- /dev/null
+++ b/MdeModulePkg/Include/Protocol/VariableLock.h
@@ -0,0 +1,63 @@
+/** @file
+ Variable Lock Protocol is related to EDK II-specific implementation of variables
+ and intended for use as a means to mark a variable read-only after the event
+ EFI_END_OF_DXE_EVENT_GUID is signaled.
+
+ Copyright (c) 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
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __VARIABLE_LOCK_H__
+#define __VARIABLE_LOCK_H__
+
+#define EDKII_VARIABLE_LOCK_PROTOCOL_GUID \
+ { \
+ 0xcd3d0a05, 0x9e24, 0x437c, { 0xa8, 0x91, 0x1e, 0xe0, 0x53, 0xdb, 0x76, 0x38 } \
+ }
+
+typedef struct _EDKII_VARIABLE_LOCK_PROTOCOL EDKII_VARIABLE_LOCK_PROTOCOL;
+
+/**
+ Mark a variable that will become read-only after leaving the DXE phase of execution.
+ Write request coming from SMM environment through EFI_SMM_VARIABLE_PROTOCOL is allowed.
+
+ @param[in] This The EDKII_VARIABLE_LOCK_PROTOCOL instance.
+ @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
+ @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
+
+ @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
+ as pending to be read-only.
+ @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
+ Or VariableName is an empty string.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EDKII_VARIABLE_LOCK_PROTOCOL_REQUEST_TO_LOCK) (
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ );
+
+///
+/// Variable Lock Protocol is related to EDK II-specific implementation of variables
+/// and intended for use as a means to mark a variable read-only after the event
+/// EFI_END_OF_DXE_EVENT_GUID is signaled.
+///
+struct _EDKII_VARIABLE_LOCK_PROTOCOL {
+ EDKII_VARIABLE_LOCK_PROTOCOL_REQUEST_TO_LOCK RequestToLock;
+};
+
+extern EFI_GUID gEdkiiVariableLockProtocolGuid;
+
+#endif
+
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index b47f7ed..bd2bd45 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -326,6 +326,10 @@
# Include/Protocol/SmmVariableProtocol.h
gEfiSmmVariableProtocolGuid = { 0xed32d533, 0x99e6, 0x4209, { 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7 }}
+ ## This protocol is intended for use as a means to mark a variable read-only after the event EFI_END_OF_DXE_EVENT_GUID is signaled.
+ # Include/Protocol/VariableLock.h
+ gEdkiiVariableLockProtocolGuid = { 0xcd3d0a05, 0x9e24, 0x437c, { 0xa8, 0x91, 0x1e, 0xe0, 0x53, 0xdb, 0x76, 0x38 }}
+
## This protocol is similar with DXE FVB protocol and used in the UEFI SMM evvironment.
# Include/Protocol/SmmFirmwareVolumeBlock.h
gEfiSmmFirmwareVolumeBlockProtocolGuid = { 0xd326d041, 0xbd31, 0x4c01, { 0xb5, 0xa8, 0x62, 0x8b, 0xe8, 0x7f, 0x6, 0x53 }}
@@ -542,7 +546,7 @@
## The size of volatile buffer. This buffer is used to store VOLATILE attribute variable.
gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x10000|UINT32|0x30000005
- ## Size of the FTW spare block range. Note that this value should larger than PcdFlashNvStorageVariableSize
+ ## Size of the FTW spare block range. Note that this value should larger than PcdFlashNvStorageVariableSize and block size aligned.
# The root cause is that variable driver will use FTW protocol to reclaim variable region.
# If the length of variable region is larger than FTW spare size, it means the whole variable region can not
# be reflushed through the manner of fault tolerant write.
@@ -667,7 +671,7 @@
## Base address of the NV variable range in flash device
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0x0|UINT32|0x30000001
- ## Base address of the FTW spare block range in flash device.
+ ## Base address of the FTW spare block range in flash device. Note that this value should be block size aligned.
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase|0x0|UINT32|0x30000013
## Base address of the FTW working block range in flash device.
@@ -676,7 +680,7 @@
## 64-bit Base address of the NV variable range in flash device
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|0x0|UINT64|0x80000001
- ## 64-bit Base address of the FTW spare block range in flash device.
+ ## 64-bit Base address of the FTW spare block range in flash device. Note that this value should be block size aligned.
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|0x0|UINT64|0x80000013
## 64-bit Base address of the FTW working block range in flash device.
diff --git a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.h b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.h
index 8deae88..0d775d1 100644
--- a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.h
+++ b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.h
@@ -32,6 +32,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
+#include <Library/ReportStatusCodeLib.h>
//
// Flash erase polarity is 1
diff --git a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
index f60ab28..979f2ae 100644
--- a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
+++ b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
@@ -47,6 +47,7 @@
DebugLib
UefiLib
PcdLib
+ ReportStatusCodeLib
[Guids]
gEfiSystemNvDataFvGuid ## CONSUMES ## FV Signature of Working Space Header
diff --git a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
index c39f84c..563f28a 100644
--- a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
+++ b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
@@ -50,6 +50,7 @@
DebugLib
UefiLib
PcdLib
+ ReportStatusCodeLib
[Guids]
gEfiSystemNvDataFvGuid ## CONSUMES ## FV Signature of Working Space Header
diff --git a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c
index 2e4052c..6a19522 100644
--- a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c
+++ b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c
@@ -1110,6 +1110,20 @@ FindFvbForFtw (
ASSERT (FALSE);
return EFI_ABORTED;
}
+ //
+ // Check the alignment of spare area address and length, they should be block size aligned
+ //
+ if (((FtwDevice->SpareAreaAddress & (FtwDevice->BlockSize - 1)) != 0) ||
+ ((FtwDevice->SpareAreaLength & (FtwDevice->BlockSize - 1)) != 0)) {
+ DEBUG ((EFI_D_ERROR, "Ftw: Spare area address or length is not block size aligned\n"));
+ FreePool (HandleBuffer);
+ //
+ // Report Status Code EFI_SW_EC_ABORTED.
+ //
+ REPORT_STATUS_CODE ( (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED), (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_ABORTED));
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+ }
break;
}
}
@@ -1117,12 +1131,12 @@ FindFvbForFtw (
}
}
FreePool (HandleBuffer);
-
+
if ((FtwDevice->FtwBackupFvb == NULL) || (FtwDevice->FtwFvBlock == NULL) ||
(FtwDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) || (FtwDevice->FtwSpareLba == (EFI_LBA) (-1))) {
return EFI_ABORTED;
}
-
+
return EFI_SUCCESS;
}
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
index cd3f5ef..9f983ff 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
@@ -21,12 +21,28 @@ VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
///
/// Define a memory cache that improves the search performance for a variable.
///
-VARIABLE_STORE_HEADER *mNvVariableCache = NULL;
+VARIABLE_STORE_HEADER *mNvVariableCache = NULL;
///
/// The memory entry used for variable statistics data.
///
-VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
+VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
+
+///
+/// The list to store the variables which cannot be set after the EFI_END_OF_DXE_EVENT_GROUP_GUID
+/// or EVT_GROUP_READY_TO_BOOT event.
+///
+LIST_ENTRY mLockedVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mLockedVariableList);
+
+///
+/// The flag to indicate whether the platform has left the DXE phase of execution.
+///
+BOOLEAN mEndOfDxe = FALSE;
+
+///
+/// The flag to indicate whether the variable storage locking is enabled.
+///
+BOOLEAN mEnableLocking = TRUE;
/**
@@ -1919,6 +1935,58 @@ IsHwErrRecVariable (
}
/**
+ Mark a variable that will become read-only after leaving the DXE phase of execution.
+
+ @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
+ @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
+ @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
+
+ @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
+ as pending to be read-only.
+ @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
+ Or VariableName is an empty string.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
+**/
+EFI_STATUS
+EFIAPI
+VariableLockRequestToLock (
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ VARIABLE_ENTRY *Entry;
+
+ if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mEndOfDxe) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ Entry = AllocateRuntimePool (sizeof (*Entry) + StrSize (VariableName));
+ if (Entry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUG ((EFI_D_INFO, "[Variable] Lock: %g:%s\n", VendorGuid, VariableName));
+
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ Entry->Name = (CHAR16 *) (Entry + 1);
+ StrCpy (Entry->Name, VariableName);
+ CopyGuid (&Entry->Guid, VendorGuid);
+ InsertTailList (&mLockedVariableList, &Entry->Link);
+
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ return EFI_SUCCESS;
+}
+
+/**
This code finds variable in storage blocks (Volatile or Non-Volatile).
@@ -2192,6 +2260,8 @@ VariableServiceSetVariable (
EFI_STATUS Status;
VARIABLE_HEADER *NextVariable;
EFI_PHYSICAL_ADDRESS Point;
+ LIST_ENTRY *Link;
+ VARIABLE_ENTRY *Entry;
//
// Check input parameters.
@@ -2247,16 +2317,6 @@ VariableServiceSetVariable (
}
}
- if (AtRuntime ()) {
- //
- // HwErrRecSupport Global Variable identifies the level of hardware error record persistence
- // support implemented by the platform. This variable is only modified by firmware and is read-only to the OS.
- //
- if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, L"HwErrRecSupport") == 0)) {
- return EFI_WRITE_PROTECTED;
- }
- }
-
AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
//
@@ -2275,13 +2335,31 @@ VariableServiceSetVariable (
mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;
}
+ if (mEndOfDxe && mEnableLocking) {
+ //
+ // Treat the variables listed in the forbidden variable list as read-only after leaving DXE phase.
+ //
+ for ( Link = GetFirstNode (&mLockedVariableList)
+ ; !IsNull (&mLockedVariableList, Link)
+ ; Link = GetNextNode (&mLockedVariableList, Link)
+ ) {
+ Entry = BASE_CR (Link, VARIABLE_ENTRY, Link);
+ if (CompareGuid (&Entry->Guid, VendorGuid) && (StrCmp (Entry->Name, VariableName) == 0)) {
+ Status = EFI_WRITE_PROTECTED;
+ DEBUG ((EFI_D_INFO, "[Variable]: Changing readonly variable after leaving DXE phase - %g:%s\n", VendorGuid, VariableName));
+ goto Done;
+ }
+ }
+ }
+
//
// Check whether the input variable is already existed.
//
Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);
if (!EFI_ERROR (Status)) {
if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {
- return EFI_WRITE_PROTECTED;
+ Status = EFI_WRITE_PROTECTED;
+ goto Done;
}
}
@@ -2292,6 +2370,7 @@ VariableServiceSetVariable (
Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);
+Done:
InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
index 8504ce0..b5e6ede 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
@@ -22,6 +22,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Protocol/FaultTolerantWrite.h>
#include <Protocol/FirmwareVolumeBlock.h>
#include <Protocol/Variable.h>
+#include <Protocol/VariableLock.h>
#include <Library/PcdLib.h>
#include <Library/HobLib.h>
#include <Library/UefiDriverEntryPoint.h>
@@ -97,6 +98,12 @@ typedef struct {
VOID *Data;
} VARIABLE_CACHE_ENTRY;
+typedef struct {
+ EFI_GUID Guid;
+ CHAR16 *Name;
+ LIST_ENTRY Link;
+} VARIABLE_ENTRY;
+
/**
Flush the HOB variable to flash.
@@ -456,7 +463,30 @@ VariableServiceQueryVariableInfo (
OUT UINT64 *RemainingVariableStorageSize,
OUT UINT64 *MaximumVariableSize
);
-
+
+/**
+ Mark a variable that will become read-only after leaving the DXE phase of execution.
+
+ @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
+ @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
+ @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
+
+ @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
+ as pending to be read-only.
+ @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
+ Or VariableName is an empty string.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
+**/
+EFI_STATUS
+EFIAPI
+VariableLockRequestToLock (
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ );
+
extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
#endif
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
index ba4d29a..c02d637 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
@@ -3,7 +3,8 @@
Implement all four UEFI Runtime Variable services for the nonvolatile
and volatile storage space and install variable architecture protocol.
-Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+Copyright (C) 2013, Red Hat, Inc.
+Copyright (c) 2006 - 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
@@ -21,6 +22,9 @@ extern VARIABLE_INFO_ENTRY *gVariableInfo;
EFI_HANDLE mHandle = NULL;
EFI_EVENT mVirtualAddressChangeEvent = NULL;
EFI_EVENT mFtwRegistration = NULL;
+extern LIST_ENTRY mLockedVariableList;
+extern BOOLEAN mEndOfDxe;
+EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock = { VariableLockRequestToLock };
/**
Return TRUE if ExitBootServices () has been called.
@@ -218,6 +222,10 @@ VariableClassAddressChangeEvent (
IN VOID *Context
)
{
+ LIST_ENTRY *Link;
+ VARIABLE_ENTRY *Entry;
+ EFI_STATUS Status;
+
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);
@@ -234,6 +242,23 @@ VariableClassAddressChangeEvent (
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.HobVariableBase);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);
EfiConvertPointer (0x0, (VOID **) &mNvVariableCache);
+
+ //
+ // in the list of locked variables, convert the name pointers first
+ //
+ for ( Link = GetFirstNode (&mLockedVariableList)
+ ; !IsNull (&mLockedVariableList, Link)
+ ; Link = GetNextNode (&mLockedVariableList, Link)
+ ) {
+ Entry = BASE_CR (Link, VARIABLE_ENTRY, Link);
+ Status = EfiConvertPointer (0x0, (VOID **) &Entry->Name);
+ ASSERT_EFI_ERROR (Status);
+ }
+ //
+ // second, convert the list itself using UefiRuntimeLib
+ //
+ Status = EfiConvertList (0x0, &mLockedVariableList);
+ ASSERT_EFI_ERROR (Status);
}
@@ -255,12 +280,34 @@ OnReadyToBoot (
VOID *Context
)
{
+ //
+ // Set the End Of DXE bit in case the EFI_END_OF_DXE_EVENT_GROUP_GUID event is not signaled.
+ //
+ mEndOfDxe = TRUE;
ReclaimForOS ();
if (FeaturePcdGet (PcdVariableCollectStatistics)) {
gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);
}
}
+/**
+ Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
+
+ This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+OnEndOfDxe (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ mEndOfDxe = TRUE;
+}
/**
Fault Tolerant Write protocol notification event handler.
@@ -288,6 +335,7 @@ FtwNotificationEvent (
UINT64 Length;
EFI_PHYSICAL_ADDRESS VariableStoreBase;
UINT64 VariableStoreLength;
+ UINTN FtwMaxBlockSize;
//
// Ensure FTW protocol is installed.
@@ -296,7 +344,12 @@ FtwNotificationEvent (
if (EFI_ERROR (Status)) {
return ;
}
-
+
+ Status = FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (PcdGet32 (PcdFlashNvStorageVariableSize) <= FtwMaxBlockSize);
+ }
+
//
// Find the proper FVB protocol for variable.
//
@@ -375,11 +428,20 @@ VariableServiceInitialize (
)
{
EFI_STATUS Status;
- EFI_EVENT ReadyToBootEvent;
+ EFI_EVENT ReadyToBootEvent;
+ EFI_EVENT EndOfDxeEvent;
Status = VariableCommonInitialize ();
ASSERT_EFI_ERROR (Status);
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEdkiiVariableLockProtocolGuid,
+ &mVariableLock,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
SystemTable->RuntimeServices->GetVariable = VariableServiceGetVariable;
SystemTable->RuntimeServices->GetNextVariableName = VariableServiceGetNextVariableName;
SystemTable->RuntimeServices->SetVariable = VariableServiceSetVariable;
@@ -426,6 +488,20 @@ VariableServiceInitialize (
NULL,
&ReadyToBootEvent
);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register the event handling function to set the End Of DXE flag.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ OnEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &EndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
index 28b69c3..8cbefef 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
@@ -2,7 +2,7 @@
# Component description file for Variable module.
#
# This module installs three EFI_RUNTIME_SERVICES: SetVariable, GetVariable, GetNextVariableName.
-# Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2006 - 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
@@ -59,13 +59,15 @@
gEfiVariableWriteArchProtocolGuid ## ALWAYS_PRODUCES
gEfiVariableArchProtocolGuid ## ALWAYS_PRODUCES
gEfiFaultTolerantWriteProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiVariableLockProtocolGuid ## ALWAYS_PRODUCES
[Guids]
gEfiVariableGuid ## PRODUCES ## Configuration Table Guid
gEfiGlobalVariableGuid ## PRODUCES ## Variable Guid
- gEfiEventVirtualAddressChangeGuid ## PRODUCES ## Event
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
gEfiSystemNvDataFvGuid ## CONSUMES
gEfiHardwareErrorVariableGuid ## SOMETIMES_CONSUMES
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
index a3a07f1..a80948b 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
@@ -29,6 +29,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Protocol/SmmFirmwareVolumeBlock.h>
#include <Protocol/SmmFaultTolerantWrite.h>
#include <Protocol/SmmAccess2.h>
+#include <Protocol/SmmEndOfDxe.h>
#include <Library/SmmServicesTableLib.h>
@@ -46,15 +47,61 @@ BOOLEAN mAtRuntime = F
EFI_GUID mZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
UINT8 *mVariableBufferPayload = NULL;
UINTN mVariableBufferPayloadSize;
+extern BOOLEAN mEndOfDxe;
+extern BOOLEAN mEnableLocking;
+
+/**
+
+ This code sets variable in storage blocks (Volatile or Non-Volatile).
+
+ @param VariableName Name of Variable to be found.
+ @param VendorGuid Variable vendor GUID.
+ @param Attributes Attribute value of the variable found
+ @param DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param Data Data pointer.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SUCCESS Set successfully.
+ @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
+ @return EFI_NOT_FOUND Not found.
+ @return EFI_WRITE_PROTECTED Variable is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmVariableSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Disable write protection when the calling SetVariable() through EFI_SMM_VARIABLE_PROTOCOL.
+ //
+ mEnableLocking = FALSE;
+ Status = VariableServiceSetVariable (
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data
+ );
+ mEnableLocking = TRUE;
+ return Status;
+}
EFI_SMM_VARIABLE_PROTOCOL gSmmVariable = {
VariableServiceGetVariable,
VariableServiceGetNextVariableName,
- VariableServiceSetVariable,
+ SmmVariableSetVariable,
VariableServiceQueryVariableInfo
};
-
/**
Return TRUE if ExitBootServices () has been called.
@@ -450,6 +497,7 @@ SmmVariableHandler (
SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *GetNextVariableName;
SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *QueryVariableInfo;
VARIABLE_INFO_ENTRY *VariableInfo;
+ SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;
UINTN InfoSize;
UINTN NameBufferSize;
UINTN CommBufferPayloadSize;
@@ -638,6 +686,7 @@ SmmVariableHandler (
break;
case SMM_VARIABLE_FUNCTION_READY_TO_BOOT:
+ mEndOfDxe = TRUE;
if (AtRuntime()) {
Status = EFI_UNSUPPORTED;
break;
@@ -670,6 +719,19 @@ SmmVariableHandler (
*CommBufferSize = InfoSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
break;
+ case SMM_VARIABLE_FUNCTION_LOCK_VARIABLE:
+ if (mEndOfDxe) {
+ Status = EFI_ACCESS_DENIED;
+ } else {
+ VariableToLock = (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *) SmmVariableFunctionHeader->Data;
+ Status = VariableLockRequestToLock (
+ NULL,
+ VariableToLock->Name,
+ &VariableToLock->Guid
+ );
+ }
+ break;
+
default:
Status = EFI_UNSUPPORTED;
}
@@ -681,6 +743,28 @@ EXIT:
return EFI_SUCCESS;
}
+/**
+ SMM END_OF_DXE protocol notification event handler.
+
+ @param Protocol Points to the protocol's unique identifier
+ @param Interface Points to the interface instance
+ @param Handle The handle on which the interface was installed
+
+ @retval EFI_SUCCESS SmmEndOfDxeCallback runs successfully
+
+**/
+EFI_STATUS
+EFIAPI
+SmmEndOfDxeCallback (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ DEBUG ((EFI_D_INFO, "[Variable]END_OF_DXE is signaled\n"));
+ mEndOfDxe = TRUE;
+ return EFI_SUCCESS;
+}
/**
SMM Fault Tolerant Write protocol notification event handler.
@@ -708,6 +792,7 @@ SmmFtwNotificationEvent (
EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
EFI_PHYSICAL_ADDRESS NvStorageVariableBase;
+ UINTN FtwMaxBlockSize;
if (mVariableModuleGlobal->FvbInstance != NULL) {
return EFI_SUCCESS;
@@ -721,6 +806,11 @@ SmmFtwNotificationEvent (
return Status;
}
+ Status = FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (PcdGet32 (PcdFlashNvStorageVariableSize) <= FtwMaxBlockSize);
+ }
+
//
// Find the proper FVB protocol for variable.
//
@@ -777,6 +867,7 @@ VariableServiceInitialize (
VOID *SmmFtwRegistration;
EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;
UINTN Size;
+ VOID *SmmEndOfDxeRegistration;
//
// Variable initialize.
@@ -847,6 +938,16 @@ VariableServiceInitialize (
ASSERT_EFI_ERROR (Status);
//
+ // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.
+ //
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmEndOfDxeProtocolGuid,
+ SmmEndOfDxeCallback,
+ &SmmEndOfDxeRegistration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
// Register FtwNotificationEvent () notify function.
//
Status = gSmst->SmmRegisterProtocolNotify (
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
index e2c5d9c..c229805 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
+++ b/MdeModulePkg/Universal/Variable/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
@@ -69,6 +69,7 @@
gEfiSmmVariableProtocolGuid ## ALWAYS_PRODUCES
gEfiSmmFaultTolerantWriteProtocolGuid ## SOMETIMES_CONSUMES
gEfiSmmAccess2ProtocolGuid ## ALWAYS_CONSUMES
+ gEfiSmmEndOfDxeProtocolGuid ## ALWAYS_CONSUMES
[Guids]
gEfiVariableGuid ## PRODUCES ## Configuration Table Guid
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
index eb67bae..e7b1014 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
@@ -19,6 +19,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Protocol/Variable.h>
#include <Protocol/SmmCommunication.h>
#include <Protocol/SmmVariable.h>
+#include <Protocol/VariableLock.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
@@ -44,6 +45,7 @@ UINT8 *mVariableBufferPhysical = NULL;
UINTN mVariableBufferSize;
UINTN mVariableBufferPayloadSize;
EFI_LOCK mVariableServicesLock;
+EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock;
/**
Acquires lock only at boot time. Simply returns at runtime.
@@ -160,6 +162,73 @@ SendCommunicateBuffer (
return SmmVariableFunctionHeader->ReturnStatus;
}
+/**
+ Mark a variable that will become read-only after leaving the DXE phase of execution.
+
+ @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
+ @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
+ @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
+
+ @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
+ as pending to be read-only.
+ @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
+ Or VariableName is an empty string.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
+**/
+EFI_STATUS
+EFIAPI
+VariableLockRequestToLock (
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN VariableNameSize;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;
+
+ if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableNameSize = StrSize (VariableName);
+
+ //
+ // If VariableName exceeds SMM payload limit. Return failure
+ //
+ if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+ //
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;
+ Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (VariableToLock != NULL);
+
+ CopyGuid (&VariableToLock->Guid, VendorGuid);
+ VariableToLock->NameSize = VariableNameSize;
+ CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
/**
This code finds variable in storage blocks (Volatile or Non-Volatile).
@@ -722,6 +791,7 @@ VariableSmmRuntimeInitialize (
IN EFI_SYSTEM_TABLE *SystemTable
)
{
+ EFI_STATUS Status;
VOID *SmmVariableRegistration;
VOID *SmmVariableWriteRegistration;
EFI_EVENT OnReadyToBootEvent;
@@ -729,6 +799,15 @@ VariableSmmRuntimeInitialize (
EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);
+ mVariableLock.RequestToLock = VariableLockRequestToLock;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEdkiiVariableLockProtocolGuid,
+ &mVariableLock,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
//
// Smm variable service is ready
//
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
index 05dd49d..761ea66 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
@@ -4,7 +4,7 @@
# This module is the Runtime DXE part correspond to SMM variable module. It
# installs variable arch protocol and variable write arch protocol and works
# with SMM variable module together.
-# Copyright (c) 2010 - 2011, 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
@@ -54,6 +54,7 @@
gEfiVariableArchProtocolGuid ## ALWAYS_PRODUCES
gEfiSmmCommunicationProtocolGuid
gEfiSmmVariableProtocolGuid
+ gEdkiiVariableLockProtocolGuid ## ALWAYS_PRODUCES
[Guids]
gEfiEventVirtualAddressChangeGuid ## PRODUCES ## Event
diff --git a/SecurityPkg/Include/Guid/PhysicalPresenceData.h b/SecurityPkg/Include/Guid/PhysicalPresenceData.h
index 4db20a7..9428657 100644
--- a/SecurityPkg/Include/Guid/PhysicalPresenceData.h
+++ b/SecurityPkg/Include/Guid/PhysicalPresenceData.h
@@ -4,7 +4,7 @@
cleared after it is processed in the next boot cycle. The TPM response
is saved to variable.
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 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
@@ -29,18 +29,9 @@ typedef struct {
UINT8 PPRequest; ///< Physical Presence request command.
UINT8 LastPPRequest;
UINT32 PPResponse;
- UINT8 Flags;
} EFI_PHYSICAL_PRESENCE;
//
-// The definition bit of the flags
-//
-#define FLAG_NO_PPI_PROVISION BIT0
-#define FLAG_NO_PPI_CLEAR BIT1
-#define FLAG_NO_PPI_MAINTENANCE BIT2
-#define FLAG_RESET_TRACK BIT3
-
-//
// The definition of physical presence operation actions
//
#define PHYSICAL_PRESENCE_NO_ACTION 0
@@ -67,6 +58,20 @@ typedef struct {
#define PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR 21
#define PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE 22
+//
+// This variable is used to save TPM Management Flags and corresponding operations.
+// It should be protected from malicious software (e.g. Set it as read-only variable).
+//
+#define PHYSICAL_PRESENCE_FLAGS_VARIABLE L"PhysicalPresenceFlags"
+
+//
+// The definition bit of the TPM Management Flags
+//
+#define FLAG_NO_PPI_PROVISION BIT0
+#define FLAG_NO_PPI_CLEAR BIT1
+#define FLAG_NO_PPI_MAINTENANCE BIT2
+#define FLAG_RESET_TRACK BIT3
+
extern EFI_GUID gEfiPhysicalPresenceGuid;
#endif
diff --git a/SecurityPkg/Include/Guid/TcgEventHob.h b/SecurityPkg/Include/Guid/TcgEventHob.h
index e88bd3a..9a1cf58 100644
--- a/SecurityPkg/Include/Guid/TcgEventHob.h
+++ b/SecurityPkg/Include/Guid/TcgEventHob.h
@@ -3,7 +3,7 @@
a TPM DXE Driver. A GUIDed HOB is generated for each measurement
made in the PEI Phase.
-Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2007 - 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
@@ -22,7 +22,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
///
#define EFI_TCG_EVENT_HOB_GUID \
{ \
- 0x2e3044ac, 0x879f, 0x490f, {0x97, 0x60, 0xbb, 0xdf, 0xaf, 0x69, 0x5f, 0x50 } \
+ 0x2b9ffb52, 0x1b13, 0x416f, { 0xa8, 0x7b, 0xbc, 0x93, 0xd, 0xef, 0x92, 0xa8 } \
}
extern EFI_GUID gTcgEventEntryHobGuid;
diff --git a/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.c b/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.c
index 3414cd2..427cc8d 100644
--- a/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.c
+++ b/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.c
@@ -22,6 +22,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <PiDxe.h>
#include <Protocol/TcgService.h>
+#include <Protocol/VariableLock.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
@@ -909,12 +910,11 @@ UserConfirm (
BOOLEAN
HaveValidTpmRequest (
IN EFI_PHYSICAL_PRESENCE *TcgPpData,
+ IN UINT8 Flags,
OUT BOOLEAN *RequestConfirmed
)
{
- UINT8 Flags;
-
- Flags = TcgPpData->Flags;
+
*RequestConfirmed = FALSE;
switch (TcgPpData->PPRequest) {
@@ -1003,14 +1003,16 @@ HaveValidTpmRequest (
VOID
ExecutePendingTpmRequest (
IN EFI_TCG_PROTOCOL *TcgProtocol,
- IN EFI_PHYSICAL_PRESENCE *TcgPpData
+ IN EFI_PHYSICAL_PRESENCE *TcgPpData,
+ IN UINT8 Flags
)
{
EFI_STATUS Status;
UINTN DataSize;
BOOLEAN RequestConfirmed;
+ UINT8 NewFlags;
- if (!HaveValidTpmRequest(TcgPpData, &RequestConfirmed)) {
+ if (!HaveValidTpmRequest(TcgPpData, Flags, &RequestConfirmed)) {
//
// Invalid operation request.
//
@@ -1039,14 +1041,29 @@ ExecutePendingTpmRequest (
// Execute requested physical presence command
//
TcgPpData->PPResponse = TPM_PP_USER_ABORT;
+ NewFlags = Flags;
if (RequestConfirmed) {
- TcgPpData->PPResponse = ExecutePhysicalPresence (TcgProtocol, TcgPpData->PPRequest, &TcgPpData->Flags);
+ TcgPpData->PPResponse = ExecutePhysicalPresence (TcgProtocol, TcgPpData->PPRequest, &NewFlags);
}
//
+ // Save the flags if it is updated.
+ //
+ if (Flags != NewFlags) {
+ Status = gRT->SetVariable (
+ PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (UINT8),
+ &NewFlags
+ );
+ }
+
+
+ //
// Clear request
//
- if ((TcgPpData->Flags & FLAG_RESET_TRACK) == 0) {
+ if ((NewFlags & FLAG_RESET_TRACK) == 0) {
TcgPpData->LastPPRequest = TcgPpData->PPRequest;
TcgPpData->PPRequest = PHYSICAL_PRESENCE_NO_ACTION;
}
@@ -1123,11 +1140,56 @@ TcgPhysicalPresenceLibProcessRequest (
UINTN DataSize;
EFI_PHYSICAL_PRESENCE TcgPpData;
EFI_TCG_PROTOCOL *TcgProtocol;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLockProtocol;
+ UINT8 PpiFlags;
Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol);
if (EFI_ERROR (Status)) {
return ;
}
+
+ //
+ // Initialize physical presence flags.
+ //
+ DataSize = sizeof (UINT8);
+ Status = gRT->GetVariable (
+ PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpiFlags
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ PpiFlags = FLAG_NO_PPI_PROVISION;
+ Status = gRT->SetVariable (
+ PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (UINT8),
+ &PpiFlags
+ );
+ }
+ ASSERT_EFI_ERROR (Status);
+ }
+ DEBUG ((EFI_D_ERROR, "[TPM] PpiFlags = %x, Status = %r\n", PpiFlags, Status));
+
+ //
+ // This flags variable controls whether physical presence is required for TPM command.
+ // It should be protected from malicious software. We set it as read-only variable here.
+ //
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLockProtocol);
+ if (!EFI_ERROR (Status)) {
+ Status = VariableLockProtocol->RequestToLock (
+ VariableLockProtocol,
+ PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiPhysicalPresenceGuid
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[TPM] Error when lock variable %s, Status = %r\n", PHYSICAL_PRESENCE_FLAGS_VARIABLE, Status));
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
//
// Initialize physical presence variable.
@@ -1143,7 +1205,6 @@ TcgPhysicalPresenceLibProcessRequest (
if (EFI_ERROR (Status)) {
if (Status == EFI_NOT_FOUND) {
ZeroMem ((VOID*)&TcgPpData, sizeof (TcgPpData));
- TcgPpData.Flags |= FLAG_NO_PPI_PROVISION;
DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
Status = gRT->SetVariable (
PHYSICAL_PRESENCE_VARIABLE,
@@ -1156,7 +1217,7 @@ TcgPhysicalPresenceLibProcessRequest (
ASSERT_EFI_ERROR (Status);
}
- DEBUG ((EFI_D_INFO, "[TPM] Flags=%x, PPRequest=%x\n", TcgPpData.Flags, TcgPpData.PPRequest));
+ DEBUG ((EFI_D_INFO, "[TPM] Flags=%x, PPRequest=%x\n", PpiFlags, TcgPpData.PPRequest));
if (TcgPpData.PPRequest == PHYSICAL_PRESENCE_NO_ACTION) {
//
@@ -1191,7 +1252,7 @@ TcgPhysicalPresenceLibProcessRequest (
//
// Execute pending TPM request.
//
- ExecutePendingTpmRequest (TcgProtocol, &TcgPpData);
+ ExecutePendingTpmRequest (TcgProtocol, &TcgPpData, PpiFlags);
DEBUG ((EFI_D_INFO, "[TPM] PPResponse = %x\n", TcgPpData.PPResponse));
//
@@ -1223,7 +1284,8 @@ TcgPhysicalPresenceLibNeedUserConfirm(
BOOLEAN LifetimeLock;
BOOLEAN CmdEnable;
EFI_TCG_PROTOCOL *TcgProtocol;
-
+ UINT8 PpiFlags;
+
Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol);
if (EFI_ERROR (Status)) {
return FALSE;
@@ -1244,6 +1306,18 @@ TcgPhysicalPresenceLibNeedUserConfirm(
return FALSE;
}
+ DataSize = sizeof (UINT8);
+ Status = gRT->GetVariable (
+ PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpiFlags
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
if (TcgPpData.PPRequest == PHYSICAL_PRESENCE_NO_ACTION) {
//
// No operation request
@@ -1251,7 +1325,7 @@ TcgPhysicalPresenceLibNeedUserConfirm(
return FALSE;
}
- if (!HaveValidTpmRequest(&TcgPpData, &RequestConfirmed)) {
+ if (!HaveValidTpmRequest(&TcgPpData, PpiFlags, &RequestConfirmed)) {
//
// Invalid operation request.
//
diff --git a/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.inf b/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.inf
index 0a197fd..d700ed2 100644
--- a/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.inf
+++ b/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.inf
@@ -6,7 +6,7 @@
# This driver will have external input - variable.
# This external input must be validated carefully to avoid security issue.
#
-# 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
@@ -53,6 +53,7 @@
[Protocols]
gEfiTcgProtocolGuid
+ gEdkiiVariableLockProtocolGuid
[Guids]
gEfiPhysicalPresenceGuid
diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec
index 8bd7145..4c3129a 100644
--- a/SecurityPkg/SecurityPkg.dec
+++ b/SecurityPkg/SecurityPkg.dec
@@ -2,7 +2,7 @@
# This package includes the security drivers, defintions(including PPIs/PROTOCOLs/GUIDs
# and library classes) and libraries instances.
#
-# 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
@@ -45,7 +45,7 @@
gEfiCertDbGuid = { 0xd9bee56e, 0x75dc, 0x49d9, { 0xb4, 0xd7, 0xb5, 0x34, 0x21, 0xf, 0x63, 0x7a } }
## Include/Guid/TcgEventHob.h
- gTcgEventEntryHobGuid = { 0x2e3044ac, 0x879f, 0x490f, {0x97, 0x60, 0xbb, 0xdf, 0xaf, 0x69, 0x5f, 0x50 }}
+ gTcgEventEntryHobGuid = { 0x2b9ffb52, 0x1b13, 0x416f, { 0xa8, 0x7b, 0xbc, 0x93, 0xd, 0xef, 0x92, 0xa8 }}
## Include/Guid/MeasuredFvHob.h
gMeasuredFvHobGuid = { 0xb2360b42, 0x7173, 0x420a, { 0x86, 0x96, 0x46, 0xca, 0x6b, 0xab, 0x10, 0x60 }}
diff --git a/SecurityPkg/Tcg/TcgDxe/TpmComm.c b/SecurityPkg/Tcg/TcgDxe/TpmComm.c
index c47794b..96732fa 100644
--- a/SecurityPkg/Tcg/TcgDxe/TpmComm.c
+++ b/SecurityPkg/Tcg/TcgDxe/TpmComm.c
@@ -1,7 +1,7 @@
/** @file
Utility functions used by TPM Dxe driver.
-Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2005 - 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
@@ -144,10 +144,17 @@ TpmCommLogEvent (
IN UINT8 *NewEventData
)
{
- UINT32 NewLogSize;
+ UINTN NewLogSize;
+
+ //
+ // Prevent Event Overflow
+ //
+ if (NewEventHdr->EventSize > (UINTN)(~0) - sizeof (*NewEventHdr)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
NewLogSize = sizeof (*NewEventHdr) + NewEventHdr->EventSize;
- if (NewLogSize + *LogSize > MaxSize) {
+ if (NewLogSize > MaxSize - *LogSize) {
return EFI_OUT_OF_RESOURCES;
}
diff --git a/SecurityPkg/Tcg/TcgSmm/TcgSmm.c b/SecurityPkg/Tcg/TcgSmm/TcgSmm.c
index 7a16b9c..97cd916 100644
--- a/SecurityPkg/Tcg/TcgSmm/TcgSmm.c
+++ b/SecurityPkg/Tcg/TcgSmm/TcgSmm.c
@@ -8,7 +8,7 @@
PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.
-Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2011 - 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
@@ -103,7 +103,22 @@ PhysicalPresenceCallback (
}
mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_SUCCESS;
} else if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {
- Flags = PpData.Flags;
+ //
+ // Get the Physical Presence flags
+ //
+ DataSize = sizeof (UINT8);
+ Status = mSmmVariable->SmmGetVariable (
+ PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_GENERAL_FAILURE;
+ return EFI_SUCCESS;
+ }
+
RequestConfirmed = FALSE;
switch (mTcgNvs->PhysicalPresence.Request) {
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c
index f10d8f7..576623e 100644
--- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c
+++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c
@@ -35,12 +35,28 @@ VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
///
/// Define a memory cache that improves the search performance for a variable.
///
-VARIABLE_STORE_HEADER *mNvVariableCache = NULL;
+VARIABLE_STORE_HEADER *mNvVariableCache = NULL;
///
/// The memory entry used for variable statistics data.
///
-VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
+VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
+
+///
+/// The list to store the variables which cannot be set after the EFI_END_OF_DXE_EVENT_GROUP_GUID
+/// or EVT_GROUP_READY_TO_BOOT event.
+///
+LIST_ENTRY mLockedVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mLockedVariableList);
+
+///
+/// The flag to indicate whether the platform has left the DXE phase of execution.
+///
+BOOLEAN mEndOfDxe = FALSE;
+
+///
+/// The flag to indicate whether the variable storage locking is enabled.
+///
+BOOLEAN mEnableLocking = TRUE;
/**
@@ -2312,6 +2328,58 @@ IsHwErrRecVariable (
}
/**
+ Mark a variable that will become read-only after leaving the DXE phase of execution.
+
+ @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
+ @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
+ @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
+
+ @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
+ as pending to be read-only.
+ @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
+ Or VariableName is an empty string.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
+**/
+EFI_STATUS
+EFIAPI
+VariableLockRequestToLock (
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ VARIABLE_ENTRY *Entry;
+
+ if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mEndOfDxe) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ Entry = AllocateRuntimePool (sizeof (*Entry) + StrSize (VariableName));
+ if (Entry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUG ((EFI_D_INFO, "[Variable] Lock: %g:%s\n", VendorGuid, VariableName));
+
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ Entry->Name = (CHAR16 *) (Entry + 1);
+ StrCpy (Entry->Name, VariableName);
+ CopyGuid (&Entry->Guid, VendorGuid);
+ InsertTailList (&mLockedVariableList, &Entry->Link);
+
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ return EFI_SUCCESS;
+}
+
+/**
This code checks if variable should be treated as read-only variable.
@param[in] VariableName Name of the Variable.
@@ -2627,6 +2695,8 @@ VariableServiceSetVariable (
VARIABLE_HEADER *NextVariable;
EFI_PHYSICAL_ADDRESS Point;
UINTN PayloadSize;
+ LIST_ENTRY *Link;
+ VARIABLE_ENTRY *Entry;
//
// Check input parameters.
@@ -2717,16 +2787,6 @@ VariableServiceSetVariable (
}
}
- if (AtRuntime ()) {
- //
- // HwErrRecSupport Global Variable identifies the level of hardware error record persistence
- // support implemented by the platform. This variable is only modified by firmware and is read-only to the OS.
- //
- if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, L"HwErrRecSupport") == 0)) {
- return EFI_WRITE_PROTECTED;
- }
- }
-
AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
//
@@ -2745,13 +2805,31 @@ VariableServiceSetVariable (
mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;
}
+ if (mEndOfDxe && mEnableLocking) {
+ //
+ // Treat the variables listed in the forbidden variable list as read-only after leaving DXE phase.
+ //
+ for ( Link = GetFirstNode (&mLockedVariableList)
+ ; !IsNull (&mLockedVariableList, Link)
+ ; Link = GetNextNode (&mLockedVariableList, Link)
+ ) {
+ Entry = BASE_CR (Link, VARIABLE_ENTRY, Link);
+ if (CompareGuid (&Entry->Guid, VendorGuid) && (StrCmp (Entry->Name, VariableName) == 0)) {
+ Status = EFI_WRITE_PROTECTED;
+ DEBUG ((EFI_D_INFO, "[Variable]: Changing readonly variable after leaving DXE phase - %g:%s\n", VendorGuid, VariableName));
+ goto Done;
+ }
+ }
+ }
+
//
// Check whether the input variable is already existed.
//
Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);
if (!EFI_ERROR (Status)) {
if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {
- return EFI_WRITE_PROTECTED;
+ Status = EFI_WRITE_PROTECTED;
+ goto Done;
}
}
@@ -2776,6 +2854,7 @@ VariableServiceSetVariable (
Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);
}
+Done:
InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h
index 4501583..f394414 100644
--- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h
+++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h
@@ -21,6 +21,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Protocol/FaultTolerantWrite.h>
#include <Protocol/FirmwareVolumeBlock.h>
#include <Protocol/Variable.h>
+#include <Protocol/VariableLock.h>
#include <Library/PcdLib.h>
#include <Library/HobLib.h>
#include <Library/UefiDriverEntryPoint.h>
@@ -106,6 +107,12 @@ typedef struct {
VOID *Data;
} VARIABLE_CACHE_ENTRY;
+typedef struct {
+ EFI_GUID Guid;
+ CHAR16 *Name;
+ LIST_ENTRY Link;
+} VARIABLE_ENTRY;
+
/**
Flush the HOB variable to flash.
@@ -577,7 +584,30 @@ VariableServiceQueryVariableInfo (
OUT UINT64 *RemainingVariableStorageSize,
OUT UINT64 *MaximumVariableSize
);
-
+
+/**
+ Mark a variable that will become read-only after leaving the DXE phase of execution.
+
+ @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
+ @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
+ @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
+
+ @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
+ as pending to be read-only.
+ @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
+ Or VariableName is an empty string.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
+**/
+EFI_STATUS
+EFIAPI
+VariableLockRequestToLock (
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ );
+
extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
#endif
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableDxe.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableDxe.c
index f91cb5d..f1ba9c1 100644
--- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableDxe.c
+++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableDxe.c
@@ -2,7 +2,8 @@
Implement all four UEFI Runtime Variable services for the nonvolatile
and volatile storage space and install variable architecture protocol.
-Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+Copyright (C) 2013, Red Hat, Inc.
+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
@@ -16,11 +17,14 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "Variable.h"
#include "AuthService.h"
-extern VARIABLE_STORE_HEADER *mNvVariableCache;
-extern VARIABLE_INFO_ENTRY *gVariableInfo;
-EFI_HANDLE mHandle = NULL;
-EFI_EVENT mVirtualAddressChangeEvent = NULL;
-EFI_EVENT mFtwRegistration = NULL;
+extern VARIABLE_STORE_HEADER *mNvVariableCache;
+extern VARIABLE_INFO_ENTRY *gVariableInfo;
+EFI_HANDLE mHandle = NULL;
+EFI_EVENT mVirtualAddressChangeEvent = NULL;
+EFI_EVENT mFtwRegistration = NULL;
+extern LIST_ENTRY mLockedVariableList;
+extern BOOLEAN mEndOfDxe;
+EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock = { VariableLockRequestToLock };
/**
Return TRUE if ExitBootServices () has been called.
@@ -218,6 +222,10 @@ VariableClassAddressChangeEvent (
IN VOID *Context
)
{
+ LIST_ENTRY *Link;
+ VARIABLE_ENTRY *Entry;
+ EFI_STATUS Status;
+
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);
@@ -236,6 +244,23 @@ VariableClassAddressChangeEvent (
EfiConvertPointer (0x0, (VOID **) &mStorageArea);
EfiConvertPointer (0x0, (VOID **) &mSerializationRuntimeBuffer);
EfiConvertPointer (0x0, (VOID **) &mNvVariableCache);
+
+ //
+ // in the list of locked variables, convert the name pointers first
+ //
+ for ( Link = GetFirstNode (&mLockedVariableList)
+ ; !IsNull (&mLockedVariableList, Link)
+ ; Link = GetNextNode (&mLockedVariableList, Link)
+ ) {
+ Entry = BASE_CR (Link, VARIABLE_ENTRY, Link);
+ Status = EfiConvertPointer (0x0, (VOID **) &Entry->Name);
+ ASSERT_EFI_ERROR (Status);
+ }
+ //
+ // second, convert the list itself using UefiRuntimeLib
+ //
+ Status = EfiConvertList (0x0, &mLockedVariableList);
+ ASSERT_EFI_ERROR (Status);
}
@@ -257,12 +282,34 @@ OnReadyToBoot (
VOID *Context
)
{
+ //
+ // Set the End Of DXE bit in case the EFI_END_OF_DXE_EVENT_GROUP_GUID event is not signaled.
+ //
+ mEndOfDxe = TRUE;
ReclaimForOS ();
if (FeaturePcdGet (PcdVariableCollectStatistics)) {
gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, gVariableInfo);
}
}
+/**
+ Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
+
+ This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+OnEndOfDxe (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ mEndOfDxe = TRUE;
+}
/**
Fault Tolerant Write protocol notification event handler.
@@ -290,6 +337,7 @@ FtwNotificationEvent (
UINT64 Length;
EFI_PHYSICAL_ADDRESS VariableStoreBase;
UINT64 VariableStoreLength;
+ UINTN FtwMaxBlockSize;
//
// Ensure FTW protocol is installed.
@@ -299,6 +347,11 @@ FtwNotificationEvent (
return ;
}
+ Status = FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (PcdGet32 (PcdFlashNvStorageVariableSize) <= FtwMaxBlockSize);
+ }
+
//
// Find the proper FVB protocol for variable.
//
@@ -378,10 +431,19 @@ VariableServiceInitialize (
{
EFI_STATUS Status;
EFI_EVENT ReadyToBootEvent;
+ EFI_EVENT EndOfDxeEvent;
Status = VariableCommonInitialize ();
ASSERT_EFI_ERROR (Status);
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEdkiiVariableLockProtocolGuid,
+ &mVariableLock,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
SystemTable->RuntimeServices->GetVariable = VariableServiceGetVariable;
SystemTable->RuntimeServices->GetNextVariableName = VariableServiceGetNextVariableName;
SystemTable->RuntimeServices->SetVariable = VariableServiceSetVariable;
@@ -428,6 +490,20 @@ VariableServiceInitialize (
NULL,
&ReadyToBootEvent
);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register the event handling function to set the End Of DXE flag.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ OnEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &EndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf
index ab676f4..dbd7d6e 100644
--- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf
+++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf
@@ -67,11 +67,12 @@
gEfiVariableWriteArchProtocolGuid ## ALWAYS_PRODUCES
gEfiVariableArchProtocolGuid ## ALWAYS_PRODUCES
gEfiFaultTolerantWriteProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiVariableLockProtocolGuid ## ALWAYS_PRODUCES
[Guids]
gEfiAuthenticatedVariableGuid ## PRODUCES ## Configuration Table Guid
gEfiGlobalVariableGuid ## PRODUCES ## Variable Guid
- gEfiEventVirtualAddressChangeGuid ## PRODUCES ## Event
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
gEfiCertTypeRsa2048Sha256Guid
gEfiImageSecurityDatabaseGuid
gEfiCertX509Guid
@@ -82,6 +83,7 @@
gEfiSystemNvDataFvGuid ## CONSUMES
gEfiCertDbGuid
gEfiHardwareErrorVariableGuid ## SOMETIMES_CONSUMES
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.c
index 0a16d71..eaef8d1 100644
--- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.c
+++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.c
@@ -29,6 +29,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Protocol/SmmFirmwareVolumeBlock.h>
#include <Protocol/SmmFaultTolerantWrite.h>
#include <Protocol/SmmAccess2.h>
+#include <Protocol/SmmEndOfDxe.h>
#include <Library/SmmServicesTableLib.h>
@@ -46,15 +47,61 @@ BOOLEAN mAtRuntime = F
EFI_GUID mZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
UINT8 *mVariableBufferPayload = NULL;
UINTN mVariableBufferPayloadSize;
+extern BOOLEAN mEndOfDxe;
+extern BOOLEAN mEnableLocking;
+
+/**
+
+ This code sets variable in storage blocks (Volatile or Non-Volatile).
+
+ @param VariableName Name of Variable to be found.
+ @param VendorGuid Variable vendor GUID.
+ @param Attributes Attribute value of the variable found
+ @param DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param Data Data pointer.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SUCCESS Set successfully.
+ @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
+ @return EFI_NOT_FOUND Not found.
+ @return EFI_WRITE_PROTECTED Variable is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmVariableSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Disable write protection when the calling SetVariable() through EFI_SMM_VARIABLE_PROTOCOL.
+ //
+ mEnableLocking = FALSE;
+ Status = VariableServiceSetVariable (
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data
+ );
+ mEnableLocking = TRUE;
+ return Status;
+}
EFI_SMM_VARIABLE_PROTOCOL gSmmVariable = {
VariableServiceGetVariable,
VariableServiceGetNextVariableName,
- VariableServiceSetVariable,
+ SmmVariableSetVariable,
VariableServiceQueryVariableInfo
};
-
/**
Return TRUE if ExitBootServices () has been called.
@@ -455,6 +502,7 @@ SmmVariableHandler (
SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *GetNextVariableName;
SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *QueryVariableInfo;
VARIABLE_INFO_ENTRY *VariableInfo;
+ SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;
UINTN InfoSize;
UINTN NameBufferSize;
UINTN CommBufferPayloadSize;
@@ -644,6 +692,7 @@ SmmVariableHandler (
break;
case SMM_VARIABLE_FUNCTION_READY_TO_BOOT:
+ mEndOfDxe = TRUE;
if (AtRuntime()) {
Status = EFI_UNSUPPORTED;
break;
@@ -676,6 +725,19 @@ SmmVariableHandler (
*CommBufferSize = InfoSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
break;
+ case SMM_VARIABLE_FUNCTION_LOCK_VARIABLE:
+ if (mEndOfDxe) {
+ Status = EFI_ACCESS_DENIED;
+ } else {
+ VariableToLock = (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *) SmmVariableFunctionHeader->Data;
+ Status = VariableLockRequestToLock (
+ NULL,
+ VariableToLock->Name,
+ &VariableToLock->Guid
+ );
+ }
+ break;
+
default:
Status = EFI_UNSUPPORTED;
}
@@ -686,6 +748,28 @@ EXIT:
return EFI_SUCCESS;
}
+/**
+ SMM END_OF_DXE protocol notification event handler.
+
+ @param Protocol Points to the protocol's unique identifier
+ @param Interface Points to the interface instance
+ @param Handle The handle on which the interface was installed
+
+ @retval EFI_SUCCESS SmmEndOfDxeCallback runs successfully
+
+**/
+EFI_STATUS
+EFIAPI
+SmmEndOfDxeCallback (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ DEBUG ((EFI_D_INFO, "[Variable]END_OF_DXE is signaled\n"));
+ mEndOfDxe = TRUE;
+ return EFI_SUCCESS;
+}
/**
SMM Fault Tolerant Write protocol notification event handler.
@@ -713,6 +797,7 @@ SmmFtwNotificationEvent (
EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
EFI_PHYSICAL_ADDRESS NvStorageVariableBase;
+ UINTN FtwMaxBlockSize;
if (mVariableModuleGlobal->FvbInstance != NULL) {
return EFI_SUCCESS;
@@ -726,6 +811,11 @@ SmmFtwNotificationEvent (
return Status;
}
+ Status = FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (PcdGet32 (PcdFlashNvStorageVariableSize) <= FtwMaxBlockSize);
+ }
+
//
// Find the proper FVB protocol for variable.
//
@@ -782,6 +872,7 @@ VariableServiceInitialize (
VOID *SmmFtwRegistration;
EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;
UINTN Size;
+ VOID *SmmEndOfDxeRegistration;
//
// Variable initialize.
@@ -852,6 +943,16 @@ VariableServiceInitialize (
ASSERT_EFI_ERROR (Status);
//
+ // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.
+ //
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmEndOfDxeProtocolGuid,
+ SmmEndOfDxeCallback,
+ &SmmEndOfDxeRegistration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
// Register FtwNotificationEvent () notify function.
//
Status = gSmst->SmmRegisterProtocolNotify (
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf
index e0aa40a..a9a1097 100644
--- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf
+++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf
@@ -73,6 +73,7 @@
gEfiSmmVariableProtocolGuid ## ALWAYS_PRODUCES
gEfiSmmFaultTolerantWriteProtocolGuid ## SOMETIMES_CONSUMES
gEfiSmmAccess2ProtocolGuid ## ALWAYS_CONSUMES
+ gEfiSmmEndOfDxeProtocolGuid ## ALWAYS_CONSUMES
[Guids]
gEfiAuthenticatedVariableGuid ## PRODUCES ## Configuration Table Guid
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.c
index b7c7f4f..7011343 100644
--- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.c
+++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.c
@@ -29,6 +29,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Protocol/Variable.h>
#include <Protocol/SmmCommunication.h>
#include <Protocol/SmmVariable.h>
+#include <Protocol/VariableLock.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
@@ -54,6 +55,7 @@ UINT8 *mVariableBufferPhysical = NULL;
UINTN mVariableBufferSize;
UINTN mVariableBufferPayloadSize;
EFI_LOCK mVariableServicesLock;
+EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock;
/**
Acquires lock only at boot time. Simply returns at runtime.
@@ -173,6 +175,73 @@ SendCommunicateBuffer (
return SmmVariableFunctionHeader->ReturnStatus;
}
+/**
+ Mark a variable that will become read-only after leaving the DXE phase of execution.
+
+ @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
+ @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
+ @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
+
+ @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
+ as pending to be read-only.
+ @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
+ Or VariableName is an empty string.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
+**/
+EFI_STATUS
+EFIAPI
+VariableLockRequestToLock (
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN VariableNameSize;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;
+
+ if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableNameSize = StrSize (VariableName);
+
+ //
+ // If VariableName exceeds SMM payload limit. Return failure
+ //
+ if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+ //
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;
+ Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (VariableToLock != NULL);
+
+ CopyGuid (&VariableToLock->Guid, VendorGuid);
+ VariableToLock->NameSize = VariableNameSize;
+ CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
/**
This code finds variable in storage blocks (Volatile or Non-Volatile).
@@ -740,6 +809,7 @@ VariableSmmRuntimeInitialize (
IN EFI_SYSTEM_TABLE *SystemTable
)
{
+ EFI_STATUS Status;
VOID *SmmVariableRegistration;
VOID *SmmVariableWriteRegistration;
EFI_EVENT OnReadyToBootEvent;
@@ -747,6 +817,15 @@ VariableSmmRuntimeInitialize (
EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);
+ mVariableLock.RequestToLock = VariableLockRequestToLock;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEdkiiVariableLockProtocolGuid,
+ &mVariableLock,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
//
// Smm variable service is ready
//
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.inf b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.inf
index 3842f01..a287027 100644
--- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.inf
+++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.inf
@@ -59,6 +59,7 @@
gEfiVariableArchProtocolGuid ## ALWAYS_PRODUCES
gEfiSmmCommunicationProtocolGuid
gEfiSmmVariableProtocolGuid
+ gEdkiiVariableLockProtocolGuid ## ALWAYS_PRODUCES
[Guids]
gEfiEventVirtualAddressChangeGuid ## PRODUCES ## Event
diff --git a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfig.vfr b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfig.vfr
index ae4b71b..9685a9e 100644
--- a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfig.vfr
+++ b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfig.vfr
@@ -43,8 +43,10 @@ formset
//
suppressif TRUE;
checkbox varid = SECUREBOOT_CONFIGURATION.HideSecureBoot,
+ questionid = KEY_HIDE_SECURE_BOOT,
prompt = STRING_TOKEN(STR_NULL),
help = STRING_TOKEN(STR_NULL),
+ flags = INTERACTIVE,
endcheckbox;
endif;
@@ -63,20 +65,29 @@ formset
//
// Display of Oneof: 'Secure Boot Mode'
//
- oneof varid = SECUREBOOT_CONFIGURATION.SecureBootMode,
- questionid = KEY_SECURE_BOOT_MODE,
- prompt = STRING_TOKEN(STR_SECURE_BOOT_MODE_PROMPT),
- help = STRING_TOKEN(STR_SECURE_BOOT_MODE_HELP),
- flags = INTERACTIVE,
- option text = STRING_TOKEN(STR_STANDARD_MODE), value = SECURE_BOOT_MODE_STANDARD, flags = DEFAULT;
- option text = STRING_TOKEN(STR_CUSTOM_MODE), value = SECURE_BOOT_MODE_CUSTOM, flags = 0;
- endoneof;
+ disableif TRUE;
+ oneof varid = SECUREBOOT_CONFIGURATION.SecureBootMode,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_MODE_PROMPT),
+ help = STRING_TOKEN(STR_SECURE_BOOT_MODE_HELP),
+ flags = INTERACTIVE,
+ option text = STRING_TOKEN(STR_STANDARD_MODE), value = SECURE_BOOT_MODE_STANDARD, flags = 0;
+ option text = STRING_TOKEN(STR_CUSTOM_MODE), value = SECURE_BOOT_MODE_CUSTOM, flags = 0;
+ endoneof;
+ endif;
+ oneof name = SecureBootMode,
+ questionid = KEY_SECURE_BOOT_MODE,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_MODE_PROMPT),
+ help = STRING_TOKEN(STR_SECURE_BOOT_MODE_HELP),
+ flags = INTERACTIVE | NUMERIC_SIZE_1,
+ option text = STRING_TOKEN(STR_STANDARD_MODE), value = SECURE_BOOT_MODE_STANDARD, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_CUSTOM_MODE), value = SECURE_BOOT_MODE_CUSTOM, flags = 0;
+ endoneof;
//
//
// Display of 'Current Secure Boot Mode'
//
- suppressif ideqval SECUREBOOT_CONFIGURATION.SecureBootMode == SECURE_BOOT_MODE_STANDARD;
+ suppressif questionref(SecureBootMode) == SECURE_BOOT_MODE_STANDARD;
grayoutif NOT ideqval SECUREBOOT_CONFIGURATION.PhysicalPresent == 1;
goto FORMID_SECURE_BOOT_OPTION_FORM,
prompt = STRING_TOKEN(STR_SECURE_BOOT_OPTION),
diff --git a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
index ecb21d0..3dc09d8 100644
--- a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
+++ b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
@@ -48,6 +48,8 @@ HII_VENDOR_DEVICE_PATH mSecureBootHiiVendorDevicePath = {
};
+BOOLEAN mIsEnterSecureBootForm = FALSE;
+
//
// OID ASN.1 Value for Hash Algorithms
//
@@ -2378,6 +2380,11 @@ SecureBootRouteConfig (
OUT EFI_STRING *Progress
)
{
+ UINT8 *SecureBootEnable;
+ SECUREBOOT_CONFIGURATION IfrNvData;
+ UINTN BufferSize;
+ EFI_STATUS Status;
+
if (Configuration == NULL || Progress == NULL) {
return EFI_INVALID_PARAMETER;
}
@@ -2387,6 +2394,39 @@ SecureBootRouteConfig (
return EFI_NOT_FOUND;
}
+ //
+ // Get Configuration from Variable.
+ //
+ SecureBootExtractConfigFromVariable (&IfrNvData);
+
+ //
+ // Map the Configuration to the configuration block.
+ //
+ BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
+ Status = gHiiConfigRouting->ConfigToBlock (
+ gHiiConfigRouting,
+ Configuration,
+ (UINT8 *)&IfrNvData,
+ &BufferSize,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Store Buffer Storage back to EFI variable if needed
+ //
+ SecureBootEnable = NULL;
+ GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);
+ if (NULL != SecureBootEnable) {
+ FreePool (SecureBootEnable);
+ Status = SaveSecureBootVariable (IfrNvData.AttemptSecureBoot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
*Progress = Configuration + StrLen (Configuration);
return EFI_SUCCESS;
}
@@ -2443,9 +2483,29 @@ SecureBootCallback (
return EFI_INVALID_PARAMETER;
}
+ if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
+ if (QuestionId == KEY_SECURE_BOOT_MODE) {
+ mIsEnterSecureBootForm = TRUE;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
+ Status = EFI_UNSUPPORTED;
+ if (QuestionId == KEY_SECURE_BOOT_MODE) {
+ if (mIsEnterSecureBootForm) {
+ Value->u8 = SECURE_BOOT_MODE_STANDARD;
+ Status = EFI_SUCCESS;
+ }
+ }
+ return Status;
+ }
+
if ((Action != EFI_BROWSER_ACTION_CHANGED) &&
(Action != EFI_BROWSER_ACTION_CHANGING) &&
- (Action != EFI_BROWSER_ACTION_FORM_CLOSE)) {
+ (Action != EFI_BROWSER_ACTION_FORM_CLOSE) &&
+ (Action != EFI_BROWSER_ACTION_DEFAULT_STANDARD)) {
return EFI_UNSUPPORTED;
}
@@ -2713,19 +2773,7 @@ SecureBootCallback (
break;
case KEY_SECURE_BOOT_MODE:
- GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL);
- if (NULL != SecureBootMode) {
- Status = gRT->SetVariable (
- EFI_CUSTOM_MODE_NAME,
- &gEfiCustomModeEnableGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
- sizeof (UINT8),
- &Value->u8
- );
- *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
- IfrNvData->SecureBootMode = Value->u8;
- FreePool (SecureBootMode);
- }
+ mIsEnterSecureBootForm = FALSE;
break;
case KEY_SECURE_BOOT_KEK_GUID:
@@ -2760,6 +2808,17 @@ SecureBootCallback (
}
break;
}
+ } else if (Action == EFI_BROWSER_ACTION_DEFAULT_STANDARD) {
+ if (QuestionId == KEY_HIDE_SECURE_BOOT) {
+ GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);
+ if (SecureBootEnable == NULL) {
+ IfrNvData->HideSecureBoot = TRUE;
+ } else {
+ FreePool (SecureBootEnable);
+ IfrNvData->HideSecureBoot = FALSE;
+ }
+ Value->b = IfrNvData->HideSecureBoot;
+ }
} else if (Action == EFI_BROWSER_ACTION_FORM_CLOSE) {
//
// Force the platform back to Standard Mode once user leave the setup screen.
diff --git a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigNvData.h b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigNvData.h
index ea43192..c15869a 100644
--- a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigNvData.h
+++ b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigNvData.h
@@ -55,6 +55,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#define KEY_VALUE_NO_SAVE_AND_EXIT_KEK 0x1009
#define KEY_VALUE_SAVE_AND_EXIT_DBX 0x100a
#define KEY_VALUE_NO_SAVE_AND_EXIT_DBX 0x100b
+#define KEY_HIDE_SECURE_BOOT 0x100c
#define KEY_SECURE_BOOT_OPTION 0x1100
#define KEY_SECURE_BOOT_PK_OPTION 0x1101