* [Patch v2 00/28] UEFI variable protection
@ 2022-04-29 18:04 Judah Vang
2022-04-29 18:04 ` [Patch v2 01/28] MdeModulePkg: Add new GUID for Variable Store Info Judah Vang
` (29 more replies)
0 siblings, 30 replies; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel
For a more detail description of the UEFI variable protected feature you can
view the Readme.md located at the following location:
https://github.com/judahvang/edk2/tree/rpmc-update
Judah Vang (28):
MdeModulePkg: Add new GUID for Variable Store Info
SecurityPkg: Add new GUIDs for
MdeModulePkg: Update AUTH_VARIABLE_INFO struct
MdeModulePkg: Add reference to new Ppi Guid
MdeModulePkg: Add new ProtectedVariable GUIDs
MdeModulePkg: Add new include files
MdeModulePkg: Add Null ProtectedVariable Library
MdeModulePkg: Add new Variable functionality
MdeModulePkg: Add support for Protected Variables
SecurityPkg: Add new KeyService types and defines
SecurityPkg: Update RPMC APIs with index
SecurityPkg: Add new variable types and functions
SecurityPkg: Fix GetVariableKey API
SecurityPkg: Add null encryption variable libs
SecurityPkg: Add VariableKey library function
SecurityPkg: Add EncryptionVariable lib with AES
SecurityPkg: Add Protected Variable Services
MdeModulePkg: Reference Null ProtectedVariableLib
SecurityPkg: Add references to new *.inf files
ArmVirtPkg: Add reference to ProtectedVariableNull
UefiPayloadPkg: Add ProtectedVariable reference
EmulatorPkg: Add ProtectedVariable reference
OvmfPkg: Add ProtectedVariable reference
OvmfPkg: Add ProtectedVariableLib reference
OvmfPkg: Add ProtectedVariableLib reference
OvmfPkg: Add ProtectedVariableLib reference
OvmfPkg: Add ProtectedVariable reference
CryptoPkg: Enable cypto HMAC KDF library
MdeModulePkg/MdeModulePkg.dec | 13 +-
SecurityPkg/SecurityPkg.dec | 43 +-
ArmVirtPkg/ArmVirtQemu.dsc | 3 +-
EmulatorPkg/EmulatorPkg.dsc | 3 +-
MdeModulePkg/MdeModulePkg.dsc | 4 +-
OvmfPkg/AmdSev/AmdSevX64.dsc | 3 +-
OvmfPkg/Bhyve/BhyveX64.dsc | 3 +-
OvmfPkg/CloudHv/CloudHvX64.dsc | 1 +
OvmfPkg/Microvm/MicrovmX64.dsc | 3 +-
OvmfPkg/OvmfPkgIa32.dsc | 1 +
OvmfPkg/OvmfPkgIa32X64.dsc | 1 +
OvmfPkg/OvmfPkgX64.dsc | 1 +
OvmfPkg/OvmfXen.dsc | 3 +-
SecurityPkg/SecurityPkg.dsc | 13 +-
UefiPayloadPkg/UefiPayloadPkg.dsc | 2 +
CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf | 2 +-
MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf | 34 +
MdeModulePkg/Universal/Variable/Pei/VariablePei.inf | 10 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf | 3 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf | 3 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf | 4 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf | 3 +-
SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf | 43 +
SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf | 38 +
SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf | 64 +
SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf | 68 +
SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf | 67 +
SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf | 62 +
SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf | 36 +
MdeModulePkg/Include/Guid/ProtectedVariable.h | 22 +
MdeModulePkg/Include/Library/AuthVariableLib.h | 4 +-
MdeModulePkg/Include/Library/EncryptionVariableLib.h | 165 ++
MdeModulePkg/Include/Library/ProtectedVariableLib.h | 700 +++++++
MdeModulePkg/Universal/Variable/Pei/Variable.h | 80 +-
MdeModulePkg/Universal/Variable/Pei/VariableParsing.h | 309 +++
MdeModulePkg/Universal/Variable/Pei/VariableStore.h | 116 ++
MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h | 126 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h | 91 +-
MdePkg/Include/Ppi/ReadOnlyVariable2.h | 4 +-
SecurityPkg/Include/Library/RpmcLib.h | 15 +-
SecurityPkg/Include/Library/VariableKeyLib.h | 37 +-
SecurityPkg/Include/Ppi/KeyServicePpi.h | 57 +
SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h | 49 +
SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h | 611 ++++++
MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c | 449 ++++
MdeModulePkg/Universal/Variable/Pei/Variable.c | 886 ++------
MdeModulePkg/Universal/Variable/Pei/VariableParsing.c | 941 +++++++++
MdeModulePkg/Universal/Variable/Pei/VariableStore.c | 305 +++
MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c | 349 +++-
MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c | 2139 +++++++++++---------
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c | 26 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c | 167 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c | 194 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c | 320 ++-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c | 2 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c | 39 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c | 41 +-
SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c | 728 +++++++
SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c | 107 +
SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c | 2095 +++++++++++++++++++
SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c | 163 ++
SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c | 1331 ++++++++++++
SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c | 209 ++
SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c | 975 +++++++++
SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c | 233 +++
SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c | 8 +-
SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c | 59 +
SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c | 6 +-
SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni | 16 +
69 files changed, 12845 insertions(+), 1863 deletions(-)
create mode 100644 MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
create mode 100644 SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
create mode 100644 SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
create mode 100644 SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
create mode 100644 SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
create mode 100644 SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
create mode 100644 SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf
create mode 100644 SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
create mode 100644 MdeModulePkg/Include/Guid/ProtectedVariable.h
create mode 100644 MdeModulePkg/Include/Library/EncryptionVariableLib.h
create mode 100644 MdeModulePkg/Include/Library/ProtectedVariableLib.h
create mode 100644 MdeModulePkg/Universal/Variable/Pei/VariableParsing.h
create mode 100644 MdeModulePkg/Universal/Variable/Pei/VariableStore.h
create mode 100644 SecurityPkg/Include/Ppi/KeyServicePpi.h
create mode 100644 SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
create mode 100644 MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
create mode 100644 MdeModulePkg/Universal/Variable/Pei/VariableParsing.c
create mode 100644 MdeModulePkg/Universal/Variable/Pei/VariableStore.c
create mode 100644 SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
create mode 100644 SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c
create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
create mode 100644 SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c
create mode 100644 SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni
--
2.35.1.windows.2
^ permalink raw reply [flat|nested] 49+ messages in thread
* [Patch v2 01/28] MdeModulePkg: Add new GUID for Variable Store Info
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-12 9:32 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 02/28] SecurityPkg: Add new GUIDs for Judah Vang
` (28 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Discover if Variable Store Info HOB has been published
by platform driver. It contains information in regards
to HOB or NV Variable Store availability
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
MdeModulePkg/MdeModulePkg.dec | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index cf79292ec877..f39827e4eacd 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -4,7 +4,7 @@
# and libraries instances, which are used for those modules.
#
# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
-# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2007 - 2022, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
# (C) Copyright 2016 - 2019 Hewlett Packard Enterprise Development LP<BR>
# Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
@@ -93,6 +93,14 @@ [LibraryClasses]
#
TpmMeasurementLib|Include/Library/TpmMeasurementLib.h
+ ## @libraryclass Provides interfaces to encrypt/decrypt variable.
+ #
+ EncryptionVariableLib|Include/Library/EncryptionVariableLib.h
+
+ ## @libraryclass Provides interfaces to encrypt/decrypt variable.
+ #
+ ProtectedVariableLib|Include/Library/ProtectedVariableLib.h
+
## @libraryclass Provides authenticated variable services.
#
AuthVariableLib|Include/Library/AuthVariableLib.h
@@ -505,6 +513,9 @@ [Ppis]
gEdkiiPeiCapsuleOnDiskPpiGuid = { 0x71a9ea61, 0x5a35, 0x4a5d, { 0xac, 0xef, 0x9c, 0xf8, 0x6d, 0x6d, 0x67, 0xe0 } }
gEdkiiPeiBootInCapsuleOnDiskModePpiGuid = { 0xb08a11e4, 0xe2b7, 0x4b75, { 0xb5, 0x15, 0xaf, 0x61, 0x6, 0x68, 0xbf, 0xd1 } }
+ ## Include/Ppi/ReadOnlyVariable2.h
+ gEfiPeiVariableStoreDiscoveredPpiGuid = { 0xa2fc038d, 0xfdf5, 0x4501, { 0xaf, 0x8e, 0x69, 0xb0, 0x20, 0xec, 0xe6, 0x63 } }
+
[Protocols]
## Load File protocol provides capability to load and unload EFI image into memory and execute it.
# Include/Protocol/LoadPe32Image.h
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 02/28] SecurityPkg: Add new GUIDs for
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
2022-04-29 18:04 ` [Patch v2 01/28] MdeModulePkg: Add new GUID for Variable Store Info Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-12 9:33 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 03/28] MdeModulePkg: Update AUTH_VARIABLE_INFO struct Judah Vang
` (27 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
The gEdkiiProtectedVariableGlobalGuid HOB contains the global
configuration data structure which is verified in PEI Phase.
The gEdkiiMetaDataHmacVariableGuid is used for saving the
meta data HMAC variable.
The gEdkiiProtectedVariableContextGuid contains the Protected
Variable context saved in PEI phase to be used later.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
SecurityPkg/SecurityPkg.dec | 43 +++++++++++++++++++-
1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec
index 9f7a032d60d5..ea88908ea7d2 100644
--- a/SecurityPkg/SecurityPkg.dec
+++ b/SecurityPkg/SecurityPkg.dec
@@ -5,7 +5,7 @@
# It also provides the definitions(including PPIs/PROTOCOLs/GUIDs and library classes)
# and libraries instances, which are used for those features.
#
-# Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2009 - 2022, Intel Corporation. All rights reserved.<BR>
# (C) Copyright 2015 Hewlett Packard Enterprise Development LP <BR>
# Copyright (c) Microsoft Corporation.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -217,6 +217,18 @@ [Guids]
## GUID used to specify section with default dbt content
gDefaultdbtFileGuid = { 0x36c513ee, 0xa338, 0x4976, { 0xa0, 0xfb, 0x6d, 0xdb, 0xa3, 0xda, 0xfe, 0x87 } }
+ ## Include/Guid/ProtectedVariable.h
+ # {8EBF379A-F18E-4728-A410-00CF9A65BE91}
+ gEdkiiProtectedVariableGlobalGuid = { 0x8ebf379a, 0xf18e, 0x4728, { 0xa4, 0x10, 0x0, 0xcf, 0x9a, 0x65, 0xbe, 0x91 } }
+
+ ## Include/Guid/ProtectedVariable.h
+ # {e3e890ad-5b67-466e-904f-94ca7e9376bb}
+ gEdkiiMetaDataHmacVariableGuid = {0xe3e890ad, 0x5b67, 0x466e, {0x90, 0x4f, 0x94, 0xca, 0x7e, 0x93, 0x76, 0xbb}}
+
+ ## Include/Guid/ProtectedVariable.h
+ # {a11a3652-875b-495a-b097-200917580b98}
+ gEdkiiProtectedVariableContextGuid = {0xa11a3652, 0x875b, 0x495a, {0xb0, 0x97, 0x20, 0x09, 0x17, 0x58, 0x0b, 0x98} }
+
[Ppis]
## The PPI GUID for that TPM physical presence should be locked.
# Include/Ppi/LockPhysicalPresence.h
@@ -242,6 +254,10 @@ [Ppis]
## Include/Ppi/Tcg.h
gEdkiiTcgPpiGuid = {0x57a13b87, 0x133d, 0x4bf3, { 0xbf, 0xf1, 0x1b, 0xca, 0xc7, 0x17, 0x6c, 0xf1 } }
+ ## Key Service Ppi
+ # Include/Ppi/KeyServicePpi.h
+ gKeyServicePpiGuid = {0x583592f6, 0xEC34, 0x4CED, {0x8E, 0x81, 0xC8, 0xD1, 0x36, 0x93, 0x04, 0x27}}
+
#
# [Error.gEfiSecurityPkgTokenSpaceGuid]
# 0x80000001 | Invalid value provided.
@@ -325,6 +341,31 @@ [PcdsFixedAtBuild, PcdsPatchableInModule]
gEfiSecurityPkgTokenSpaceGuid.PcdCpuRngSupportedAlgorithm|{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}|VOID*|0x00010032
+ ## Progress Code for variable integrity check result.<BR><BR>
+ # DEFAULT: (EFI_PERIPHERAL_FIXED_MEDIA | [EFI_STATUS&0xFF])
+ # @Prompt Status Code for variable integiry check result
+ gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeVariableIntegrity|0x01070000|UINT32|0x00010033
+
+ ## Null-terminated Unicode string of the Platform Variable Name
+ # @Prompt known unprotected variable name
+ gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName|L""|VOID*|0x00010034
+
+ ## Guid name to identify Platform Variable Guid
+ # @Prompt known unprotected variable guid
+ gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid|{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }|VOID*|0x00010035
+
+ ## Defines Protected Variable Integrity support.
+ # TRUE - Enable Protected Variable Integrity.<BR>
+ # FALSE - Disable Protected Variable Integrity.<BR>
+ # @Prompt Protected Variable Integrity support.
+ gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity|FALSE|BOOLEAN|0x00010036
+
+ ## Defines Protected Variable Confidentiality support.
+ # TRUE - Enable Protected Variable Confidentiality.<BR>
+ # FALSE - Disable Protected Variable Confidentiality.<BR>
+ # @Prompt Protected Variable Integrity support.
+ gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality|FALSE|BOOLEAN|0x00010037
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## Image verification policy for OptionRom. Only following values are valid:<BR><BR>
# NOTE: Do NOT use 0x5 and 0x2 since it violates the UEFI specification and has been removed.<BR>
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 03/28] MdeModulePkg: Update AUTH_VARIABLE_INFO struct
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
2022-04-29 18:04 ` [Patch v2 01/28] MdeModulePkg: Add new GUID for Variable Store Info Judah Vang
2022-04-29 18:04 ` [Patch v2 02/28] SecurityPkg: Add new GUIDs for Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-12 9:33 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 04/28] MdeModulePkg: Add reference to new Ppi Guid Judah Vang
` (26 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Added NameSize and State to AUTH_VARIABLE_INFO struct.
The size of the name and state is needed when creating
the variable digest.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
MdeModulePkg/Include/Library/AuthVariableLib.h | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/MdeModulePkg/Include/Library/AuthVariableLib.h b/MdeModulePkg/Include/Library/AuthVariableLib.h
index 37aceba699e6..32391bbf2b61 100644
--- a/MdeModulePkg/Include/Library/AuthVariableLib.h
+++ b/MdeModulePkg/Include/Library/AuthVariableLib.h
@@ -1,7 +1,7 @@
/** @file
Provides services to initialize and process authenticated variables.
-Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -25,9 +25,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
(OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)))
typedef struct {
+ UINTN NameSize;
CHAR16 *VariableName;
EFI_GUID *VendorGuid;
UINT32 Attributes;
+ UINT8 State;
UINTN DataSize;
VOID *Data;
UINT32 PubKeyIndex;
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 04/28] MdeModulePkg: Add reference to new Ppi Guid
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (2 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 03/28] MdeModulePkg: Update AUTH_VARIABLE_INFO struct Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-12 9:32 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 05/28] MdeModulePkg: Add new ProtectedVariable GUIDs Judah Vang
` (25 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add reference to gEfiPeiVariableStoreDiscoveredPpiGuid which
contains information whether variable store is available.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
MdePkg/Include/Ppi/ReadOnlyVariable2.h | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/MdePkg/Include/Ppi/ReadOnlyVariable2.h b/MdePkg/Include/Ppi/ReadOnlyVariable2.h
index 926c0bc82a43..c5a8470565bb 100644
--- a/MdePkg/Include/Ppi/ReadOnlyVariable2.h
+++ b/MdePkg/Include/Ppi/ReadOnlyVariable2.h
@@ -2,7 +2,7 @@
This file declares Read-only Variable Service2 PPI.
This ppi permits read-only access to the UEFI variable store during the PEI phase.
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Revision Reference:
@@ -106,4 +106,6 @@ struct _EFI_PEI_READ_ONLY_VARIABLE2_PPI {
extern EFI_GUID gEfiPeiReadOnlyVariable2PpiGuid;
+extern EFI_GUID gEfiPeiVariableStoreDiscoveredPpiGuid;
+
#endif
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 05/28] MdeModulePkg: Add new ProtectedVariable GUIDs
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (3 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 04/28] MdeModulePkg: Add reference to new Ppi Guid Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-12 9:32 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 06/28] MdeModulePkg: Add new include files Judah Vang
` (24 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
New ProtectVariable GUIDs for passing variable information
from PEI phase to SMM phase.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
MdeModulePkg/Include/Guid/ProtectedVariable.h | 22 ++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/MdeModulePkg/Include/Guid/ProtectedVariable.h b/MdeModulePkg/Include/Guid/ProtectedVariable.h
new file mode 100644
index 000000000000..0c6e19e0456b
--- /dev/null
+++ b/MdeModulePkg/Include/Guid/ProtectedVariable.h
@@ -0,0 +1,22 @@
+/** @file
+ The GUID definitions specific for protected variable services.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PROTECTED_VARIABLE_H_
+#define PROTECTED_VARIABLE_H_
+
+#define EDKII_PROTECTED_VARIABLE_GLOBAL_GUID \
+ { 0x8ebf379a, 0xf18e, 0x4728, { 0xa4, 0x10, 0x0, 0xcf, 0x9a, 0x65, 0xbe, 0x91 } }
+
+#define EDKII_METADATA_HMAC_VARIABLE_GUID \
+ { 0xb54cda50, 0xec54, 0x4b20, { 0x85, 0xb4, 0x57, 0xbf, 0x52, 0x98, 0x68, 0x3d } }
+
+extern EFI_GUID gEdkiiProtectedVariableGlobalGuid;
+extern EFI_GUID gEdkiiMetaDataHmacVariableGuid;
+extern EFI_GUID gEdkiiProtectedVariableContextGuid;
+
+#endif // __PROTECTED_VARIABLE_H__
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 06/28] MdeModulePkg: Add new include files
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (4 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 05/28] MdeModulePkg: Add new ProtectedVariable GUIDs Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-12 9:31 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 07/28] MdeModulePkg: Add Null ProtectedVariable Library Judah Vang
` (23 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add EncryptionVariableLib.h for providing encryption and
decryption services for protected variables.
Add ProtectedVariableLib.h for providing integrity or
variables.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
MdeModulePkg/Include/Library/EncryptionVariableLib.h | 165 +++++
MdeModulePkg/Include/Library/ProtectedVariableLib.h | 700 ++++++++++++++++++++
2 files changed, 865 insertions(+)
diff --git a/MdeModulePkg/Include/Library/EncryptionVariableLib.h b/MdeModulePkg/Include/Library/EncryptionVariableLib.h
new file mode 100644
index 000000000000..c7740e659dcf
--- /dev/null
+++ b/MdeModulePkg/Include/Library/EncryptionVariableLib.h
@@ -0,0 +1,165 @@
+/** @file
+ Provides services to encrypt/decrypt variables.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef ENCRYPTION_VARIABLE_LIB_H_
+#define ENCRYPTION_VARIABLE_LIB_H_
+
+#include <IndustryStandard/Tpm20.h>
+
+#include <Guid/VariableFormat.h>
+
+#include <Library/AuthVariableLib.h>
+
+#define ENC_TYPE_NULL 0
+#define ENC_TYPE_AES TPM_ALG_AES
+
+typedef struct _VARIABLE_ENCRYPTION_FLAGS {
+ BOOLEAN Auth; // Variable is authenticated or not
+ BOOLEAN DecryptInPlace; // Do decryption in place
+ BOOLEAN Protected; // Variable is protected or not
+} VARIABLE_ENCRYPTION_FLAGS;
+
+typedef struct _VARIABLE_ENCRYPTION_INFO {
+ AUTH_VARIABLE_INFO Header; // Authenticated varabile header
+ VARIABLE_HEADER *Buffer; // Pointer to variable buffer
+ UINT64 StoreIndex; // Variable store index
+ VOID *PlainData; // Pointer to plain data
+ UINT32 PlainDataSize; // Size of plain data
+ VOID *CipherData; // Pointer to cipher data
+ UINT32 CipherDataSize; // Size of cipher data
+ UINT32 CipherHeaderSize; // Size of cipher header
+ UINT32 CipherDataType; // Type of cipher data
+ VOID *Key; // Pointer to encrypt/decrypt key
+ UINT32 KeySize; // Size of key
+ VARIABLE_ENCRYPTION_FLAGS Flags; // Encryption flags
+} VARIABLE_ENCRYPTION_INFO;
+
+/**
+ Encrypt variable data.
+
+ @param[in, out] VarInfo Pointer to structure containing detailed information about a variable.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_INVALID_PARAMETER If ProtectedVarLibContextIn == NULL or ProtectedVarLibContextOut == NULL.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
+ @retval EFI_UNSUPPORTED Unsupported to process authenticated variable.
+
+**/
+EFI_STATUS
+EFIAPI
+EncryptVariable (
+ IN OUT VARIABLE_ENCRYPTION_INFO *VarInfo
+ );
+
+/**
+ Decrypt variable data.
+
+ If VarEncInfo->CipherData is not NULL, it must holds the cipher data to be
+ decrypted. Otherwise, assume the cipher data from variable data buffer, i.e.
+ VarEncInfo->Header.Data.
+
+ If VarEncInfo->Flags.DecryptInPlace is TRUE, the decrypted data will be put
+ back in the same buffer as cipher buffer got above, after encryption header,
+ which helps to identify later if the data in buffer is decrypted or not. This
+ can avoid repeat decryption when accessing the same variable more than once.
+
+ If VarEncInfo->Flags.DecryptInPlace is FALSE, VarEncInfo->PlainData must be
+ passed in with a valid buffer with VarEncInfo->PlainDataSize set correctly
+ with its size.
+
+ Note the VarEncInfo->PlainData is always pointing to the buffer address with
+ decrypted data without encryption header, and VarEncInfo->PlainDataSize is
+ always the size of original variable data, if this function returned
+ successfully.
+
+ @param[in, out] VarInfo Pointer to structure containing detailed
+ information about a variable.
+
+ @retval EFI_SUCCESS Variable was decrypted successfully.
+ @retval EFI_INVALID_PARAMETER Variable information in VarEncInfo is invalid.
+ @retval EFI_BUFFER_TOO_SMALL VarEncInfo->PlainData is not NULL but
+ VarEncInfo->PlainDataSize is too small.
+ @retval EFI_ABORTED Uknown error occurred during decrypting.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
+ @retval EFI_COMPROMISED_DATA The cipher header is not valid.
+ @retval EFI_UNSUPPORTED Unsupported to encrypt variable.
+
+**/
+EFI_STATUS
+EFIAPI
+DecryptVariable (
+ IN OUT VARIABLE_ENCRYPTION_INFO *VarInfo
+ );
+
+/**
+ Get cipher information about a variable, including plaindata size,
+ cipher algorithm type, etc.
+
+ For data passed in with VarEncInfo,
+
+ VarEncInfo->Header.Data
+ - The variable data in normal variable structure.
+ VarEncInfo->Header.DataSize
+ - The size of variable data.
+
+ For data passed out with VarEncInfo (valid only if EFI_SUCCESS is returned),
+
+ VarEncInfo->CipherDataType
+ - ENC_TYPE_NULL, if the variable is not encrypted or has been decrypted;
+ - ENC_TYPE_AES, if the variable is encrypted.
+ VarEncInfo->CipherHeaderSize
+ - Size of cipher header put before encrypted or decrypted data.
+ VarEncInfo->PlainData
+ - NULL, if the variable is encrypted; Or
+ - pointer to original variable data, if the variable has been decrypted.
+ VarEncInfo->PlainDataSize
+ - The size of original variable data
+ VarEncInfo->CipherData
+ - NULL, if the variable is decrypted; Or
+ - pointer to start of encrypted variable data, including encryption header;
+ VarEncInfo->CipherDataSize
+ - The size of encrypted variable data, including encryption header.
+
+ @param[in, out] VarInfo Pointer to structure containing detailed
+ information about a variable.
+
+ @retval EFI_SUCCESS The information was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER Variable information in VarEncInfo is invalid.
+ @retval EFI_NOT_FOUND No cipher information recognized.
+ @retval EFI_UNSUPPORTED Unsupported interface.
+
+**/
+EFI_STATUS
+EFIAPI
+GetCipherDataInfo (
+ IN OUT VARIABLE_ENCRYPTION_INFO *VarInfo
+ );
+
+/**
+ Force set cipher information for a variable, like plaindata size,
+ cipher algorithm type, cipher data etc.
+
+ The destination buffer must be passed via VarEncInfo->Header.Data.
+
+ This method is only used to update and/or change plain data information.
+
+ @param[in, out] VarInfo Pointer to structure containing detailed
+ information about a variable.
+
+ @retval EFI_SUCCESS The information was updated successfully.
+ @retval EFI_INVALID_PARAMETER Variable information in VarEncInfo is invalid.
+ @retval EFI_UNSUPPORTED If this method is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SetCipherDataInfo (
+ IN OUT VARIABLE_ENCRYPTION_INFO *VarInfo
+ );
+
+#endif //_ENCRYPTION_VARIABLE_LIB_H_
diff --git a/MdeModulePkg/Include/Library/ProtectedVariableLib.h b/MdeModulePkg/Include/Library/ProtectedVariableLib.h
new file mode 100644
index 000000000000..2f57b4ebbc70
--- /dev/null
+++ b/MdeModulePkg/Include/Library/ProtectedVariableLib.h
@@ -0,0 +1,700 @@
+/** @file
+ Defines interfaces of protected variable services for non-volatile variable
+ storage.
+
+Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PROTECTED_VARIABLE_LIB_H_
+#define PROTECTED_VARIABLE_LIB_H_
+
+#include <PiPei.h>
+#include <PiDxe.h>
+
+#include <Guid/VariableFormat.h>
+
+#include <Protocol/VarCheck.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include <Library/UefiLib.h>
+#include <Library/EncryptionVariableLib.h>
+
+#pragma pack(1)
+
+typedef struct _VARIABLE_DIGEST_FLAGS {
+ BOOLEAN Auth; // Authenticated variable format
+ BOOLEAN Valid; // Valid variable data in current variable
+ BOOLEAN Protected; // Protected variable (used in calculating HMAC)
+ BOOLEAN Encrypted; // Encrypted variable
+ BOOLEAN Freeable; // Memory reserved for current node can be freed
+ BOOLEAN CacheIndexAhead; // Indicates if CacheIndex is Ahead relative to Global structure
+ BOOLEAN Reserved[2]; // Reserved fields
+} VARIABLE_DIGEST_FLAGS;
+
+typedef struct _VARIABLE_DIGEST {
+ ///
+ /// Pointer to digest of next variable in a pre-defined rule of order for
+ /// integration verification. In other words, the final HMAC of all
+ /// protected variables is calculated by concatenating digest of each
+ /// variable in the order of this singly linked list.
+ ///
+ EFI_PHYSICAL_ADDRESS Prev;
+ EFI_PHYSICAL_ADDRESS Next;
+ ///
+ /// Index to variable in physical store, used to locate the variable directly
+ /// inside the store (Implementation dependent).
+ ///
+ EFI_PHYSICAL_ADDRESS StoreIndex;
+ ///
+ /// Index to variable in memory cache, used to locate the variable directly
+ /// inside the cache (Implementation dependent).
+ ///
+ EFI_PHYSICAL_ADDRESS CacheIndex;
+
+ ///
+ /// Pointer to Cache offset within Global Structure
+ ///
+ UINT32 CacheOffset;
+
+ ///
+ /// Frequently accessed information relating to the variable.
+ ///
+ UINT16 DigestSize; // Size of digest value
+ UINT16 NameSize; // Size of variable name
+ UINT32 DataSize; // Size of variable data
+ UINT32 PlainDataSize; // Size of plain data of current variable (if encrypted)
+ UINT32 State; // State of current variable
+ UINT32 Attributes; // Attributes of current variable
+
+ EFI_GUID VendorGuid; // GUID
+ VARIABLE_DIGEST_FLAGS Flags; // Variable digest flags
+ //
+ // Data with variable length are put at the end of this structure.
+ //
+ // CHAR16 VariableName[NameSize/2];
+ // UINT8 DigestValue[DigestSize];
+} VARIABLE_DIGEST;
+
+#pragma pack()
+
+#define VAR_DIG_NAMEOFF(VarDig) (sizeof (VARIABLE_DIGEST))
+#define VAR_DIG_DIGOFF(VarDig) (VAR_DIG_NAMEOFF (VarDig) + (VarDig)->NameSize)
+
+#define VAR_DIG_END(VarDig) (VAR_DIG_DIGOFF (VarDig) + (VarDig)->DigestSize)
+
+#define VAR_DIG_VALUE(VarDig) (VOID *)((UINTN)(VarDig) + VAR_DIG_DIGOFF (VarDig))
+#define VAR_DIG_NAME(VarDig) (CHAR16 *)((UINTN)(VarDig) + VAR_DIG_NAMEOFF (VarDig))
+#define VAR_DIG_GUID(VarDig) &(VAR_DIG_PTR (VarDig)->VendorGuid)
+
+#define VAR_DIG_PTR(Addr) ((VARIABLE_DIGEST *)(UINTN)(Addr))
+#define VAR_DIG_ADR(Ptr) ((EFI_PHYSICAL_ADDRESS)(UINTN)(Ptr))
+#define VAR_DIG_NEXT(VarDig) (VAR_DIG_PTR ((VarDig)->Next))
+#define VAR_DIG_PREV(VarDig) (VAR_DIG_PTR ((VarDig)->Prev))
+
+#define VAR_INDEX_INVALID ((UINT64)(-1))
+
+#define VAR_HDR_PTR(Addr) ((VARIABLE_HEADER *)(UINTN)(Addr))
+
+typedef VARIABLE_ENCRYPTION_INFO PROTECTED_VARIABLE_INFO;
+
+/**
+
+ This function writes data to the NV variable storage at given position.
+
+ Note: Per current variable service architecture, only SMM is allowed to
+ (directly) change NV variable storage.
+
+ @param VariableInfo Pointer to structure holding details of a variable.
+ @param Offset Offset to the given variable to write from.
+ @param Size Size of data to be written.
+ @param Buffer Pointer to the buffer from which data is written.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameters passed in.
+ @retval EFI_UNSUPPORTED Updating NV variable storage is not supported.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to complete the operation.
+ @retval EFI_SUCCESS Variable store successfully updated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PROTECTED_VAR_LIB_UPDATE_VARIABLE_STORE)(
+ IN PROTECTED_VARIABLE_INFO *VariableInfo,
+ IN UINTN Offset,
+ IN UINT32 Size,
+ IN UINT8 *Buffer
+ );
+
+/**
+ Update the variable region with Variable information.
+
+ @param[in] AuthVariableInfo Pointer AUTH_VARIABLE_INFO structure for
+ input of the variable.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PROTECTED_VAR_LIB_UPDATE_VARIABLE)(
+ IN AUTH_VARIABLE_INFO *AuthVariableInfo
+ );
+
+/**
+
+ Retrieve details about a variable and return them in VariableInfo->Header.
+
+ If VariableInfo->Address is given, this function will calculate its offset
+ relative to given variable storage via VariableStore; Otherwise, it will try
+ other internal variable storages or cached copies. It's assumed that, for all
+ copies of NV variable storage, all variables are stored in the same relative
+ position. If VariableInfo->Address is found in the range of any storage copies,
+ its offset relative to that storage should be the same in other copies.
+
+ If VariableInfo->Offset is given (non-zero) but not VariableInfo->Address,
+ this function will return the variable memory address inside VariableStore,
+ if given, via VariableInfo->Address; Otherwise, the address of other storage
+ copies will be returned, if any.
+
+ For a new variable whose offset has not been determined, a value of -1 as
+ VariableInfo->Offset should be passed to skip the offset calculation.
+
+ @param VariableInfo Pointer to variable information.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo->Address
+ and VariableInfo->Offset are NULL (0).
+ @retval EFI_NOT_FOUND If given Address or Offset is out of range of
+ any given or internal storage copies.
+ @retval EFI_SUCCESS Variable details are retrieved successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PROTECTED_VAR_LIB_GET_VAR_INFO)(
+ IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
+ );
+
+/**
+
+ Retrieve details of the variable next to given variable within VariableStore.
+
+ If VarInfo->Address is NULL, the first one in VariableStore is returned.
+
+ VariableStart and/or VariableEnd can be given optionally for the situation
+ in which the valid storage space is smaller than the VariableStore->Size.
+ This usually happens when PEI variable services make a compact variable
+ cache to save memory, which cannot make use VariableStore->Size to determine
+ the correct variable storage range.
+
+ @param VariableStore Pointer to a variable storage. It's optional.
+ @param VariableStart Start point of valid range in VariableStore.
+ @param VariableEnd End point of valid range in VariableStore.
+ @param VariableInfo Pointer to variable information.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL.
+ @retval EFI_NOT_FOUND If the end of VariableStore is reached.
+ @retval EFI_SUCCESS The next variable is retrieved successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PROTECTED_VAR_LIB_GET_NEXT_VAR_INFO)(
+ IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *DIGEST_METHOD_CALLBACK)(
+ IN VARIABLE_HEADER *Variable,
+ IN OUT VARIABLE_DIGEST *Digest
+ );
+
+/**
+
+ Initialize a memory copy of NV variable storage.
+
+ To save memory consumption (especially in PEI phase), it's allowed to cache
+ only valid variables. In such case, an index table recording offset of each
+ valid variables could be employed. The index table makes sure the cached copy
+ to be synchronized with the original copy in NV variable storage. To avoid
+ TOCTOU issue, once the variables are cached in memory and verified, NV
+ variable storage should not be used to read variable information. The cached
+ copy should be used instead.
+
+ If StoreCacheBase is not given, this function should return the required
+ cache size and valid variable number, if VariableNumber is not NULL. Then
+ the caller can prepare correct cache buffer and index table buffer before
+ next calling.
+
+ @param[in] CacheBase Base address of NV variable storage cache.
+ @param[in] CacheSize Size of CacheBuffer.
+ @param[out] CacheSize Size of required cache buffer.
+ @param[out] DigBuffer Base address of digest of each variable.
+ @param[in, out] DigBufferSize Digest size of one variable if DigestBuffer is NULL.
+ Size of DigestBuffer if DigestBuffer is NOT NULL.
+ @param[out] DigSize Required size of DigestBuffer if DigestBuffer is NULL.
+ @param[out] DigMethod Method used to generate digest for each variable.
+ @param[out] VarNumber Number of valid variables.
+ @param[out] AuthFlag Auth-variable indicator.
+
+ @retval EFI_INVALID_PARAMETER CacheSize is NULL; Or,
+ StoreCacheBase is 0 but *CacheSize it not.
+ @retval EFI_VOLUME_CORRUPTED If original NV variable storage is corrupted.
+ @retval EFI_BUFFER_TOO_SMALL If *CacheSize is smaller than required memory.
+ @retval EFI_SUCCESS The cached variable storage is initialized.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PROTECTED_VAR_LIB_INIT_VAR_STORE)(
+ OUT VOID *CacheBase OPTIONAL,
+ IN OUT UINT32 *CacheSize OPTIONAL,
+ OUT VOID *DigBuffer OPTIONAL,
+ IN OUT UINT32 *DigBufferSize OPTIONAL,
+ IN UINT32 DigSize OPTIONAL,
+ IN DIGEST_METHOD_CALLBACK DigMethod OPTIONAL,
+ OUT UINT32 *VarNumber OPTIONAL,
+ OUT BOOLEAN *AuthFlag OPTIONAL
+ );
+
+/**
+
+ Initiate a variable retrieval in SMM environment from non-SMM environment.
+
+ This is usually required in BS/RT environment when local cached copy is in
+ encrypted form. Variable decryption can only be done in SMM environment.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[out] Attributes Attribute value of the variable found.
+ @param[in, out] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[out] Data Data pointer.
+
+ @retval EFI_SUCCESS Found the specified variable.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PROTECTED_VAR_LIB_FIND_VAR_SMM)(
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ );
+
+/**
+ Check if a variable is user variable or not.
+
+ @param[in] Variable Pointer to variable header.
+
+ @retval TRUE User variable.
+ @retval FALSE System variable.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *PROTECTED_VAR_LIB_IS_USER_VAR)(
+ IN VARIABLE_HEADER *Variable
+ );
+
+/**
+ Check if a HOB variable store is available or not.
+
+ @retval EFI_NOT_READY HOB variable store info not available.
+ @retval EFI_NOT_FOUND HOB variable store is NOT available.
+ @retval EFI_SUCCESS HOB variable store is available.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PROTECTED_VAR_LIB_HOB_STORE_AVAILABLE)(
+ VOID
+ );
+
+typedef enum {
+ FromPeiModule,
+ FromBootServiceModule,
+ FromRuntimeModule,
+ FromSmmModule
+} VARIABLE_SERVICE_USER;
+
+#pragma pack(1)
+
+#define PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION 0x02
+
+typedef struct _PROTECTED_VARIABLE_CONTEXT_IN {
+ UINT32 StructVersion;
+ UINT32 StructSize;
+ UINT32 MaxVariableSize;
+
+ VARIABLE_SERVICE_USER VariableServiceUser;
+
+ PROTECTED_VAR_LIB_FIND_VAR_SMM FindVariableSmm;
+ PROTECTED_VAR_LIB_GET_VAR_INFO GetVariableInfo;
+ PROTECTED_VAR_LIB_GET_NEXT_VAR_INFO GetNextVariableInfo;
+ PROTECTED_VAR_LIB_UPDATE_VARIABLE_STORE UpdateVariableStore;
+ PROTECTED_VAR_LIB_UPDATE_VARIABLE UpdateVariable;
+ PROTECTED_VAR_LIB_HOB_STORE_AVAILABLE IsHobVariableStoreAvailable;
+} PROTECTED_VARIABLE_CONTEXT_IN;
+
+#pragma pack()
+
+/**
+
+ Initialization for protected variable services.
+
+ If this initialization failed upon any error, the whole variable services
+ should not be used. A system reset might be needed to re-construct NV
+ variable storage to be the default state.
+
+ @param[in] ContextIn Pointer to variable service context needed by
+ protected variable.
+
+ @retval EFI_SUCCESS Protected variable services are ready.
+ @retval EFI_INVALID_PARAMETER If ContextIn == NULL or something missing or
+ mismatching in the content in ContextIn.
+ @retval EFI_COMPROMISED_DATA If failed to check integrity of protected variables.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibInitialize (
+ IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn
+ );
+
+/**
+
+ An alternative version of ProtectedVariableLibGetData to get plain data, if
+ encrypted, from given variable, for different use cases.
+
+ @param[in,out] VarInfo Pointer to structure containing variable information.
+
+ @retval EFI_SUCCESS Found the specified variable.
+ @retval EFI_INVALID_PARAMETER VarInfo is NULL or both VarInfo->Address and
+ VarInfo->Offset are invalid.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ );
+
+/**
+ This service retrieves a variable's value using its name and GUID.
+
+ Read the specified variable from the UEFI variable store. If the Data
+ buffer is too small to hold the contents of the variable, the error
+ EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+ size to obtain the data.
+
+ @param VariableName A pointer to a null-terminated string that is the variable's name.
+ @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+ @param Attributes If non-NULL, on return, points to the variable's attributes.
+ @param DataSize On entry, points to the size in bytes of the Data buffer.
+ On return, points to the size of the data returned in Data.
+ @param Data Points to the buffer which will hold the returned variable value.
+ May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable was be found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
+ DataSize is updated with the size required for
+ the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByName (
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ );
+
+/**
+
+ Retrieve plain data, if encrypted, of given variable.
+
+ If variable encryption is employed, this function will initiate a SMM request
+ to get the plain data. Due to security consideration, the decryption can only
+ be done in SMM environment.
+
+ @param[in] Variable Pointer to header of a Variable.
+ @param[out] Data Pointer to plain data of the given variable.
+ @param[in, out] DataSize Size of data returned or data buffer needed.
+ @param[in] AuthFlag Auth-variable indicator.
+
+ @retval EFI_SUCCESS Found the specified variable.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL If *DataSize is smaller than needed.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByBuffer (
+ IN VARIABLE_HEADER *Variable,
+ IN OUT VOID *Data,
+ IN OUT UINT32 *DataSize,
+ IN BOOLEAN AuthFlag
+ );
+
+/**
+
+ Prepare for variable update.
+
+ This is needed only once during current boot to mitigate replay attack. Its
+ major job is to advance RPMC (Replay Protected Monotonic Counter).
+
+ @retval EFI_SUCCESS Variable is ready to update hereafter.
+ @retval EFI_UNSUPPORTED Updating variable is not supported.
+ @retval EFI_DEVICE_ERROR Error in advancing RPMC.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteInit (
+ VOID
+ );
+
+/**
+
+ Update a variable with protection provided by this library.
+
+ If variable encryption is employed, the new variable data will be encrypted
+ before being written to NV variable storage.
+
+ A special variable, called "MetaDataHmacVar", will always be updated along
+ with variable being updated to reflect the changes (HMAC value) of all
+ protected valid variables. The only exceptions, currently, are variable
+ "MetaDataHmacVar" itself and variable "VarErrorLog".
+
+ The buffer passed by NewVariable must be double of maximum variable size,
+ which allows to pass the "MetaDataHmacVar" back to caller along with encrypted
+ new variable data, if any. This can make sure the new variable data and
+ "MetaDataHmacVar" can be written at almost the same time to reduce the chance
+ of compromising the integrity.
+
+ If *NewVariableSize is zero, it means to delete variable passed by CurrVariable
+ and/or CurrVariableInDel. "MetaDataHmacVar" will be updated as well in such
+ case because of less variables in storage. NewVariable should be always passed
+ in to convey new "MetaDataHmacVar" back.
+
+ @param[in,out] CurrVariable Variable to be updated. It's NULL if
+ adding a new variable.
+ @param[in,out] CurrVariableInDel In-delete-transition copy of updating variable.
+ @param[in] NewVariable Buffer of new variable data.
+ @param[out] NewVariable Buffer of "MetaDataHmacVar" and new
+ variable (encrypted).
+ @param[in] NewVariableSize Size of NewVariable.
+ @param[out] NewVariableSize Size of (encrypted) NewVariable and
+ "MetaDataHmacVar".
+
+ @retval EFI_SUCCESS The variable is updated with protection successfully.
+ @retval EFI_INVALID_PARAMETER NewVariable is NULL.
+ @retval EFI_NOT_FOUND Information missing to finish the operation.
+ @retval EFI_ABORTED Failed to encrypt variable or calculate HMAC.
+ @retval EFI_NOT_READY The RPMC device is not yet initialized.
+ @retval EFI_DEVICE_ERROR The RPMC device has error in updating.
+ @retval EFI_ACCESS_DENIED The given variable is not allowed to update.
+ Currently this only happens on updating
+ "MetaDataHmacVar" from code outside of this
+ library.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibUpdate (
+ IN OUT VARIABLE_HEADER *CurrVariable OPTIONAL,
+ IN OUT VARIABLE_HEADER *CurrVariableInDel OPTIONAL,
+ IN OUT VARIABLE_HEADER *NewVariable,
+ IN OUT UINTN *NewVariableSize
+ );
+
+/**
+
+ Finalize a variable updating after it's written to NV variable storage
+ successfully.
+
+ This usually includes works like increasing RPMC, synchronizing local cache,
+ updating new position of "MetaDataHmacVar", deleting old copy of "MetaDataHmacVar"
+ completely, etc.
+
+ @param[in] NewVariable Buffer of new variables and MetaDataHmacVar.
+ @param[in] VariableSize Size of buffer pointed by NewVariable.
+ @param[in] Offset Offset to NV variable storage from where the new
+ variable and MetaDataHmacVar have been written.
+
+ @retval EFI_SUCCESS No problem in winding up the variable write operation.
+ @retval Others Failed to updating state of old copy of updated
+ variable, or failed to increase RPMC, etc.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteFinal (
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN VariableSize,
+ IN UINT64 StoreIndex
+ );
+
+/**
+ Return the request variable name and GUID as per StoreIndex.
+
+ This function is called multiple times to retrieve the VariableName
+ and VariableGuid of all variables currently available in the system.
+ On each call, the previous results are passed into the interface,
+ and, on return, the interface returns the data for the next
+ interface. When the entire variable list has been returned,
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+ @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ On return, the size of the variable name buffer.
+ @param VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+ @param VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFind (
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ );
+
+/**
+ Return the next variable name and GUID.
+
+ This function is called multiple times to retrieve the VariableName
+ and VariableGuid of all variables currently available in the system.
+ On each call, the previous results are passed into the interface,
+ and, on return, the interface returns the data for the next
+ interface. When the entire variable list has been returned,
+ EFI_NOT_FOUND is returned.
+
+ @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ On return, the size of the variable name buffer.
+ @param VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+ @param VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFindNext (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ );
+
+/**
+ Find variable via information in data structure PROTECTED_VARIABLE_INFO.
+
+ If VarInfo->StoreIndex is given and valid, always used it to search variable
+ in store. Otherwise, search the variable via variable name and guid pointed
+ by VarInfo->Header.VariableName and VarInfo->Header.VendorGuid.
+
+ @param VarInfo Pointer to data containing variable information.
+
+ @return EFI_SUCCESS Found the variable.
+ @return EFI_INVALID_PARAMETER No valid variable information is given.
+ @return EFI_NOT_FOUND The given variable was not found or no more
+ variables available.
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFindNextEx (
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ );
+
+/**
+ Refresh variable information changed by variable service.
+
+ @param Variable Pointer to buffer of the updated variable.
+ @param VariableSize Size of variable pointed by Variable.
+ @param StoreIndex New index of the variable in store.
+ @param RefreshData Flag to indicate if the variable has been updated.
+
+ @return EFI_SUCCESS No error occurred in updating.
+ @return EFI_NOT_FOUND The given variable was not found in
+ ProtectedVariableLib.
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibRefresh (
+ IN VARIABLE_HEADER *Variable,
+ IN UINTN VariableSize,
+ IN UINT64 StoreIndex,
+ IN BOOLEAN RefreshData
+ );
+
+/**
+ Refresh variable information changed by variable service.
+
+ @param Buffer Pointer to a pointer of buffer.
+ @param NumElements Pointer to number of elements in list.
+
+
+ @return EFI_SUCCESS Successfully retrieved sorted list.
+ @return others Unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetSortedList (
+ IN OUT EFI_PHYSICAL_ADDRESS **Buffer,
+ IN OUT UINTN *NumElements
+ );
+
+/**
+
+ Determine if the variable is the HMAC variable
+
+ @param VariableName Pointer to variable name.
+
+ @return TRUE Variable is HMAC variable
+ @return FALSE Variable is not HMAC variable
+
+**/
+BOOLEAN
+ProtectedVariableLibIsHmac (
+ IN CHAR16 *VariableName
+ );
+
+#endif
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 07/28] MdeModulePkg: Add Null ProtectedVariable Library
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (5 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 06/28] MdeModulePkg: Add new include files Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-22 8:38 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 08/28] MdeModulePkg: Add new Variable functionality Judah Vang
` (22 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add Null versions of the ProtectedVariable Library.
This will be the default libraries for platforms that
do not support ProtectedVariable.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf | 34 ++
MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c | 449 ++++++++++++++++++++
2 files changed, 483 insertions(+)
diff --git a/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
new file mode 100644
index 000000000000..6a17191c4e1e
--- /dev/null
+++ b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
@@ -0,0 +1,34 @@
+## @file
+# Provides null version of protected variable services.
+#
+# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010029
+ BASE_NAME = ProtectedVariableLibNull
+ FILE_GUID = 352C6A1B-403A-4E37-8517-FAA50BC45251
+ MODULE_TYPE = BASE
+ VERSION_STRING = 0.1
+ LIBRARY_CLASS = ProtectedVariableLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ ProtectedVariable.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+
diff --git a/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
new file mode 100644
index 000000000000..cc1e16c1a671
--- /dev/null
+++ b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
@@ -0,0 +1,449 @@
+/** @file
+ NULL version of ProtectedVariableLib used to disable protected variable services.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Uefi.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ProtectedVariableLib.h>
+
+/**
+
+ Initialization for protected varibale services.
+
+ @param[in] ContextIn Pointer to variable service context needed by
+ protected variable.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibInitialize (
+ IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Get a verified copy of NV variable storage.
+
+ @param[out] VariableFvHeader Pointer to the header of whole NV firmware volume.
+ @param[out] VariableStoreHeader Pointer to the header of variable storage.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetStore (
+ OUT EFI_FIRMWARE_VOLUME_HEADER **VariableFvHeader,
+ OUT VARIABLE_STORE_HEADER **VariableStoreHeader
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Prepare for variable update.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteInit (
+ VOID
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Update a variable with protection provided by this library.
+
+ @param[in,out] CurrVariable Variable to be updated. It's NULL if
+ adding a new variable.
+ @param[in] CurrVariableInDel In-delete-transiion copy of updating variable.
+ @param[in,out] NewVariable Buffer of new variable data.
+ Buffer of "MetaDataHmacVar" and new
+ variable (encrypted).
+ @param[in,out] NewVariableSize Size of NewVariable.
+ Size of (encrypted) NewVariable and
+ "MetaDataHmacVar".
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibUpdate (
+ IN OUT VARIABLE_HEADER *CurrVariable,
+ IN VARIABLE_HEADER *CurrVariableInDel,
+ IN OUT VARIABLE_HEADER *NewVariable,
+ IN OUT UINTN *NewVariableSize
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Finalize a variable updating after it's written to NV variable storage
+ successfully.
+
+ @param[in] NewVariable Buffer of new variables and MetaDataHmacVar.
+ @param[in] VariableSize Size of buffer pointed by NewVariable.
+ @param[in] StoreIndex New index of the variable in store.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteFinal (
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN VariableSize,
+ IN UINT64 StoreIndex
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Perform garbage collection against the cached copy of NV variable storage.
+
+ @param[in] VariableStoreBuffer Buffer used to do the reclaim.
+ @param[out] LastVariableOffset New free space start point.
+ @param[in] CurrVariableOffset Offset of existing variable.
+ @param[in] CurrVariableInDelOffset Offset of old copy of existing variable.
+ @param[in,out] NewVariable Buffer of new variable data.
+ @param[in] NewVariableSize Size of new variable data.
+ @param[in,out] HwErrVariableTotalSize Total size of variables with HR attribute.
+ @param[in,out] CommonVariableTotalSize Total size of common variables.
+ @param[in,out] CommonUserVariableTotalSize Total size of user variables.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibReclaim (
+ IN VARIABLE_STORE_HEADER *VariableStoreBuffer,
+ OUT UINTN *LastVariableOffset,
+ IN UINTN CurrVariableOffset,
+ IN UINTN CurrVariableInDelOffset,
+ IN OUT VARIABLE_HEADER **NewVariable,
+ IN UINTN NewVariableSize,
+ IN OUT UINTN *HwErrVariableTotalSize,
+ IN OUT UINTN *CommonVariableTotalSize,
+ IN OUT UINTN *CommonUserVariableTotalSize
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ An alternative version of ProtectedVariableLibGetData to get plain data, if
+ encrypted, from given variable, for different use cases.
+
+ @param[in,out] VarInfo Pointer to structure containing variable information.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetDataInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Retrieve plain data, if encrypted, of given variable.
+
+ @param[in] Variable Pointer to header of a Variable.
+ @param[in,out] Data Pointer to plain data of the given variable.
+ @param[in,out] DataSize Size of data returned or data buffer needed.
+ @param[in] AuthFlag Auth-variable indicator.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetData (
+ IN VARIABLE_HEADER *Variable,
+ IN OUT VOID *Data,
+ IN OUT UINT32 *DataSize,
+ IN BOOLEAN AuthFlag
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Retrieve next protected variable stub.
+
+ @param[in,out] VarInfo Pointer to structure containing variable information.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetNextEx (
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Retrieve next protected variable.
+
+ @param[in,out] VariableNameSize Pointer to size of variable name.
+ @param[in,out] VariableName Pointer to variable name.
+ @param[in,out] VariableGuid Pointer to vairable GUID.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetNext (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Get the specified protected variable.
+
+ @param[in] VariableName Pointer to variable name.
+ @param[in] VariableGuid Pointer to vairable GUID.
+ @param[out] Attributes Pointer to attributes.
+ @param[in,out] DataSize Pointer to data size.
+ @param[out] Data Pointer to data.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGet (
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Find the protected variable.
+
+ @param[in,out] VarInfo Pointer to structure containing variable information.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFind (
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Find next protected variable.
+
+ @param[in,out] VariableNameSize Pointer to size of variable name.
+ @param[in,out] VariableName Pointer to variable name.
+ @param[in,out] VariableGuid Pointer to vairable GUID.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFindNext (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Find next protected variable stub.
+
+ @param[in,out] VarInfo Pointer to structure containing variable information.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFindNextEx (
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Get protected variable by information.
+
+ @param[in,out] VarInfo Pointer to structure containing variable information.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Get protected variable by name.
+
+ @param[in] VariableName Pointer to variable name.
+ @param[in] VariableGuid Pointer to vairable GUID.
+ @param[out] Attributes Pointer to attributes.
+ @param[in,out] DataSize Pointer to data size.
+ @param[out] Data Pointer to data.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByName (
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Get protected variable by name.
+
+ @param[in] Variable Pointer to variable name.
+ @param[in,out] Data Pointer to variable data.
+ @param[in,out] DataSize Pointer to data size.
+ @param[in] AuthFlag Authenticate flag.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByBuffer (
+ IN VARIABLE_HEADER *Variable,
+ IN OUT VOID *Data,
+ IN OUT UINT32 *DataSize,
+ IN BOOLEAN AuthFlag
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Refresh variable information changed by variable service.
+
+ @param[in] Variable Pointer to buffer of the updated variable.
+ @param[in] VariableSize Size of variable pointed by Variable.
+ @param[in] StoreIndex New index of the variable in store.
+ @param[in] RefreshData Flag to indicate if the variable has been updated.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibRefresh (
+ IN VARIABLE_HEADER *Variable,
+ IN UINTN VariableSize,
+ IN UINT64 StoreIndex,
+ IN BOOLEAN RefreshData
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Get sorted protected variable list.
+
+ @param[in,out] Buffer Pointer to buffer.
+ @param[in,out] NumElements Pointer to number of elements.
+
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetSortedList (
+ IN OUT EFI_PHYSICAL_ADDRESS **Buffer,
+ IN OUT UINTN *NumElements
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Determine if the variable is the HMAC variable.
+
+ @param[in] VariableName Pointer to variable name.
+
+ @return FALSE Variable is not HMAC variable
+
+**/
+BOOLEAN
+ProtectedVariableLibIsHmac (
+ IN CHAR16 *VariableName
+ )
+{
+ return FALSE;
+}
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 08/28] MdeModulePkg: Add new Variable functionality
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (6 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 07/28] MdeModulePkg: Add Null ProtectedVariable Library Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-22 10:24 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 09/28] MdeModulePkg: Add support for Protected Variables Judah Vang
` (21 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Provide new APIs for retrieving variable information.
Add new function stubs for retrieving Protected
variable information.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
MdeModulePkg/Universal/Variable/Pei/VariablePei.inf | 10 +-
MdeModulePkg/Universal/Variable/Pei/Variable.h | 80 +-
MdeModulePkg/Universal/Variable/Pei/VariableParsing.h | 309 +++++++
MdeModulePkg/Universal/Variable/Pei/VariableStore.h | 116 +++
MdeModulePkg/Universal/Variable/Pei/Variable.c | 886 +++---------------
MdeModulePkg/Universal/Variable/Pei/VariableParsing.c | 941 ++++++++++++++++++++
MdeModulePkg/Universal/Variable/Pei/VariableStore.c | 305 +++++++
7 files changed, 1891 insertions(+), 756 deletions(-)
diff --git a/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf b/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
index 7cbdd2385e8f..af172126a011 100644
--- a/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
+++ b/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
@@ -3,7 +3,7 @@
#
# This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
#
-# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
@@ -26,6 +26,10 @@ [Defines]
[Sources]
Variable.c
Variable.h
+ VariableStore.c
+ VariableStore.h
+ VariableParsing.c
+ VariableParsing.h
[Packages]
MdePkg/MdePkg.dec
@@ -39,6 +43,7 @@ [LibraryClasses]
DebugLib
PeiServicesTablePointerLib
PeiServicesLib
+ ProtectedVariableLib
[Guids]
## CONSUMES ## GUID # Variable store header
@@ -56,7 +61,8 @@ [Guids]
gEdkiiFaultTolerantWriteGuid
[Ppis]
- gEfiPeiReadOnlyVariable2PpiGuid ## PRODUCES
+ gEfiPeiReadOnlyVariable2PpiGuid ## PRODUCES
+ gEfiPeiVariableStoreDiscoveredPpiGuid ## CONSUMES
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## SOMETIMES_CONSUMES
diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.h b/MdeModulePkg/Universal/Variable/Pei/Variable.h
index 7f9ad5bfc357..115426edd626 100644
--- a/MdeModulePkg/Universal/Variable/Pei/Variable.h
+++ b/MdeModulePkg/Universal/Variable/Pei/Variable.h
@@ -2,7 +2,7 @@
The internal header file includes the common header files, defines
internal structure and functions used by PeiVariable module.
-Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -20,11 +20,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Library/BaseMemoryLib.h>
#include <Library/PeiServicesTablePointerLib.h>
#include <Library/PeiServicesLib.h>
+#include <Library/ProtectedVariableLib.h>
#include <Guid/VariableFormat.h>
#include <Guid/VariableIndexTable.h>
#include <Guid/SystemNvDataGuid.h>
#include <Guid/FaultTolerantWrite.h>
+#include <Guid/ProtectedVariable.h>
typedef enum {
VariableStoreTypeHob,
@@ -142,4 +144,80 @@ PeiGetNextVariableName (
IN OUT EFI_GUID *VariableGuid
);
+/**
+ This service retrieves a variable's value using its name and GUID.
+
+ Read the specified variable from the UEFI variable store. If the Data
+ buffer is too small to hold the contents of the variable, the error
+ EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+ size to obtain the data.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+ @param VariableName A pointer to a null-terminated string that is the variable's name.
+ @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+ @param Attributes If non-NULL, on return, points to the variable's attributes.
+ @param DataSize On entry, points to the size in bytes of the Data buffer.
+ On return, points to the size of the data returned in Data.
+ @param Data Points to the buffer which will hold the returned variable value.
+ May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
+ DataSize is updated with the size required for
+ the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariableEx (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ );
+
+/**
+ Return the next variable name and GUID.
+
+ This function is called multiple times to retrieve the VariableName
+ and VariableGuid of all variables currently available in the system.
+ On each call, the previous results are passed into the interface,
+ and, on return, the interface returns the data for the next
+ interface. When the entire variable list has been returned,
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+ @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ @param VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+
+ @param VariableGuid On entry, a pointer to an UEFI _GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableNameEx (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ );
+
#endif
diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableParsing.h b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.h
new file mode 100644
index 000000000000..d7af6cb6e8be
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.h
@@ -0,0 +1,309 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by PeiVariable module.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PEI_VARIABLE_PARSING_H_
+#define PEI_VARIABLE_PARSING_H_
+
+#include "Variable.h"
+
+/**
+
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header.
+
+**/
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ );
+
+/**
+
+ Gets the pointer to the end of the variable storage area.
+
+ This function gets pointer to the end of the variable storage
+ area, according to the input variable store header.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the end of the variable storage area.
+
+**/
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ );
+
+/**
+ This code checks if variable header is valid or not.
+
+ @param[in] Variable Pointer to the Variable Header.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable
+ );
+
+/**
+ This code gets the pointer to the next variable header.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] VariableHeader Pointer to the Variable Header that has consecutive content.
+
+ @return A VARIABLE_HEADER* pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader
+ );
+
+/**
+ This code gets the pointer to the variable guid.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ );
+
+/**
+ This code gets the pointer to the variable name.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return A CHAR16* pointer to Variable Name.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ );
+
+/**
+ This code gets the size of name of variable.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ );
+
+/**
+ This code gets the size of data of variable.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ );
+
+/**
+ This code gets the pointer to the variable data.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] VariableHeader Pointer to the Variable Header that has consecutive content.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return A UINT8* pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader,
+ IN BOOLEAN AuthFlag
+ );
+
+/**
+ Get variable header that has consecutive content.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Variable Pointer to the Variable Header.
+ @param[out] VariableHeader Pointer to Pointer to the Variable Header that has consecutive content.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+GetVariableHeader (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ OUT VARIABLE_HEADER **VariableHeader
+ );
+
+/**
+ This code gets the size of variable header.
+
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+ IN BOOLEAN AuthFlag
+ );
+
+/**
+ Get variable name or data to output buffer.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] NameOrData Pointer to the variable name/data that may be inconsecutive.
+ @param[in] Size Variable name/data size.
+ @param[out] Buffer Pointer to output buffer to hold the variable name/data.
+
+**/
+VOID
+GetVariableNameOrData (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN UINT8 *NameOrData,
+ IN UINTN Size,
+ OUT UINT8 *Buffer
+ );
+
+/**
+ This function compares a variable with variable entries in database.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Variable Pointer to the variable in our database
+ @param[in] VariableHeader Pointer to the Variable Header that has consecutive content.
+ @param[in] VariableName Name of the variable to compare to 'Variable'
+ @param[in] VendorGuid GUID of the variable to compare to 'Variable'
+ @param[out] PtrTrack Variable Track Pointer structure that contains Variable Information.
+
+ @retval EFI_SUCCESS Found match variable
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+CompareWithValidVariable (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack
+ );
+
+/**
+
+ Retrieve details of the variable next to given variable within VariableStore.
+
+ If VarInfo->Address is NULL, the first one in VariableStore is returned.
+
+ VariableStart and/or VariableEnd can be given optionally for the situation
+ in which the valid storage space is smaller than the VariableStore->Size.
+ This usually happens when PEI variable services make a compact variable
+ cache to save memory, which cannot make use VariableStore->Size to determine
+ the correct variable storage range.
+
+ @param[in,out] VariableInfo Pointer to variable information.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL.
+ @retval EFI_NOT_FOUND If the end of VariableStore is reached.
+ @retval EFI_SUCCESS The next variable is retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextVariableInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
+ );
+
+/**
+
+ Retrieve details about a variable and return them in VariableInfo->Header.
+
+ If VariableInfo->Address is given, this function will calculate its offset
+ relative to given variable storage via VariableStore; Otherwise, it will try
+ other internal variable storages or cached copies. It's assumed that, for all
+ copies of NV variable storage, all variables are stored in the same relative
+ position. If VariableInfo->Address is found in the range of any storage copies,
+ its offset relative to that storage should be the same in other copies.
+
+ If VariableInfo->Offset is given (non-zero) but not VariableInfo->Address,
+ this function will return the variable memory address inside VariableStore,
+ if given, via VariableInfo->Address; Otherwise, the address of other storage
+ copies will be returned, if any.
+
+ For a new variable whose offset has not been determined, a value of -1 as
+ VariableInfo->Offset should be passed to skip the offset calculation.
+
+ @param[in,out] VariableInfo Pointer to variable information.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo->Address
+ and VariableInfo->Offset are NULL (0).
+ @retval EFI_NOT_FOUND If given Address or Offset is out of range of
+ any given or internal storage copies.
+ @retval EFI_SUCCESS Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
+ );
+
+/**
+
+ Find variable specified with input parameters.
+
+ @param[in] StoreInfo Pointer to variable information.
+ @param[in] VariableName Pointer to variable name.
+ @param[in] VendorGuid Pointer to variable GUID.
+ @param[in] PtrTrack Pointer to variable track.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo->Address
+ and VariableInfo->Offset are NULL (0).
+ @retval EFI_NOT_FOUND If given Address or Offset is out of range of
+ any given or internal storage copies.
+ @retval EFI_SUCCESS Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+FindVariableEx (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack
+ );
+
+#endif
diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableStore.h b/MdeModulePkg/Universal/Variable/Pei/VariableStore.h
new file mode 100644
index 000000000000..6e2f6f939bab
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Pei/VariableStore.h
@@ -0,0 +1,116 @@
+/** @file
+ Implement ReadOnly Variable Services required by PEIM and install
+ PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PEI_VARIABLE_STORE_H_
+#define PEI_VARIABLE_STORE_H_
+
+/**
+ Get variable store status.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @retval EfiRaw Variable store is raw
+ @retval EfiValid Variable store is valid
+ @retval EfiInvalid Variable store is invalid
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ );
+
+/**
+ Reports HOB variable store is available or not.
+
+ @retval EFI_NOT_READY HOB variable store info not available.
+ @retval EFI_NOT_FOUND HOB variable store is NOT available.
+ @retval EFI_SUCCESS HOB variable store is available.
+**/
+EFI_STATUS
+EFIAPI
+IsHobVariableStoreAvailable (
+ VOID
+ );
+
+/**
+ Get HOB variable store.
+
+ @param[out] StoreInfo Return the store info.
+
+**/
+VOID
+GetHobVariableStore (
+ OUT VARIABLE_STORE_INFO *StoreInfo
+ );
+
+/**
+ Get NV variable store.
+
+ @param[out] StoreInfo Return the store info.
+ @param[out] VariableStoreHeader Return header of FV containing the store.
+
+**/
+VOID
+GetNvVariableStore (
+ OUT VARIABLE_STORE_INFO *StoreInfo,
+ OUT EFI_FIRMWARE_VOLUME_HEADER **VariableFvHeader
+ );
+
+/**
+ Return the variable store header and the store info based on the Index.
+
+ @param[in] Type The type of the variable store.
+ @param[out] StoreInfo Return the store info.
+
+ @return Pointer to the variable store header.
+**/
+VARIABLE_STORE_HEADER *
+GetVariableStore (
+ IN VARIABLE_STORE_TYPE Type,
+ OUT VARIABLE_STORE_INFO *StoreInfo
+ );
+
+/**
+ Make a cached copy of NV variable storage.
+
+ To save memory in PEI phase, only valid variables are copied into cache.
+ An IndexTable could be used to store the offset (relative to NV storage
+ base) of each copied variable, in case we need to restore the storage
+ as the same (valid) variables layout as in original one.
+
+ Variables with valid format and following state can be taken as valid:
+ - with state VAR_ADDED;
+ - with state VAR_IN_DELETED_TRANSITION but without the same variable
+ with state VAR_ADDED;
+ - with state VAR_ADDED and/or VAR_IN_DELETED_TRANSITION for variable
+ MetaDataHmacVar.
+
+ @param[out] StoreCacheBase Base address of variable storage cache.
+ @param[in,out] StoreCacheSize Size of space in StoreCacheBase.
+ @param[out] IndexTable Buffer of index (offset) table with entries of
+ VariableNumber.
+ @param[out] VariableNumber Number of valid variables.
+ @param[out] AuthFlag Aut-variable indicator.
+
+ @return EFI_INVALID_PARAMETER Invalid StoreCacheSize and/or StoreCacheBase.
+ @return EFI_VOLUME_CORRUPTED Invalid or no NV variable storage found.
+ @return EFI_BUFFER_TOO_SMALL StoreCacheSize is smaller than needed.
+ @return EFI_SUCCESS NV variable storage is cached successfully.
+**/
+EFI_STATUS
+EFIAPI
+InitNvVariableStore (
+ OUT EFI_PHYSICAL_ADDRESS StoreCacheBase OPTIONAL,
+ IN OUT UINT32 *StoreCacheSize,
+ OUT UINT32 *IndexTable OPTIONAL,
+ OUT UINT32 *VariableNumber OPTIONAL,
+ OUT BOOLEAN *AuthFlag OPTIONAL
+ );
+
+#endif
diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.c b/MdeModulePkg/Universal/Variable/Pei/Variable.c
index b36dd0de67b2..ce790946626e 100644
--- a/MdeModulePkg/Universal/Variable/Pei/Variable.c
+++ b/MdeModulePkg/Universal/Variable/Pei/Variable.c
@@ -2,20 +2,22 @@
Implement ReadOnly Variable Services required by PEIM and install
PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
Copyright (c) Microsoft Corporation.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Variable.h"
+#include "VariableParsing.h"
+#include "VariableStore.h"
//
// Module globals
//
EFI_PEI_READ_ONLY_VARIABLE2_PPI mVariablePpi = {
- PeiGetVariable,
- PeiGetNextVariableName
+ PeiGetVariableEx,
+ PeiGetNextVariableNameEx
};
EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = {
@@ -41,759 +43,33 @@ PeimInitializeVariableServices (
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_CONTEXT_IN ContextIn;
+
+ //
+ // If protected variable services are not supported, EFI_UNSUPPORTED should
+ // be always returned. Check it here.
+ //
+ ContextIn.StructVersion = PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
+ ContextIn.StructSize = sizeof (ContextIn);
+
+ ContextIn.MaxVariableSize = 0;
+ ContextIn.VariableServiceUser = FromPeiModule;
+ ContextIn.GetVariableInfo = GetVariableInfo;
+ ContextIn.GetNextVariableInfo = GetNextVariableInfo;
+ ContextIn.FindVariableSmm = NULL;
+ ContextIn.UpdateVariableStore = NULL;
+ ContextIn.UpdateVariable = NULL;
+ ContextIn.IsHobVariableStoreAvailable = IsHobVariableStoreAvailable;
+
+ Status = ProtectedVariableLibInitialize (&ContextIn);
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ return Status;
+ }
+
return PeiServicesInstallPpi (&mPpiListVariable);
}
-/**
-
- Gets the pointer to the first variable header in given variable store area.
-
- @param VarStoreHeader Pointer to the Variable Store Header.
-
- @return Pointer to the first variable header.
-
-**/
-VARIABLE_HEADER *
-GetStartPointer (
- IN VARIABLE_STORE_HEADER *VarStoreHeader
- )
-{
- //
- // The start of variable store
- //
- return (VARIABLE_HEADER *)HEADER_ALIGN (VarStoreHeader + 1);
-}
-
-/**
-
- Gets the pointer to the end of the variable storage area.
-
- This function gets pointer to the end of the variable storage
- area, according to the input variable store header.
-
- @param VarStoreHeader Pointer to the Variable Store Header.
-
- @return Pointer to the end of the variable storage area.
-
-**/
-VARIABLE_HEADER *
-GetEndPointer (
- IN VARIABLE_STORE_HEADER *VarStoreHeader
- )
-{
- //
- // The end of variable store
- //
- return (VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)VarStoreHeader + VarStoreHeader->Size);
-}
-
-/**
- This code checks if variable header is valid or not.
-
- @param Variable Pointer to the Variable Header.
-
- @retval TRUE Variable header is valid.
- @retval FALSE Variable header is not valid.
-
-**/
-BOOLEAN
-IsValidVariableHeader (
- IN VARIABLE_HEADER *Variable
- )
-{
- if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-/**
- This code gets the size of variable header.
-
- @param AuthFlag Authenticated variable flag.
-
- @return Size of variable header in bytes in type UINTN.
-
-**/
-UINTN
-GetVariableHeaderSize (
- IN BOOLEAN AuthFlag
- )
-{
- UINTN Value;
-
- if (AuthFlag) {
- Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
- } else {
- Value = sizeof (VARIABLE_HEADER);
- }
-
- return Value;
-}
-
-/**
- This code gets the size of name of variable.
-
- @param Variable Pointer to the Variable Header.
- @param AuthFlag Authenticated variable flag.
-
- @return Size of variable in bytes in type UINTN.
-
-**/
-UINTN
-NameSizeOfVariable (
- IN VARIABLE_HEADER *Variable,
- IN BOOLEAN AuthFlag
- )
-{
- AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
-
- AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
- if (AuthFlag) {
- if ((AuthVariable->State == (UINT8)(-1)) ||
- (AuthVariable->DataSize == (UINT32)(-1)) ||
- (AuthVariable->NameSize == (UINT32)(-1)) ||
- (AuthVariable->Attributes == (UINT32)(-1)))
- {
- return 0;
- }
-
- return (UINTN)AuthVariable->NameSize;
- } else {
- if ((Variable->State == (UINT8)(-1)) ||
- (Variable->DataSize == (UINT32)(-1)) ||
- (Variable->NameSize == (UINT32)(-1)) ||
- (Variable->Attributes == (UINT32)(-1)))
- {
- return 0;
- }
-
- return (UINTN)Variable->NameSize;
- }
-}
-
-/**
- This code gets the size of data of variable.
-
- @param Variable Pointer to the Variable Header.
- @param AuthFlag Authenticated variable flag.
-
- @return Size of variable in bytes in type UINTN.
-
-**/
-UINTN
-DataSizeOfVariable (
- IN VARIABLE_HEADER *Variable,
- IN BOOLEAN AuthFlag
- )
-{
- AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
-
- AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
- if (AuthFlag) {
- if ((AuthVariable->State == (UINT8)(-1)) ||
- (AuthVariable->DataSize == (UINT32)(-1)) ||
- (AuthVariable->NameSize == (UINT32)(-1)) ||
- (AuthVariable->Attributes == (UINT32)(-1)))
- {
- return 0;
- }
-
- return (UINTN)AuthVariable->DataSize;
- } else {
- if ((Variable->State == (UINT8)(-1)) ||
- (Variable->DataSize == (UINT32)(-1)) ||
- (Variable->NameSize == (UINT32)(-1)) ||
- (Variable->Attributes == (UINT32)(-1)))
- {
- return 0;
- }
-
- return (UINTN)Variable->DataSize;
- }
-}
-
-/**
- This code gets the pointer to the variable name.
-
- @param Variable Pointer to the Variable Header.
- @param AuthFlag Authenticated variable flag.
-
- @return A CHAR16* pointer to Variable Name.
-
-**/
-CHAR16 *
-GetVariableNamePtr (
- IN VARIABLE_HEADER *Variable,
- IN BOOLEAN AuthFlag
- )
-{
- return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag));
-}
-
-/**
- This code gets the pointer to the variable guid.
-
- @param Variable Pointer to the Variable Header.
- @param AuthFlag Authenticated variable flag.
-
- @return A EFI_GUID* pointer to Vendor Guid.
-
-**/
-EFI_GUID *
-GetVendorGuidPtr (
- IN VARIABLE_HEADER *Variable,
- IN BOOLEAN AuthFlag
- )
-{
- AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
-
- AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
- if (AuthFlag) {
- return &AuthVariable->VendorGuid;
- } else {
- return &Variable->VendorGuid;
- }
-}
-
-/**
- This code gets the pointer to the variable data.
-
- @param Variable Pointer to the Variable Header.
- @param VariableHeader Pointer to the Variable Header that has consecutive content.
- @param AuthFlag Authenticated variable flag.
-
- @return A UINT8* pointer to Variable Data.
-
-**/
-UINT8 *
-GetVariableDataPtr (
- IN VARIABLE_HEADER *Variable,
- IN VARIABLE_HEADER *VariableHeader,
- IN BOOLEAN AuthFlag
- )
-{
- UINTN Value;
-
- //
- // Be careful about pad size for alignment
- //
- Value = (UINTN)GetVariableNamePtr (Variable, AuthFlag);
- Value += NameSizeOfVariable (VariableHeader, AuthFlag);
- Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));
-
- return (UINT8 *)Value;
-}
-
-/**
- This code gets the pointer to the next variable header.
-
- @param StoreInfo Pointer to variable store info structure.
- @param Variable Pointer to the Variable Header.
- @param VariableHeader Pointer to the Variable Header that has consecutive content.
-
- @return A VARIABLE_HEADER* pointer to next variable header.
-
-**/
-VARIABLE_HEADER *
-GetNextVariablePtr (
- IN VARIABLE_STORE_INFO *StoreInfo,
- IN VARIABLE_HEADER *Variable,
- IN VARIABLE_HEADER *VariableHeader
- )
-{
- EFI_PHYSICAL_ADDRESS TargetAddress;
- EFI_PHYSICAL_ADDRESS SpareAddress;
- UINTN Value;
-
- Value = (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo->AuthFlag);
- Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);
- Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag));
- //
- // Be careful about pad size for alignment
- //
- Value = HEADER_ALIGN (Value);
-
- if (StoreInfo->FtwLastWriteData != NULL) {
- TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
- SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
- if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >= (UINTN)TargetAddress)) {
- //
- // Next variable is in spare block.
- //
- Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress);
- }
- }
-
- return (VARIABLE_HEADER *)Value;
-}
-
-/**
- Get variable store status.
-
- @param VarStoreHeader Pointer to the Variable Store Header.
-
- @retval EfiRaw Variable store is raw
- @retval EfiValid Variable store is valid
- @retval EfiInvalid Variable store is invalid
-
-**/
-VARIABLE_STORE_STATUS
-GetVariableStoreStatus (
- IN VARIABLE_STORE_HEADER *VarStoreHeader
- )
-{
- if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) ||
- CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
- (VarStoreHeader->Format == VARIABLE_STORE_FORMATTED) &&
- (VarStoreHeader->State == VARIABLE_STORE_HEALTHY)
- )
- {
- return EfiValid;
- }
-
- if ((((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff) &&
- (((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff) &&
- (((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff) &&
- (((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff) &&
- (VarStoreHeader->Size == 0xffffffff) &&
- (VarStoreHeader->Format == 0xff) &&
- (VarStoreHeader->State == 0xff)
- )
- {
- return EfiRaw;
- } else {
- return EfiInvalid;
- }
-}
-
-/**
- Compare two variable names, one of them may be inconsecutive.
-
- @param StoreInfo Pointer to variable store info structure.
- @param Name1 Pointer to one variable name.
- @param Name2 Pointer to another variable name.
- @param NameSize Variable name size.
-
- @retval TRUE Name1 and Name2 are identical.
- @retval FALSE Name1 and Name2 are not identical.
-
-**/
-BOOLEAN
-CompareVariableName (
- IN VARIABLE_STORE_INFO *StoreInfo,
- IN CONST CHAR16 *Name1,
- IN CONST CHAR16 *Name2,
- IN UINTN NameSize
- )
-{
- EFI_PHYSICAL_ADDRESS TargetAddress;
- EFI_PHYSICAL_ADDRESS SpareAddress;
- UINTN PartialNameSize;
-
- if (StoreInfo->FtwLastWriteData != NULL) {
- TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
- SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
- if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 + NameSize) > (UINTN)TargetAddress)) {
- //
- // Name1 is inconsecutive.
- //
- PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1;
- //
- // Partial content is in NV storage.
- //
- if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize) == 0) {
- //
- // Another partial content is in spare block.
- //
- if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) {
- return TRUE;
- }
- }
-
- return FALSE;
- } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 + NameSize) > (UINTN)TargetAddress)) {
- //
- // Name2 is inconsecutive.
- //
- PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2;
- //
- // Partial content is in NV storage.
- //
- if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize) == 0) {
- //
- // Another partial content is in spare block.
- //
- if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) {
- return TRUE;
- }
- }
-
- return FALSE;
- }
- }
-
- //
- // Both Name1 and Name2 are consecutive.
- //
- if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- This function compares a variable with variable entries in database.
-
- @param StoreInfo Pointer to variable store info structure.
- @param Variable Pointer to the variable in our database
- @param VariableHeader Pointer to the Variable Header that has consecutive content.
- @param VariableName Name of the variable to compare to 'Variable'
- @param VendorGuid GUID of the variable to compare to 'Variable'
- @param PtrTrack Variable Track Pointer structure that contains Variable Information.
-
- @retval EFI_SUCCESS Found match variable
- @retval EFI_NOT_FOUND Variable not found
-
-**/
-EFI_STATUS
-CompareWithValidVariable (
- IN VARIABLE_STORE_INFO *StoreInfo,
- IN VARIABLE_HEADER *Variable,
- IN VARIABLE_HEADER *VariableHeader,
- IN CONST CHAR16 *VariableName,
- IN CONST EFI_GUID *VendorGuid,
- OUT VARIABLE_POINTER_TRACK *PtrTrack
- )
-{
- VOID *Point;
- EFI_GUID *TempVendorGuid;
-
- TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag);
-
- if (VariableName[0] == 0) {
- PtrTrack->CurrPtr = Variable;
- return EFI_SUCCESS;
- } else {
- //
- // Don't use CompareGuid function here for performance reasons.
- // Instead we compare the GUID a UINT32 at a time and branch
- // on the first failed comparison.
- //
- if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) &&
- (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) &&
- (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) &&
- (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3])
- )
- {
- ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);
- Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag);
- if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {
- PtrTrack->CurrPtr = Variable;
- return EFI_SUCCESS;
- }
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Get HOB variable store.
-
- @param[out] StoreInfo Return the store info.
- @param[out] VariableStoreHeader Return variable store header.
-
-**/
-VOID
-GetHobVariableStore (
- OUT VARIABLE_STORE_INFO *StoreInfo,
- OUT VARIABLE_STORE_HEADER **VariableStoreHeader
- )
-{
- EFI_HOB_GUID_TYPE *GuidHob;
-
- //
- // Make sure there is no more than one Variable HOB.
- //
- DEBUG_CODE_BEGIN ();
- GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
- if (GuidHob != NULL) {
- if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
- DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
- ASSERT (FALSE);
- } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
- DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));
- ASSERT (FALSE);
- }
- } else {
- GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
- if (GuidHob != NULL) {
- if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
- DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
- ASSERT (FALSE);
- }
- }
- }
-
- DEBUG_CODE_END ();
-
- GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
- if (GuidHob != NULL) {
- *VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
- StoreInfo->AuthFlag = TRUE;
- } else {
- GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
- if (GuidHob != NULL) {
- *VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
- StoreInfo->AuthFlag = FALSE;
- }
- }
-}
-
-/**
- Return the variable store header and the store info based on the Index.
-
- @param Type The type of the variable store.
- @param StoreInfo Return the store info.
-
- @return Pointer to the variable store header.
-**/
-VARIABLE_STORE_HEADER *
-GetVariableStore (
- IN VARIABLE_STORE_TYPE Type,
- OUT VARIABLE_STORE_INFO *StoreInfo
- )
-{
- EFI_HOB_GUID_TYPE *GuidHob;
- EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
- VARIABLE_STORE_HEADER *VariableStoreHeader;
- EFI_PHYSICAL_ADDRESS NvStorageBase;
- UINT32 NvStorageSize;
- FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
- UINT32 BackUpOffset;
-
- StoreInfo->IndexTable = NULL;
- StoreInfo->FtwLastWriteData = NULL;
- StoreInfo->AuthFlag = FALSE;
- VariableStoreHeader = NULL;
- switch (Type) {
- case VariableStoreTypeHob:
- GetHobVariableStore (StoreInfo, &VariableStoreHeader);
-
- break;
-
- case VariableStoreTypeNv:
- if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
- //
- // Emulated non-volatile variable mode is not enabled.
- //
-
- NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
- NvStorageBase = (EFI_PHYSICAL_ADDRESS)(PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ?
- PcdGet64 (PcdFlashNvStorageVariableBase64) :
- PcdGet32 (PcdFlashNvStorageVariableBase)
- );
- ASSERT (NvStorageBase != 0);
-
- //
- // First let FvHeader point to NV storage base.
- //
- FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase;
-
- //
- // Check the FTW last write data hob.
- //
- BackUpOffset = 0;
- GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
- if (GuidHob != NULL) {
- FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *)GET_GUID_HOB_DATA (GuidHob);
- if (FtwLastWriteData->TargetAddress == NvStorageBase) {
- //
- // Let FvHeader point to spare block.
- //
- FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FtwLastWriteData->SpareAddress;
- DEBUG ((DEBUG_INFO, "PeiVariable: NV storage is backed up in spare block: 0x%x\n", (UINTN)FtwLastWriteData->SpareAddress));
- } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {
- StoreInfo->FtwLastWriteData = FtwLastWriteData;
- //
- // Flash NV storage from the offset is backed up in spare block.
- //
- BackUpOffset = (UINT32)(FtwLastWriteData->TargetAddress - NvStorageBase);
- DEBUG ((DEBUG_INFO, "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN)FtwLastWriteData->SpareAddress));
- //
- // At least one block data in flash NV storage is still valid, so still leave FvHeader point to NV storage base.
- //
- }
- }
-
- //
- // Check if the Firmware Volume is not corrupted
- //
- if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {
- DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
- break;
- }
-
- VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINT8 *)FvHeader + FvHeader->HeaderLength);
-
- StoreInfo->AuthFlag = (BOOLEAN)(CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid));
-
- GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
- if (GuidHob != NULL) {
- StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
- } else {
- //
- // If it's the first time to access variable region in flash, create a guid hob to record
- // VAR_ADDED type variable info.
- // Note that as the resource of PEI phase is limited, only store the limited number of
- // VAR_ADDED type variables to reduce access time.
- //
- StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE *)BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
- StoreInfo->IndexTable->Length = 0;
- StoreInfo->IndexTable->StartPtr = GetStartPointer (VariableStoreHeader);
- StoreInfo->IndexTable->EndPtr = GetEndPointer (VariableStoreHeader);
- StoreInfo->IndexTable->GoneThrough = 0;
- }
- }
-
- break;
-
- default:
- ASSERT (FALSE);
- break;
- }
-
- StoreInfo->VariableStoreHeader = VariableStoreHeader;
- return VariableStoreHeader;
-}
-
-/**
- Get variable header that has consecutive content.
-
- @param StoreInfo Pointer to variable store info structure.
- @param Variable Pointer to the Variable Header.
- @param VariableHeader Pointer to Pointer to the Variable Header that has consecutive content.
-
- @retval TRUE Variable header is valid.
- @retval FALSE Variable header is not valid.
-
-**/
-BOOLEAN
-GetVariableHeader (
- IN VARIABLE_STORE_INFO *StoreInfo,
- IN VARIABLE_HEADER *Variable,
- OUT VARIABLE_HEADER **VariableHeader
- )
-{
- EFI_PHYSICAL_ADDRESS TargetAddress;
- EFI_PHYSICAL_ADDRESS SpareAddress;
- EFI_HOB_GUID_TYPE *GuidHob;
- UINTN PartialHeaderSize;
-
- if (Variable == NULL) {
- return FALSE;
- }
-
- //
- // First assume variable header pointed by Variable is consecutive.
- //
- *VariableHeader = Variable;
-
- if (StoreInfo->FtwLastWriteData != NULL) {
- TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
- SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
- if (((UINTN)Variable > (UINTN)SpareAddress) &&
- (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >= (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader)))
- {
- //
- // Reach the end of variable store.
- //
- return FALSE;
- }
-
- if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable + GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) {
- //
- // Variable header pointed by Variable is inconsecutive,
- // create a guid hob to combine the two partial variable header content together.
- //
- GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
- if (GuidHob != NULL) {
- *VariableHeader = (VARIABLE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
- } else {
- *VariableHeader = (VARIABLE_HEADER *)BuildGuidHob (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag));
- PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable;
- //
- // Partial content is in NV storage.
- //
- CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable, PartialHeaderSize);
- //
- // Another partial content is in spare block.
- //
- CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8 *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) - PartialHeaderSize);
- }
- }
- } else {
- if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
- //
- // Reach the end of variable store.
- //
- return FALSE;
- }
- }
-
- return IsValidVariableHeader (*VariableHeader);
-}
-
-/**
- Get variable name or data to output buffer.
-
- @param StoreInfo Pointer to variable store info structure.
- @param NameOrData Pointer to the variable name/data that may be inconsecutive.
- @param Size Variable name/data size.
- @param Buffer Pointer to output buffer to hold the variable name/data.
-
-**/
-VOID
-GetVariableNameOrData (
- IN VARIABLE_STORE_INFO *StoreInfo,
- IN UINT8 *NameOrData,
- IN UINTN Size,
- OUT UINT8 *Buffer
- )
-{
- EFI_PHYSICAL_ADDRESS TargetAddress;
- EFI_PHYSICAL_ADDRESS SpareAddress;
- UINTN PartialSize;
-
- if (StoreInfo->FtwLastWriteData != NULL) {
- TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
- SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
- if (((UINTN)NameOrData < (UINTN)TargetAddress) && (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) {
- //
- // Variable name/data is inconsecutive.
- //
- PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData;
- //
- // Partial content is in NV storage.
- //
- CopyMem (Buffer, NameOrData, PartialSize);
- //
- // Another partial content is in spare block.
- //
- CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size - PartialSize);
- return;
- }
- }
-
- //
- // Variable name/data is consecutive.
- //
- CopyMem (Buffer, NameOrData, Size);
-}
-
/**
Find the variable in the specified variable store.
@@ -1246,3 +522,107 @@ PeiGetNextVariableName (
}
}
}
+
+/**
+ This service retrieves a variable's value using its name and GUID.
+
+ Read the specified variable from the UEFI variable store. If the Data
+ buffer is too small to hold the contents of the variable, the error
+ EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+ size to obtain the data.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+ @param VariableName A pointer to a null-terminated string that is the variable's name.
+ @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+ @param Attributes If non-NULL, on return, points to the variable's attributes.
+ @param DataSize On entry, points to the size in bytes of the Data buffer.
+ On return, points to the size of the data returned in Data.
+ @param Data Points to the buffer which will hold the returned variable value.
+ May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable was be found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
+ DataSize is updated with the size required for
+ the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariableEx (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // If variable protection is employed, always get variable data through
+ // ProtectedVariableLib.
+ //
+ Status = ProtectedVariableLibGetByName (VariableName, VariableGuid, Attributes, DataSize, Data);
+ if (Status != EFI_UNSUPPORTED) {
+ return Status;
+ }
+
+ return PeiGetVariable (This, VariableName, VariableGuid, Attributes, DataSize, Data);
+}
+
+/**
+ Return the next variable name and GUID.
+
+ This function is called multiple times to retrieve the VariableName
+ and VariableGuid of all variables currently available in the system.
+ On each call, the previous results are passed into the interface,
+ and, on return, the interface returns the data for the next
+ interface. When the entire variable list has been returned,
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+ @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ On return, the size of the variable name buffer.
+ @param VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+ @param VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableNameEx (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // If variable protection is employed, always get next variable through
+ // ProtectedVariableLib.
+ //
+ Status = ProtectedVariableLibFindNext (VariableNameSize, VariableName, VariableGuid);
+ if (Status != EFI_UNSUPPORTED) {
+ return Status;
+ }
+
+ return PeiGetNextVariableName (This, VariableNameSize, VariableName, VariableGuid);
+}
diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableParsing.c b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.c
new file mode 100644
index 000000000000..2d605d39cbb6
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.c
@@ -0,0 +1,941 @@
+/** @file
+ Implement ReadOnly Variable Services required by PEIM and install
+ PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+#include "VariableStore.h"
+
+/**
+
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header.
+
+**/
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The start of variable store
+ //
+ return (VARIABLE_HEADER *)HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+/**
+
+ Gets the pointer to the end of the variable storage area.
+
+ This function gets pointer to the end of the variable storage
+ area, according to the input variable store header.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the end of the variable storage area.
+
+**/
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store
+ //
+ return (VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)VarStoreHeader + VarStoreHeader->Size);
+}
+
+/**
+ This code checks if variable header is valid or not.
+
+ @param[in] Variable Pointer to the Variable Header.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ This code gets the size of variable header.
+
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+ IN BOOLEAN AuthFlag
+ )
+{
+ UINTN Value;
+
+ if (AuthFlag) {
+ Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ } else {
+ Value = sizeof (VARIABLE_HEADER);
+ }
+
+ return Value;
+}
+
+/**
+ This code gets the size of name of variable.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+ if (AuthFlag) {
+ if ((AuthVariable->State == (UINT8)(-1)) ||
+ (AuthVariable->DataSize == (UINT32)(-1)) ||
+ (AuthVariable->NameSize == (UINT32)(-1)) ||
+ (AuthVariable->Attributes == (UINT32)(-1)))
+ {
+ return 0;
+ }
+
+ return (UINTN)AuthVariable->NameSize;
+ } else {
+ if ((Variable->State == (UINT8)(-1)) ||
+ (Variable->DataSize == (UINT32)(-1)) ||
+ (Variable->NameSize == (UINT32)(-1)) ||
+ (Variable->Attributes == (UINT32)(-1)))
+ {
+ return 0;
+ }
+
+ return (UINTN)Variable->NameSize;
+ }
+}
+
+/**
+ This code gets the size of data of variable.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+ if (AuthFlag) {
+ if ((AuthVariable->State == (UINT8)(-1)) ||
+ (AuthVariable->DataSize == (UINT32)(-1)) ||
+ (AuthVariable->NameSize == (UINT32)(-1)) ||
+ (AuthVariable->Attributes == (UINT32)(-1)))
+ {
+ return 0;
+ }
+
+ return (UINTN)AuthVariable->DataSize;
+ } else {
+ if ((Variable->State == (UINT8)(-1)) ||
+ (Variable->DataSize == (UINT32)(-1)) ||
+ (Variable->NameSize == (UINT32)(-1)) ||
+ (Variable->Attributes == (UINT32)(-1)))
+ {
+ return 0;
+ }
+
+ return (UINTN)Variable->DataSize;
+ }
+}
+
+/**
+ This code gets the pointer to the variable name.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return A CHAR16* pointer to Variable Name.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag));
+}
+
+/**
+ This code gets the pointer to the variable guid.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+ if (AuthFlag) {
+ return &AuthVariable->VendorGuid;
+ } else {
+ return &Variable->VendorGuid;
+ }
+}
+
+/**
+ This code gets the pointer to the variable data.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] VariableHeader Pointer to the Variable Header that has consecutive content.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return A UINT8* pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader,
+ IN BOOLEAN AuthFlag
+ )
+{
+ UINTN Value;
+
+ //
+ // Be careful about pad size for alignment
+ //
+ Value = (UINTN)GetVariableNamePtr (Variable, AuthFlag);
+ Value += NameSizeOfVariable (VariableHeader, AuthFlag);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));
+
+ return (UINT8 *)Value;
+}
+
+/**
+ This code gets the pointer to the next variable header.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] VariableHeader Pointer to the Variable Header that has consecutive content.
+
+ @return A VARIABLE_HEADER* pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ UINTN Value;
+
+ Value = (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo->AuthFlag);
+ Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);
+ Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag));
+ //
+ // Be careful about pad size for alignment
+ //
+ Value = HEADER_ALIGN (Value);
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >= (UINTN)TargetAddress)) {
+ //
+ // Next variable is in spare block.
+ //
+ Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress);
+ }
+ }
+
+ return (VARIABLE_HEADER *)Value;
+}
+
+/**
+ Compare two variable names, one of them may be inconsecutive.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Name1 Pointer to one variable name.
+ @param[in] Name2 Pointer to another variable name.
+ @param[in] NameSize Variable name size.
+
+ @retval TRUE Name1 and Name2 are identical.
+ @retval FALSE Name1 and Name2 are not identical.
+
+**/
+BOOLEAN
+CompareVariableName (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN CONST CHAR16 *Name1,
+ IN CONST CHAR16 *Name2,
+ IN UINTN NameSize
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ UINTN PartialNameSize;
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 + NameSize) > (UINTN)TargetAddress)) {
+ //
+ // Name1 is inconsecutive.
+ //
+ PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1;
+ //
+ // Partial content is in NV storage.
+ //
+ if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize) == 0) {
+ //
+ // Another partial content is in spare block.
+ //
+ if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 + NameSize) > (UINTN)TargetAddress)) {
+ //
+ // Name2 is inconsecutive.
+ //
+ PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2;
+ //
+ // Partial content is in NV storage.
+ //
+ if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize) == 0) {
+ //
+ // Another partial content is in spare block.
+ //
+ if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+ }
+
+ //
+ // Both Name1 and Name2 are consecutive.
+ //
+ if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ This function compares a variable with variable entries in database.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Variable Pointer to the variable in our database
+ @param[in] VariableHeader Pointer to the Variable Header that has
+ consecutive content.
+ @param[in] VariableName Name of the variable to compare to 'Variable'
+ @param[in] VendorGuid GUID of the variable to compare to 'Variable'
+ @param[out] PtrTrack Variable Track Pointer structure that contains
+ Variable Information.
+
+ @retval EFI_SUCCESS Found match variable
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+CompareWithValidVariable (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack
+ )
+{
+ VOID *Point;
+ EFI_GUID *TempVendorGuid;
+
+ TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag);
+
+ if (VariableName[0] == 0) {
+ PtrTrack->CurrPtr = Variable;
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Don't use CompareGuid function here for performance reasons.
+ // Instead we compare the GUID a UINT32 at a time and branch
+ // on the first failed comparison.
+ //
+ if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) &&
+ (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) &&
+ (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) &&
+ (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3])
+ )
+ {
+ ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);
+ Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag);
+ if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {
+ PtrTrack->CurrPtr = Variable;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Get variable header that has consecutive content.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Variable Pointer to the Variable Header.
+ @param[out] VariableHeader Pointer to Pointer to the Variable Header
+ that has consecutive content.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+GetVariableHeader (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ OUT VARIABLE_HEADER **VariableHeader
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ UINTN PartialHeaderSize;
+
+ if (Variable == NULL) {
+ return FALSE;
+ }
+
+ //
+ // First assume variable header pointed by Variable is consecutive.
+ //
+ *VariableHeader = Variable;
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN)Variable > (UINTN)SpareAddress) &&
+ (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >= (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader)))
+ {
+ //
+ // Reach the end of variable store.
+ //
+ return FALSE;
+ }
+
+ if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable + GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) {
+ //
+ // Variable header pointed by Variable is inconsecutive,
+ // create a guid hob to combine the two partial variable header content together.
+ //
+ GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
+ if (GuidHob != NULL) {
+ *VariableHeader = (VARIABLE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ *VariableHeader = (VARIABLE_HEADER *)BuildGuidHob (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag));
+ PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable;
+ //
+ // Partial content is in NV storage.
+ //
+ CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable, PartialHeaderSize);
+ //
+ // Another partial content is in spare block.
+ //
+ CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8 *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) - PartialHeaderSize);
+ }
+ }
+ } else {
+ if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
+ //
+ // Reach the end of variable store.
+ //
+ return FALSE;
+ }
+ }
+
+ return IsValidVariableHeader (*VariableHeader);
+}
+
+/**
+ Get variable name or data to output buffer.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] NameOrData Pointer to the variable name/data that may be inconsecutive.
+ @param[in] Size Variable name/data size.
+ @param[out] Buffer Pointer to output buffer to hold the variable name/data.
+
+**/
+VOID
+GetVariableNameOrData (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN UINT8 *NameOrData,
+ IN UINTN Size,
+ OUT UINT8 *Buffer
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ UINTN PartialSize;
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN)NameOrData < (UINTN)TargetAddress) && (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) {
+ //
+ // Variable name/data is inconsecutive.
+ //
+ PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData;
+ //
+ // Partial content is in NV storage.
+ //
+ CopyMem (Buffer, NameOrData, PartialSize);
+ //
+ // Another partial content is in spare block.
+ //
+ CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size - PartialSize);
+ return;
+ }
+ }
+
+ //
+ // Variable name/data is consecutive.
+ //
+ CopyMem (Buffer, NameOrData, Size);
+}
+
+/**
+
+ Internal function to retrieve variable information.
+
+ @param[in,out] VariableInfo Pointer to variable information.
+ @param[in] StoreInfo Pointer to store copy of variable (optional).
+ @param[in] VariablePtr Pointer to variable buffer.
+ @param[in] VariableHeader Pointer to variable header.
+
+ @retval EFI_INVALID_PARAMETER One ore more required parameters are NULL.
+ @retval EFI_BUFFER_TOO_SMALL Given buffer is too small to hold data.
+ @retval EFI_SUCCESS Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableInfoInternal (
+ IN OUT PROTECTED_VARIABLE_INFO *VariableInfo,
+ IN VARIABLE_STORE_INFO *StoreInfo OPTIONAL,
+ IN VARIABLE_HEADER *VariablePtr,
+ IN VARIABLE_HEADER *VariableHeader
+ )
+{
+ VARIABLE_HEADER *VariableBuffer;
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariableHeader;
+ UINTN NameSize;
+ UINTN DataSize;
+ UINTN VariableSize;
+
+ if ((VariableInfo == NULL) || (VariablePtr == NULL) || (VariableHeader == NULL)) {
+ ASSERT (VariableInfo != NULL);
+ ASSERT (VariablePtr != NULL);
+ ASSERT (VariableHeader != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableBuffer = VariableInfo->Buffer;
+
+ //
+ // Make a copy of the whole variable if VariableInfo->Buffer is given. But
+ // don't do this if StoreInfo is not given, because VariableInfo->Buffer
+ // has already hold a copy of variable in such situation.
+ //
+ NameSize = NameSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
+ DataSize = DataSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
+ if ((VariableBuffer != NULL) && (VariableBuffer != VariablePtr)) {
+ if (StoreInfo != NULL) {
+ CopyMem (
+ VariableBuffer,
+ VariableHeader,
+ GetVariableHeaderSize (VariableInfo->Flags.Auth)
+ );
+ GetVariableNameOrData (
+ StoreInfo,
+ (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
+ NameSize,
+ (UINT8 *)GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth)
+ );
+ GetVariableNameOrData (
+ StoreInfo,
+ (UINT8 *)GetVariableDataPtr (VariablePtr, VariableHeader, VariableInfo->Flags.Auth),
+ DataSize,
+ (UINT8 *)GetVariableDataPtr (VariableBuffer, VariableHeader, VariableInfo->Flags.Auth)
+ );
+ } else {
+ //
+ // Suppose the variable is in consecutive space.
+ //
+ VariableSize = GetVariableHeaderSize (VariableInfo->Flags.Auth)
+ + NameSize + GET_PAD_SIZE (NameSize)
+ + DataSize;
+ CopyMem (VariableBuffer, VariablePtr, VariableSize);
+ }
+ }
+
+ //
+ // Generally, if no consecutive buffer passed in, don't return back any data.
+ //
+ // If follow pointers are NULL, return back pointers to following data inside
+ // VariableInfo->Buffer, if it's given.
+ //
+ // VariableInfo->Header.VariableName
+ // VariableInfo->Header.Data
+ // VariableInfo->Header.VendorGuid
+ // VariableInfo->Header.TimeStamp
+ //
+ // Otherwise, suppose they're buffers used to hold a copy of corresponding
+ // data.
+ //
+ //
+
+ //
+ // AuthVariable header
+ //
+ if (VariableInfo->Flags.Auth) {
+ AuthVariableHeader = (AUTHENTICATED_VARIABLE_HEADER *)VariableHeader;
+
+ VariableInfo->Header.State = AuthVariableHeader->State;
+ VariableInfo->Header.Attributes = AuthVariableHeader->Attributes;
+ VariableInfo->Header.PubKeyIndex = AuthVariableHeader->PubKeyIndex;
+ VariableInfo->Header.MonotonicCount = ReadUnaligned64 (
+ &(AuthVariableHeader->MonotonicCount)
+ );
+ if (VariableInfo->Header.TimeStamp != NULL) {
+ CopyMem (
+ VariableInfo->Header.TimeStamp,
+ &AuthVariableHeader->TimeStamp,
+ sizeof (EFI_TIME)
+ );
+ } else if (VariableBuffer != NULL) {
+ AuthVariableHeader = (AUTHENTICATED_VARIABLE_HEADER *)VariableBuffer;
+ VariableInfo->Header.TimeStamp = &AuthVariableHeader->TimeStamp;
+ }
+ } else {
+ VariableInfo->Header.State = VariableHeader->State;
+ VariableInfo->Header.Attributes = VariableHeader->Attributes;
+ VariableInfo->Header.PubKeyIndex = 0;
+ VariableInfo->Header.MonotonicCount = 0;
+ VariableInfo->Header.TimeStamp = NULL;
+ }
+
+ //
+ // VendorGuid
+ //
+ if (VariableInfo->Header.VendorGuid != NULL) {
+ CopyGuid (
+ VariableInfo->Header.VendorGuid,
+ GetVendorGuidPtr (VariableHeader, VariableInfo->Flags.Auth)
+ );
+ } else if (VariableBuffer != NULL) {
+ VariableInfo->Header.VendorGuid
+ = GetVendorGuidPtr (VariableBuffer, VariableInfo->Flags.Auth);
+ }
+
+ //
+ // VariableName
+ //
+ if ( (VariableInfo->Header.VariableName != NULL)
+ && (VariableInfo->Header.NameSize >= NameSize))
+ {
+ GetVariableNameOrData (
+ StoreInfo,
+ (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
+ NameSize,
+ (UINT8 *)VariableInfo->Header.VariableName
+ );
+ } else if (VariableBuffer != NULL) {
+ VariableInfo->Header.VariableName
+ = GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth);
+ } else if (VariableInfo->Header.VariableName != NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Data
+ //
+ if ( (VariableInfo->Header.Data != NULL)
+ && (VariableInfo->Header.DataSize >= DataSize))
+ {
+ GetVariableNameOrData (
+ StoreInfo,
+ GetVariableDataPtr (VariablePtr, VariableHeader, StoreInfo->AuthFlag),
+ DataSize,
+ VariableInfo->Header.Data
+ );
+ } else if (VariableBuffer != NULL) {
+ VariableInfo->Header.Data
+ = GetVariableDataPtr (VariableBuffer, VariableBuffer, VariableInfo->Flags.Auth);
+ } else if (VariableInfo->Header.Data != NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Update size information about name & data.
+ //
+ VariableInfo->Header.NameSize = NameSize;
+ VariableInfo->Header.DataSize = DataSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Retrieve details about a variable, given by VariableInfo->Buffer or
+ VariableInfo->Index, and pass the details back in VariableInfo->Header.
+
+ This function is used to resolve the variable data structure into
+ VariableInfo->Header, for easier access later without revisiting the variable
+ data in variable store. If pointers in the structure of VariableInfo->Header
+ are not NULL, it's supposed that they are buffers passed in to hold a copy of
+ data of corresponding data fields in variable data structure. Otherwise, this
+ function simply returns pointers pointing to address of those data fields.
+
+ The variable is specified by either VariableInfo->Index or VariableInfo->Buffer.
+ If VariableInfo->Index is given, this function finds the corresponding variable
+ first from variable storage according to the Index.
+
+ If both VariableInfo->Index and VariableInfo->Buffer are given, it's supposed
+ that VariableInfo->Buffer is a buffer passed in to hold a whole copy of
+ requested variable data to be returned.
+
+ @param[in,out] VariableInfo Pointer to variable information.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo->Buffer
+ and VariableInfo->Index are NULL (0).
+ @retval EFI_NOT_FOUND If given Buffer or Index is out of range of
+ any given or internal storage copies.
+ @retval EFI_SUCCESS Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
+ )
+{
+ VARIABLE_HEADER *VariablePtr;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_TYPE StoreType;
+ VARIABLE_STORE_INFO StoreInfo;
+ UINTN Offset;
+
+ if ((VariableInfo == NULL) ||
+ ((VariableInfo->Buffer == NULL) && (VariableInfo->StoreIndex == VAR_INDEX_INVALID)))
+ {
+ ASSERT (VariableInfo != NULL);
+ ASSERT (VariableInfo->StoreIndex != VAR_INDEX_INVALID || VariableInfo->Buffer != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StoreInfo.VariableStoreHeader = NULL;
+ for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax; ++StoreType) {
+ GetVariableStore (StoreType, &StoreInfo);
+ if (StoreInfo.VariableStoreHeader != NULL) {
+ break;
+ }
+ }
+
+ ASSERT (StoreInfo.VariableStoreHeader != NULL);
+
+ //
+ // No StoreIndex? Don't retrieve variable information from store but just from
+ // VariableInfo->Buffer.
+ //
+ if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
+ VariablePtr = VariableInfo->Buffer;
+ VariableHeader = VariablePtr;
+
+ return GetVariableInfoInternal (VariableInfo, NULL, VariablePtr, VariableHeader);
+ }
+
+ Offset = (UINTN)VariableInfo->StoreIndex;
+ if ( (StoreInfo.FtwLastWriteData != NULL)
+ && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+ - (UINTN)StoreInfo.VariableStoreHeader)))
+ {
+ Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+ - (UINTN)StoreInfo.VariableStoreHeader);
+ VariablePtr = (VARIABLE_HEADER *)
+ ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
+ } else {
+ VariablePtr = (VARIABLE_HEADER *)
+ ((UINTN)StoreInfo.VariableStoreHeader + Offset);
+ }
+
+ //
+ // Note that variable might be in unconsecutive space. Always get a copy
+ // of its header in consecutive buffer.
+ //
+ if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
+ return EFI_NOT_FOUND;
+ }
+
+ return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr, VariableHeader);
+}
+
+/**
+
+ Retrieve details of the variable next to given variable within VariableStore.
+
+ If VarInfo->Buffer is NULL, the first one in VariableStore is returned.
+
+ VariableStart and/or VariableEnd can be given optionally for the situation
+ in which the valid storage space is smaller than the VariableStore->Size.
+ This usually happens when PEI variable services make a compact variable
+ cache to save memory, which cannot make use VariableStore->Size to determine
+ the correct variable storage range.
+
+ @param[in,out] VariableInfo Pointer to variable information.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL.
+ @retval EFI_NOT_FOUND If the end of VariableStore is reached.
+ @retval EFI_SUCCESS The next variable is retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextVariableInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
+ )
+{
+ VARIABLE_HEADER *VariablePtr;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_INFO StoreInfo;
+ VARIABLE_STORE_TYPE StoreType;
+ UINTN Offset;
+
+ if (VariableInfo == NULL) {
+ ASSERT (VariableInfo != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StoreInfo.VariableStoreHeader = NULL;
+ for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax; ++StoreType) {
+ GetVariableStore (StoreType, &StoreInfo);
+ if (StoreInfo.VariableStoreHeader != NULL) {
+ break;
+ }
+ }
+
+ ASSERT (StoreInfo.VariableStoreHeader != NULL);
+
+ //
+ // VariableInfo->StoreIndex is supposed to be the index to variable found
+ // last time. Use it to get the variable next to it in store. If it's invalid,
+ // return the first variable available in store.
+ //
+ VariableInfo->Flags.Auth = StoreInfo.AuthFlag;
+ if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
+ VariablePtr = GetStartPointer (StoreInfo.VariableStoreHeader);
+ } else {
+ Offset = (UINTN)VariableInfo->StoreIndex;
+ if ( (StoreInfo.FtwLastWriteData != NULL)
+ && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+ - (UINTN)StoreInfo.VariableStoreHeader)))
+ {
+ Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+ - (UINTN)StoreInfo.VariableStoreHeader);
+ VariablePtr = (VARIABLE_HEADER *)
+ ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
+ } else {
+ VariablePtr = (VARIABLE_HEADER *)
+ ((UINTN)StoreInfo.VariableStoreHeader + Offset);
+ }
+
+ //
+ // Note that variable might be in unconsecutive space. Always get a copy
+ // of its header in consecutive buffer.
+ //
+ if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
+ return EFI_NOT_FOUND;
+ }
+
+ VariablePtr = GetNextVariablePtr (&StoreInfo, VariablePtr, VariableHeader);
+ }
+
+ //
+ // Get a copy of variable header in consecutive buffer.
+ //
+ if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Use the offset to the start of variable store as index of the variable.
+ //
+ if ( (StoreInfo.FtwLastWriteData == NULL)
+ || ((UINTN)VariablePtr < (UINTN)StoreInfo.FtwLastWriteData->TargetAddress))
+ {
+ VariableInfo->StoreIndex
+ = (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.VariableStoreHeader);
+ } else {
+ VariableInfo->StoreIndex
+ = (UINT64)((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+ - (UINTN)StoreInfo.VariableStoreHeader);
+ VariableInfo->StoreIndex
+ += (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.FtwLastWriteData->SpareAddress);
+ }
+
+ if ((StoreType == VariableStoreTypeHob) && (VariableInfo->Buffer == NULL)) {
+ VariableInfo->Buffer = VariablePtr;
+ }
+
+ return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr, VariableHeader);
+}
diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableStore.c b/MdeModulePkg/Universal/Variable/Pei/VariableStore.c
new file mode 100644
index 000000000000..72bd17a43048
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Pei/VariableStore.c
@@ -0,0 +1,305 @@
+/** @file
+ Implement ReadOnly Variable Services required by PEIM and install
+ PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VariableParsing.h"
+#include "VariableStore.h"
+
+/**
+ Get variable store status.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @retval EfiRaw Variable store is raw
+ @retval EfiValid Variable store is valid
+ @retval EfiInvalid Variable store is invalid
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) ||
+ CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
+ (VarStoreHeader->Format == VARIABLE_STORE_FORMATTED) &&
+ (VarStoreHeader->State == VARIABLE_STORE_HEALTHY)
+ )
+ {
+ return EfiValid;
+ }
+
+ if ((((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff) &&
+ (((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff) &&
+ (((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff) &&
+ (((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff) &&
+ (VarStoreHeader->Size == 0xffffffff) &&
+ (VarStoreHeader->Format == 0xff) &&
+ (VarStoreHeader->State == 0xff)
+ )
+ {
+ return EfiRaw;
+ } else {
+ return EfiInvalid;
+ }
+}
+
+/**
+ Reports HOB variable store is available or not.
+
+ @retval EFI_NOT_READY HOB variable store info not available.
+ @retval EFI_NOT_FOUND HOB variable store is NOT available.
+ @retval EFI_SUCCESS HOB variable store is available.
+**/
+EFI_STATUS
+EFIAPI
+IsHobVariableStoreAvailable (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ VOID *VariableStoreInfoHob;
+
+ //
+ // Discover if Variable Store Info Hob has been published by platform driver.
+ // It contains information regards to HOB or NV Variable Store availability
+ //
+ GuidHob = GetFirstGuidHob (&gEfiPeiVariableStoreDiscoveredPpiGuid);
+ if (GuidHob == NULL) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Check if HOB Variable Store is available
+ //
+ VariableStoreInfoHob = GET_GUID_HOB_DATA (GuidHob);
+ if (*(BOOLEAN *)VariableStoreInfoHob == TRUE) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // This might be NV Variable Store
+ //
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Get HOB variable store.
+
+ @param[out] StoreInfo Return the store info.
+
+**/
+VOID
+GetHobVariableStore (
+ OUT VARIABLE_STORE_INFO *StoreInfo
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ //
+ // Make sure there is no more than one Variable HOB.
+ //
+ DEBUG_CODE_BEGIN ();
+ GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+ if (GuidHob != NULL) {
+ if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
+ ASSERT (FALSE);
+ } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));
+ ASSERT (FALSE);
+ }
+ } else {
+ GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+ if (GuidHob != NULL) {
+ if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
+ ASSERT (FALSE);
+ }
+ }
+ }
+
+ DEBUG_CODE_END ();
+
+ GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+ if (GuidHob != NULL) {
+ StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
+ StoreInfo->AuthFlag = TRUE;
+ } else {
+ GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+ if (GuidHob != NULL) {
+ StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
+ StoreInfo->AuthFlag = FALSE;
+ }
+ }
+}
+
+/**
+ Get NV variable store.
+
+ @param[out] StoreInfo Return the store info.
+ @param[out] VariableFvHeader Return header of FV containing the store.
+
+**/
+VOID
+GetNvVariableStore (
+ OUT VARIABLE_STORE_INFO *StoreInfo,
+ OUT EFI_FIRMWARE_VOLUME_HEADER **VariableFvHeader
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ VARIABLE_STORE_HEADER *StoreHeader;
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *HobData;
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
+ EFI_PHYSICAL_ADDRESS NvStorageBase;
+ UINT32 NvStorageSize;
+ UINT32 BackUpOffset;
+
+ NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS)
+ (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0)
+ ? PcdGet64 (PcdFlashNvStorageVariableBase64)
+ : PcdGet32 (PcdFlashNvStorageVariableBase);
+ ASSERT (NvStorageBase != 0);
+
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase;
+
+ //
+ // Check the FTW last write data hob.
+ //
+ BackUpOffset = 0;
+ FtwLastWriteData = NULL;
+ HobData = NULL;
+ GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
+
+ if (GuidHob != NULL) {
+ HobData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *)GET_GUID_HOB_DATA (GuidHob);
+ if (HobData->TargetAddress == NvStorageBase) {
+ //
+ // Let FvHeader point to spare block.
+ //
+ DEBUG ((
+ EFI_D_INFO,
+ "PeiVariable: NV storage is backed up in spare block: 0x%x\n",
+ (UINTN)HobData->SpareAddress
+ ));
+
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)HobData->SpareAddress;
+ HobData = NULL;
+ } else if ((HobData->TargetAddress > NvStorageBase) &&
+ (HobData->TargetAddress < (NvStorageBase + NvStorageSize)))
+ {
+ //
+ // Flash NV storage from the offset is backed up in spare block.
+ //
+ BackUpOffset = (UINT32)(HobData->TargetAddress - NvStorageBase);
+ DEBUG ((
+ EFI_D_INFO,
+ "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n",
+ BackUpOffset,
+ (UINTN)FtwLastWriteData->SpareAddress
+ ));
+ //
+ // At least one block data in flash NV storage is still valid, so still
+ // leave FvHeader point to NV storage base.
+ //
+ }
+ }
+
+ if (StoreInfo != NULL) {
+ StoreInfo->FtwLastWriteData = HobData;
+ }
+
+ if (VariableFvHeader != NULL) {
+ *VariableFvHeader = FvHeader;
+ }
+
+ //
+ // Check if the Firmware Volume is not corrupted
+ //
+ if ((FvHeader->Signature == EFI_FVH_SIGNATURE) &&
+ CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))
+ {
+ StoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)FvHeader + FvHeader->HeaderLength);
+ } else {
+ StoreHeader = NULL;
+ DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
+ }
+
+ if (StoreInfo != NULL) {
+ StoreInfo->VariableStoreHeader = StoreHeader;
+ if (StoreHeader != NULL) {
+ StoreInfo->AuthFlag = CompareGuid (
+ &StoreHeader->Signature,
+ &gEfiAuthenticatedVariableGuid
+ );
+ }
+ }
+}
+
+/**
+ Return the variable store header and the store info based on the Index.
+
+ @param[in] Type The type of the variable store.
+ @param[out] StoreInfo Return the store info.
+
+ @return Pointer to the variable store header.
+**/
+VARIABLE_STORE_HEADER *
+GetVariableStore (
+ IN VARIABLE_STORE_TYPE Type,
+ OUT VARIABLE_STORE_INFO *StoreInfo
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ StoreInfo->VariableStoreHeader = NULL;
+ StoreInfo->IndexTable = NULL;
+ StoreInfo->FtwLastWriteData = NULL;
+ StoreInfo->AuthFlag = FALSE;
+ switch (Type) {
+ case VariableStoreTypeHob:
+ GetHobVariableStore (StoreInfo);
+ break;
+
+ case VariableStoreTypeNv:
+ if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
+ //
+ // Emulated non-volatile variable mode is not enabled.
+ //
+ GetNvVariableStore (StoreInfo, NULL);
+ if (StoreInfo->VariableStoreHeader != NULL) {
+ GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
+ if (GuidHob != NULL) {
+ StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ //
+ // If it's the first time to access variable region in flash, create a guid hob to record
+ // VAR_ADDED type variable info.
+ // Note that as the resource of PEI phase is limited, only store the limited number of
+ // VAR_ADDED type variables to reduce access time.
+ //
+ StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE *)BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
+ StoreInfo->IndexTable->Length = 0;
+ StoreInfo->IndexTable->StartPtr = GetStartPointer (StoreInfo->VariableStoreHeader);
+ StoreInfo->IndexTable->EndPtr = GetEndPointer (StoreInfo->VariableStoreHeader);
+ StoreInfo->IndexTable->GoneThrough = 0;
+ }
+ }
+ }
+
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ return StoreInfo->VariableStoreHeader;
+}
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 09/28] MdeModulePkg: Add support for Protected Variables
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (7 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 08/28] MdeModulePkg: Add new Variable functionality Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-22 14:03 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 10/28] SecurityPkg: Add new KeyService types and defines Judah Vang
` (20 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add support for Protected Variables.
Add new API to retrieve Variable Infomation and data.
Add new API to update variable in non-volatile storage or
cached copy.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf | 3 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf | 3 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf | 4 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf | 3 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h | 126 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h | 91 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c | 349 +++-
MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c | 2139 +++++++++++---------
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c | 26 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c | 167 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c | 194 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c | 320 ++-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c | 2 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c | 39 +-
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c | 41 +-
15 files changed, 2454 insertions(+), 1053 deletions(-)
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
index c9434df631ee..c0b90e6ca066 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
@@ -9,7 +9,7 @@
# This external input must be validated carefully to avoid security issues such as
# buffer overflow or integer overflow.
#
-# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -73,6 +73,7 @@ [LibraryClasses]
VarCheckLib
VariablePolicyLib
VariablePolicyHelperLib
+ ProtectedVariableLib
[Protocols]
gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
index eaa97a01c6e5..6f9f027fbb0f 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
@@ -18,7 +18,7 @@
# may not be modified without authorization. If platform fails to protect these resources,
# the authentication service provided in this driver will be broken, and the behavior is undefined.
#
-# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -82,6 +82,7 @@ [LibraryClasses]
UefiBootServicesTableLib
VariablePolicyLib
VariablePolicyHelperLib
+ ProtectedVariableLib
[Protocols]
gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
index a0d8b2267e92..5d2fc78ea917 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
@@ -13,7 +13,7 @@
# may not be modified without authorization. If platform fails to protect these resources,
# the authentication service provided in this driver will be broken, and the behavior is undefined.
#
-# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -61,6 +61,8 @@ [LibraryClasses]
SafeIntLib
PcdLib
MmUnblockMemoryLib
+ ProtectedVariableLib
+ IoLib
[Protocols]
gEfiVariableWriteArchProtocolGuid ## PRODUCES
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
index d8c4f77e7f1f..6ea7b8d4293e 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
@@ -18,7 +18,7 @@
# may not be modified without authorization. If platform fails to protect these resources,
# the authentication service provided in this driver will be broken, and the behavior is undefined.
#
-# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -78,6 +78,7 @@ [LibraryClasses]
VarCheckLib
VariablePolicyLib
VariablePolicyHelperLib
+ ProtectedVariableLib
[Protocols]
gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
index 31e408976a35..97b4f9c906ff 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
@@ -2,7 +2,7 @@
The internal header file includes the common header files, defines
internal structure and functions used by Variable modules.
-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -31,6 +31,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Library/MemoryAllocationLib.h>
#include <Library/AuthVariableLib.h>
#include <Library/VarCheckLib.h>
+#include <Library/ProtectedVariableLib.h>
#include <Guid/GlobalVariable.h>
#include <Guid/EventGroup.h>
#include <Guid/VariableFormat.h>
@@ -823,4 +824,127 @@ VariableExLibAtRuntime (
VOID
);
+/**
+ Is user variable?
+
+ @param[in] Variable Pointer to variable header.
+
+ @retval TRUE User variable.
+ @retval FALSE System variable.
+
+**/
+BOOLEAN
+IsUserVariable (
+ IN VARIABLE_HEADER *Variable
+ );
+
+/**
+
+ Variable store garbage collection and reclaim operation.
+
+ @param[in] VariableBase Base address of variable store.
+ @param[out] LastVariableOffset Offset of last variable.
+ @param[in] IsVolatile The variable store is volatile or not;
+ if it is non-volatile, need FTW.
+ @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
+ @param[in] NewVariable Pointer to new variable.
+ @param[in] NewVariableSize New variable size.
+
+ @return EFI_SUCCESS Reclaim operation has finished successfully.
+ @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
+ @return Others Unexpect error happened during reclaim operation.
+
+**/
+EFI_STATUS
+Reclaim (
+ IN EFI_PHYSICAL_ADDRESS VariableBase,
+ OUT UINTN *LastVariableOffset,
+ IN BOOLEAN IsVolatile,
+ IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN NewVariableSize
+ );
+
+/**
+
+ This function writes data to the FWH at the correct LBA even if the LBAs
+ are fragmented.
+
+ @param Global Pointer to VARIABLE_GLOBAL structure.
+ @param Volatile Point out the Variable is Volatile or Non-Volatile.
+ @param SetByIndex TRUE if target pointer is given as index.
+ FALSE if target pointer is absolute.
+ @param Fvb Pointer to the writable FVB protocol.
+ @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
+ structure.
+ @param DataSize Size of data to be written.
+ @param Buffer Pointer to the buffer from which data is written.
+
+ @retval EFI_INVALID_PARAMETER Parameters not valid.
+ @retval EFI_UNSUPPORTED Fvb is a NULL for Non-Volatile variable update.
+ @retval EFI_OUT_OF_RESOURCES The remaining size is not enough.
+ @retval EFI_SUCCESS Variable store successfully updated.
+
+**/
+EFI_STATUS
+UpdateVariableStore (
+ IN VARIABLE_GLOBAL *Global,
+ IN BOOLEAN Volatile,
+ IN BOOLEAN SetByIndex,
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ IN UINTN DataPtrIndex,
+ IN UINT32 DataSize,
+ IN UINT8 *Buffer
+ );
+
+/**
+ Update partial data of a variable on NV storage and/or cached copy.
+
+ @param[in] VariableInfo Pointer to a variable with detailed information.
+ @param[in] Offset Offset to write from.
+ @param[in] Size Size of data Buffer to update.
+ @param[in] Buffer Pointer to data buffer to update.
+
+ @retval EFI_SUCCESS The variable data was updated successfully.
+ @retval EFI_UNSUPPORTED If this function is called directly in runtime.
+ @retval EFI_INVALID_PARAMETER If VariableInfo, Buffer or Size are not valid.
+ @retval Others Failed to update NV storage or variable cache.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibUpdateNvVariable (
+ IN PROTECTED_VARIABLE_INFO *VariableInfo,
+ IN UINTN Offset,
+ IN UINT32 Size,
+ IN UINT8 *Buffer
+ );
+
+/**
+ Finds the given variable in a variable store in SMM.
+
+ Caution: This function may receive untrusted input.
+ The data size is external input, so this function will validate it carefully to avoid buffer overflow.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[out] Attributes Attribute value of the variable found.
+ @param[in, out] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[out] Data Data pointer.
+
+ @retval EFI_SUCCESS Found the specified variable.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+
+**/
+EFI_STATUS
+FindVariableInSmm (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ );
+
#endif
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
index 951e8a089e34..3a4e8019aaf9 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
@@ -2,7 +2,7 @@
Functions in this module are associated with variable parsing operations and
are intended to be usable across variable driver source files.
-Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -19,6 +19,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
@param[in] Variable Pointer to the Variable Header.
@param[in] VariableStoreEnd Pointer to the Variable Store End.
+ @param[in] AuthFormat Auth-variable indicator.
@retval TRUE Variable header is valid.
@retval FALSE Variable header is not valid.
@@ -27,7 +28,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
BOOLEAN
IsValidVariableHeader (
IN VARIABLE_HEADER *Variable,
- IN VARIABLE_HEADER *VariableStoreEnd
+ IN VARIABLE_HEADER *VariableStoreEnd,
+ IN BOOLEAN AuthFormat
);
/**
@@ -192,6 +194,28 @@ GetVariableDataOffset (
IN BOOLEAN AuthFormat
);
+/**
+ Get variable data payload.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[out] Data Pointer to buffer used to store the variable data.
+ @param[in] DataSize Size of buffer passed by Data.
+ @param[out] DataSize Size of data copied into Data buffer.
+ @param[in] AuthFlag Auth-variable indicator.
+
+ @return EFI_SUCCESS Data was fetched.
+ @return EFI_INVALID_PARAMETER DataSize is NULL.
+ @return EFI_BUFFER_TOO_SMALL DataSize is smaller than size of variable data.
+
+**/
+EFI_STATUS
+GetVariableData (
+ IN VARIABLE_HEADER *Variable,
+ IN OUT VOID *Data,
+ IN OUT UINT32 *DataSize,
+ IN BOOLEAN AuthFlag
+ );
+
/**
This code gets the pointer to the next variable header.
@@ -344,4 +368,67 @@ UpdateVariableInfo (
IN OUT VARIABLE_INFO_ENTRY **VariableInfo
);
+/**
+
+ Retrieve details of the variable next to given variable within VariableStore.
+
+ If VarInfo->Address is NULL, the first one in VariableStore is returned.
+
+ VariableStart and/or VariableEnd can be given optionally for the situation
+ in which the valid storage space is smaller than the VariableStore->Size.
+ This usually happens when PEI variable services make a compact variable
+ cache to save memory, which cannot make use VariableStore->Size to determine
+ the correct variable storage range.
+
+ @param VariableStore Pointer to a variable storage. It's optional.
+ @param VariableStart Start point of valid range in VariableStore.
+ @param VariableEnd End point of valid range in VariableStore.
+ @param VariableInfo Pointer to variable information.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL.
+ @retval EFI_NOT_FOUND If the end of VariableStore is reached.
+ @retval EFI_SUCCESS The next variable is retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextVariableInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ );
+
+/**
+
+ Retrieve details about a variable and return them in VariableInfo->Header.
+
+ If VariableInfo->Address is given, this function will calculate its offset
+ relative to given variable storage via VariableStore; Otherwise, it will try
+ other internal variable storages or cached copies. It's assumed that, for all
+ copies of NV variable storage, all variables are stored in the same relative
+ position. If VariableInfo->Address is found in the range of any storage copies,
+ its offset relative to that storage should be the same in other copies.
+
+ If VariableInfo->Offset is given (non-zero) but not VariableInfo->Address,
+ this function will return the variable memory address inside VariableStore,
+ if given, via VariableInfo->Address; Otherwise, the address of other storage
+ copies will be returned, if any.
+
+ For a new variable whose offset has not been determined, a value of -1 as
+ VariableInfo->Offset should be passed to skip the offset calculation.
+
+ @param VariableStore Pointer to a variable storage. It's optional.
+ @param VariableInfo Pointer to variable information.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo->Address
+ and VariableInfo->Offset are NULL (0).
+ @retval EFI_NOT_FOUND If given Address or Offset is out of range of
+ any given or internal storage copies.
+ @retval EFI_SUCCESS Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ );
+
#endif
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
index fe64d0a2b3dd..a5b7f8a1fbe2 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
@@ -2,12 +2,15 @@
Handles non-volatile variable store garbage collection, using FTW
(Fault Tolerant Write) protocol.
-Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Variable.h"
+#include "VariableNonVolatile.h"
+#include "VariableParsing.h"
+#include "VariableRuntimeCache.h"
/**
Gets LBA of block and offset by given address.
@@ -155,3 +158,347 @@ FtwVariableSpace (
return Status;
}
+
+/**
+
+ Variable store garbage collection and reclaim operation.
+
+ @param[in] VariableBase Base address of variable store.
+ @param[out] LastVariableOffset Offset of last variable.
+ @param[in] IsVolatile The variable store is volatile or not;
+ if it is non-volatile, need FTW.
+ @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
+ @param[in] NewVariable Pointer to new variable.
+ @param[in] NewVariableSize New variable size.
+
+ @return EFI_SUCCESS Reclaim operation has finished successfully.
+ @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
+ @return Others Unexpect error happened during reclaim operation.
+
+**/
+EFI_STATUS
+Reclaim (
+ IN EFI_PHYSICAL_ADDRESS VariableBase,
+ OUT UINTN *LastVariableOffset,
+ IN BOOLEAN IsVolatile,
+ IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN NewVariableSize
+ )
+{
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *AddedVariable;
+ VARIABLE_HEADER *NextVariable;
+ VARIABLE_HEADER *NextAddedVariable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINT8 *ValidBuffer;
+ UINTN MaximumBufferSize;
+ UINTN VariableSize;
+ UINTN NameSize;
+ UINT8 *CurrPtr;
+ VOID *Point0;
+ VOID *Point1;
+ BOOLEAN FoundAdded;
+ EFI_STATUS Status;
+ EFI_STATUS DoneStatus;
+ UINTN CommonVariableTotalSize;
+ UINTN CommonUserVariableTotalSize;
+ UINTN HwErrVariableTotalSize;
+ VARIABLE_HEADER *UpdatingVariable;
+ VARIABLE_HEADER *UpdatingInDeletedTransition;
+ BOOLEAN AuthFormat;
+
+ AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+ UpdatingVariable = NULL;
+ UpdatingInDeletedTransition = NULL;
+ if (UpdatingPtrTrack != NULL) {
+ UpdatingVariable = UpdatingPtrTrack->CurrPtr;
+ UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;
+ }
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)VariableBase);
+
+ CommonVariableTotalSize = 0;
+ CommonUserVariableTotalSize = 0;
+ HwErrVariableTotalSize = 0;
+
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+ //
+ // Start Pointers for the variable.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+ MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
+
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader), AuthFormat)) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ if (((Variable->State == VAR_ADDED) || (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) &&
+ (Variable != UpdatingVariable) &&
+ (Variable != UpdatingInDeletedTransition)
+ )
+ {
+ VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+ MaximumBufferSize += VariableSize;
+ }
+
+ Variable = NextVariable;
+ }
+
+ if (NewVariable != NULL) {
+ //
+ // Add the new variable size.
+ //
+ MaximumBufferSize += NewVariableSize;
+ }
+
+ //
+ // Reserve the 1 Bytes with Oxff to identify the
+ // end of the variable buffer.
+ //
+ MaximumBufferSize += 1;
+ ValidBuffer = AllocatePool (MaximumBufferSize);
+ if (ValidBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
+ // as the buffer to reduce SMRAM consumption for SMM variable driver.
+ //
+ MaximumBufferSize = mNvVariableCache->Size;
+ ValidBuffer = (UINT8 *)mNvVariableCache;
+ }
+
+ SetMem (ValidBuffer, MaximumBufferSize, 0xff);
+
+ //
+ // Copy variable store header.
+ //
+ CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
+ CurrPtr = (UINT8 *)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
+
+ //
+ // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader), AuthFormat)) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ if ((Variable != UpdatingVariable) && (Variable->State == VAR_ADDED)) {
+ VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+ CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
+ if (!IsVolatile) {
+ (VOID)ProtectedVariableLibRefresh (
+ (VARIABLE_HEADER *)CurrPtr,
+ VariableSize,
+ (UINTN)CurrPtr - (UINTN)ValidBuffer,
+ FALSE
+ );
+
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+ == EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+ {
+ HwErrVariableTotalSize += VariableSize;
+ } else {
+ CommonVariableTotalSize += VariableSize;
+ if (IsUserVariable (Variable)) {
+ CommonUserVariableTotalSize += VariableSize;
+ }
+ }
+ }
+
+ CurrPtr += VariableSize;
+ }
+
+ Variable = NextVariable;
+ }
+
+ //
+ // Reinstall all in delete transition variables.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader), AuthFormat)) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ if ((Variable != UpdatingVariable) && (Variable != UpdatingInDeletedTransition) && (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) &&
+ (ProtectedVariableLibIsHmac (GetVariableNamePtr (Variable, AuthFormat)) == FALSE))
+ {
+ FoundAdded = FALSE;
+ AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
+ while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABLE_STORE_HEADER *)ValidBuffer), AuthFormat)) {
+ NextAddedVariable = GetNextVariablePtr (AddedVariable, AuthFormat);
+ NameSize = NameSizeOfVariable (AddedVariable, AuthFormat);
+ if (CompareGuid (
+ GetVendorGuidPtr (AddedVariable, AuthFormat),
+ GetVendorGuidPtr (Variable, AuthFormat)
+ ) && (NameSize == NameSizeOfVariable (Variable, AuthFormat)))
+ {
+ Point0 = (VOID *)GetVariableNamePtr (AddedVariable, AuthFormat);
+ Point1 = (VOID *)GetVariableNamePtr (Variable, AuthFormat);
+ if (CompareMem (Point0, Point1, NameSize) == 0) {
+ FoundAdded = TRUE;
+ break;
+ }
+ }
+
+ AddedVariable = NextAddedVariable;
+ }
+
+ if (!FoundAdded) {
+ //
+ // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
+ //
+ VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+ CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
+ ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
+ if (!IsVolatile) {
+ (VOID)ProtectedVariableLibRefresh (
+ (VARIABLE_HEADER *)CurrPtr,
+ VariableSize,
+ (UINTN)CurrPtr - (UINTN)ValidBuffer,
+ FALSE
+ );
+
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+ == EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+ {
+ HwErrVariableTotalSize += VariableSize;
+ } else {
+ CommonVariableTotalSize += VariableSize;
+ if (IsUserVariable (Variable)) {
+ CommonUserVariableTotalSize += VariableSize;
+ }
+ }
+ }
+
+ CurrPtr += VariableSize;
+ }
+ }
+
+ Variable = NextVariable;
+ }
+
+ //
+ // Install the new variable if it is not NULL.
+ //
+ if (NewVariable != NULL) {
+ if (((UINTN)CurrPtr - (UINTN)ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {
+ //
+ // No enough space to store the new variable.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ if (!IsVolatile) {
+ if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ HwErrVariableTotalSize += NewVariableSize;
+ } else if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ CommonVariableTotalSize += NewVariableSize;
+ if (IsUserVariable (NewVariable)) {
+ CommonUserVariableTotalSize += NewVariableSize;
+ }
+ }
+
+ if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||
+ (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace) ||
+ (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace))
+ {
+ //
+ // No enough space to store the new variable by NV or NV+HR attribute.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+
+ CopyMem (CurrPtr, (UINT8 *)NewVariable, NewVariableSize);
+ ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
+ if (UpdatingVariable != NULL) {
+ UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer)));
+ UpdatingPtrTrack->InDeletedTransitionPtr = NULL;
+ }
+
+ CurrPtr += NewVariableSize;
+ }
+
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+ //
+ // If volatile/emulated non-volatile variable store, just copy valid buffer.
+ //
+ SetMem ((UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size, 0xff);
+ CopyMem ((UINT8 *)(UINTN)VariableBase, ValidBuffer, (UINTN)CurrPtr - (UINTN)ValidBuffer);
+ *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
+ if (!IsVolatile) {
+ //
+ // Emulated non-volatile variable mode.
+ //
+ mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
+ mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
+ mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
+ }
+
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // If non-volatile variable store, perform FTW here.
+ //
+ Status = FtwVariableSpace (
+ VariableBase,
+ (VARIABLE_STORE_HEADER *)ValidBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
+ mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
+ mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
+ mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
+ } else {
+ mVariableModuleGlobal->HwErrVariableTotalSize = 0;
+ mVariableModuleGlobal->CommonVariableTotalSize = 0;
+ mVariableModuleGlobal->CommonUserVariableTotalSize = 0;
+ Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);
+ while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase), AuthFormat)) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
+ } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
+ if (IsUserVariable (Variable)) {
+ mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;
+ }
+ }
+
+ Variable = NextVariable;
+ }
+
+ *LastVariableOffset = (UINTN)Variable - (UINTN)VariableBase;
+ }
+ }
+
+Done:
+ DoneStatus = EFI_SUCCESS;
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+ DoneStatus = SynchronizeRuntimeVariableCache (
+ &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache,
+ 0,
+ VariableStoreHeader->Size
+ );
+ ASSERT_EFI_ERROR (DoneStatus);
+ FreePool (ValidBuffer);
+ } else {
+ //
+ // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
+ //
+ CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size);
+ DoneStatus = SynchronizeRuntimeVariableCache (
+ &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,
+ 0,
+ VariableStoreHeader->Size
+ );
+ ASSERT_EFI_ERROR (DoneStatus);
+ }
+
+ if (!EFI_ERROR (Status) && EFI_ERROR (DoneStatus)) {
+ Status = DoneStatus;
+ }
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
index 6c1a3440ac8c..6e86099eb72b 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
@@ -16,7 +16,7 @@
VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,
integer overflow. It should also check attribute to avoid authentication bypass.
-Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>
Copyright (c) Microsoft Corporation.<BR>
Copyright (c) 2022, ARM Limited. All rights reserved.<BR>
@@ -30,7 +30,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include "VariableParsing.h"
#include "VariableRuntimeCache.h"
-VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
+VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal = NULL;
///
/// Define a memory cache that improves the search performance for a variable.
@@ -458,7 +458,7 @@ CalculateCommonUserVariableTotalSize (
//
if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {
Variable = GetStartPointer (mNvVariableCache);
- while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
+ while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache), mVariableModuleGlobal->VariableGlobal.AuthFormat)) {
NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);
VariableSize = (UINTN)NextVariable - (UINTN)Variable;
if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
@@ -497,330 +497,6 @@ InitializeVariableQuota (
CalculateCommonUserVariableTotalSize ();
}
-/**
-
- Variable store garbage collection and reclaim operation.
-
- @param[in] VariableBase Base address of variable store.
- @param[out] LastVariableOffset Offset of last variable.
- @param[in] IsVolatile The variable store is volatile or not;
- if it is non-volatile, need FTW.
- @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
- @param[in] NewVariable Pointer to new variable.
- @param[in] NewVariableSize New variable size.
-
- @return EFI_SUCCESS Reclaim operation has finished successfully.
- @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
- @return Others Unexpect error happened during reclaim operation.
-
-**/
-EFI_STATUS
-Reclaim (
- IN EFI_PHYSICAL_ADDRESS VariableBase,
- OUT UINTN *LastVariableOffset,
- IN BOOLEAN IsVolatile,
- IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
- IN VARIABLE_HEADER *NewVariable,
- IN UINTN NewVariableSize
- )
-{
- VARIABLE_HEADER *Variable;
- VARIABLE_HEADER *AddedVariable;
- VARIABLE_HEADER *NextVariable;
- VARIABLE_HEADER *NextAddedVariable;
- VARIABLE_STORE_HEADER *VariableStoreHeader;
- UINT8 *ValidBuffer;
- UINTN MaximumBufferSize;
- UINTN VariableSize;
- UINTN NameSize;
- UINT8 *CurrPtr;
- VOID *Point0;
- VOID *Point1;
- BOOLEAN FoundAdded;
- EFI_STATUS Status;
- EFI_STATUS DoneStatus;
- UINTN CommonVariableTotalSize;
- UINTN CommonUserVariableTotalSize;
- UINTN HwErrVariableTotalSize;
- VARIABLE_HEADER *UpdatingVariable;
- VARIABLE_HEADER *UpdatingInDeletedTransition;
- BOOLEAN AuthFormat;
-
- AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
- UpdatingVariable = NULL;
- UpdatingInDeletedTransition = NULL;
- if (UpdatingPtrTrack != NULL) {
- UpdatingVariable = UpdatingPtrTrack->CurrPtr;
- UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;
- }
-
- VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)VariableBase);
-
- CommonVariableTotalSize = 0;
- CommonUserVariableTotalSize = 0;
- HwErrVariableTotalSize = 0;
-
- if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
- //
- // Start Pointers for the variable.
- //
- Variable = GetStartPointer (VariableStoreHeader);
- MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
-
- while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
- NextVariable = GetNextVariablePtr (Variable, AuthFormat);
- if (((Variable->State == VAR_ADDED) || (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) &&
- (Variable != UpdatingVariable) &&
- (Variable != UpdatingInDeletedTransition)
- )
- {
- VariableSize = (UINTN)NextVariable - (UINTN)Variable;
- MaximumBufferSize += VariableSize;
- }
-
- Variable = NextVariable;
- }
-
- if (NewVariable != NULL) {
- //
- // Add the new variable size.
- //
- MaximumBufferSize += NewVariableSize;
- }
-
- //
- // Reserve the 1 Bytes with Oxff to identify the
- // end of the variable buffer.
- //
- MaximumBufferSize += 1;
- ValidBuffer = AllocatePool (MaximumBufferSize);
- if (ValidBuffer == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- } else {
- //
- // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
- // as the buffer to reduce SMRAM consumption for SMM variable driver.
- //
- MaximumBufferSize = mNvVariableCache->Size;
- ValidBuffer = (UINT8 *)mNvVariableCache;
- }
-
- SetMem (ValidBuffer, MaximumBufferSize, 0xff);
-
- //
- // Copy variable store header.
- //
- CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
- CurrPtr = (UINT8 *)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
-
- //
- // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
- //
- Variable = GetStartPointer (VariableStoreHeader);
- while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
- NextVariable = GetNextVariablePtr (Variable, AuthFormat);
- if ((Variable != UpdatingVariable) && (Variable->State == VAR_ADDED)) {
- VariableSize = (UINTN)NextVariable - (UINTN)Variable;
- CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
- CurrPtr += VariableSize;
- if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
- HwErrVariableTotalSize += VariableSize;
- } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
- CommonVariableTotalSize += VariableSize;
- if (IsUserVariable (Variable)) {
- CommonUserVariableTotalSize += VariableSize;
- }
- }
- }
-
- Variable = NextVariable;
- }
-
- //
- // Reinstall all in delete transition variables.
- //
- Variable = GetStartPointer (VariableStoreHeader);
- while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
- NextVariable = GetNextVariablePtr (Variable, AuthFormat);
- if ((Variable != UpdatingVariable) && (Variable != UpdatingInDeletedTransition) && (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
- //
- // Buffer has cached all ADDED variable.
- // Per IN_DELETED variable, we have to guarantee that
- // no ADDED one in previous buffer.
- //
-
- FoundAdded = FALSE;
- AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
- while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABLE_STORE_HEADER *)ValidBuffer))) {
- NextAddedVariable = GetNextVariablePtr (AddedVariable, AuthFormat);
- NameSize = NameSizeOfVariable (AddedVariable, AuthFormat);
- if (CompareGuid (
- GetVendorGuidPtr (AddedVariable, AuthFormat),
- GetVendorGuidPtr (Variable, AuthFormat)
- ) && (NameSize == NameSizeOfVariable (Variable, AuthFormat)))
- {
- Point0 = (VOID *)GetVariableNamePtr (AddedVariable, AuthFormat);
- Point1 = (VOID *)GetVariableNamePtr (Variable, AuthFormat);
- if (CompareMem (Point0, Point1, NameSize) == 0) {
- FoundAdded = TRUE;
- break;
- }
- }
-
- AddedVariable = NextAddedVariable;
- }
-
- if (!FoundAdded) {
- //
- // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
- //
- VariableSize = (UINTN)NextVariable - (UINTN)Variable;
- CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
- ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
- CurrPtr += VariableSize;
- if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
- HwErrVariableTotalSize += VariableSize;
- } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
- CommonVariableTotalSize += VariableSize;
- if (IsUserVariable (Variable)) {
- CommonUserVariableTotalSize += VariableSize;
- }
- }
- }
- }
-
- Variable = NextVariable;
- }
-
- //
- // Install the new variable if it is not NULL.
- //
- if (NewVariable != NULL) {
- if (((UINTN)CurrPtr - (UINTN)ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {
- //
- // No enough space to store the new variable.
- //
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- if (!IsVolatile) {
- if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
- HwErrVariableTotalSize += NewVariableSize;
- } else if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
- CommonVariableTotalSize += NewVariableSize;
- if (IsUserVariable (NewVariable)) {
- CommonUserVariableTotalSize += NewVariableSize;
- }
- }
-
- if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||
- (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace) ||
- (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace))
- {
- //
- // No enough space to store the new variable by NV or NV+HR attribute.
- //
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- }
-
- CopyMem (CurrPtr, (UINT8 *)NewVariable, NewVariableSize);
- ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
- if (UpdatingVariable != NULL) {
- UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer)));
- UpdatingPtrTrack->InDeletedTransitionPtr = NULL;
- }
-
- CurrPtr += NewVariableSize;
- }
-
- if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
- //
- // If volatile/emulated non-volatile variable store, just copy valid buffer.
- //
- SetMem ((UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size, 0xff);
- CopyMem ((UINT8 *)(UINTN)VariableBase, ValidBuffer, (UINTN)CurrPtr - (UINTN)ValidBuffer);
- *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
- if (!IsVolatile) {
- //
- // Emulated non-volatile variable mode.
- //
- mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
- mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
- mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
- }
-
- Status = EFI_SUCCESS;
- } else {
- //
- // If non-volatile variable store, perform FTW here.
- //
- Status = FtwVariableSpace (
- VariableBase,
- (VARIABLE_STORE_HEADER *)ValidBuffer
- );
- if (!EFI_ERROR (Status)) {
- *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
- mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
- mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
- mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
- } else {
- mVariableModuleGlobal->HwErrVariableTotalSize = 0;
- mVariableModuleGlobal->CommonVariableTotalSize = 0;
- mVariableModuleGlobal->CommonUserVariableTotalSize = 0;
- Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);
- while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase))) {
- NextVariable = GetNextVariablePtr (Variable, AuthFormat);
- VariableSize = (UINTN)NextVariable - (UINTN)Variable;
- if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
- mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
- } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
- mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
- if (IsUserVariable (Variable)) {
- mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;
- }
- }
-
- Variable = NextVariable;
- }
-
- *LastVariableOffset = (UINTN)Variable - (UINTN)VariableBase;
- }
- }
-
-Done:
- DoneStatus = EFI_SUCCESS;
- if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
- DoneStatus = SynchronizeRuntimeVariableCache (
- &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache,
- 0,
- VariableStoreHeader->Size
- );
- ASSERT_EFI_ERROR (DoneStatus);
- FreePool (ValidBuffer);
- } else {
- //
- // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
- //
- CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size);
- DoneStatus = SynchronizeRuntimeVariableCache (
- &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,
- 0,
- VariableStoreHeader->Size
- );
- ASSERT_EFI_ERROR (DoneStatus);
- }
-
- if (!EFI_ERROR (Status) && EFI_ERROR (DoneStatus)) {
- Status = DoneStatus;
- }
-
- return Status;
-}
-
/**
Finds variable in storage blocks of volatile and non-volatile storage areas.
@@ -1657,9 +1333,665 @@ AutoUpdateLangVariable (
}
/**
- Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
- index of associated public key is needed.
+ Check if there's enough free space in storage to write the new variable.
+ @param[in] NewVariable Pointer to buffer of new variable.
+ @param[in] VariableSize Size of new variable.
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] VolatileFlag Volatile/non-volatile variable indicator.
+
+ @retval EFI_SUCCESS Enough free space on variable storage.
+ @retval EFI_BUFFER_TOO_SMALL There's not enough continuous free space.
+ @retval EFI_OUT_OF_RESOURCES There's not enough free space in total.
+**/
+EFI_STATUS
+CheckVariableStoreSpace (
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN VariableSize,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN BOOLEAN VolatileFlag
+ )
+{
+ BOOLEAN IsCommonVariable;
+ BOOLEAN IsCommonUserVariable;
+ UINTN CommonVariableTotalSize;
+ UINTN CommonUserVariableTotalSize;
+ UINTN HwErrVariableTotalSize;
+ VARIABLE_STORE_HEADER *VarStore;
+
+ if ((NewVariable == NULL) || (VariableSize == 0)) {
+ return EFI_SUCCESS;
+ }
+
+ if (VolatileFlag) {
+ VarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+ mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+ if ((UINT32)(VariableSize + mVariableModuleGlobal->VolatileLastVariableOffset)
+ > VarStore->Size)
+ {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ } else {
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {
+ IsCommonVariable = TRUE;
+ IsCommonUserVariable = IsUserVariable (NewVariable);
+ } else {
+ IsCommonVariable = FALSE;
+ IsCommonUserVariable = FALSE;
+ }
+
+ CommonVariableTotalSize = mVariableModuleGlobal->CommonVariableTotalSize + VariableSize;
+ CommonUserVariableTotalSize = mVariableModuleGlobal->CommonUserVariableTotalSize + VariableSize;
+ HwErrVariableTotalSize = mVariableModuleGlobal->HwErrVariableTotalSize + VariableSize;
+
+ if ( (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) &&
+ (HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)))
+ || (IsCommonVariable && (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace))
+ || (IsCommonVariable &&
+ AtRuntime () &&
+ (CommonVariableTotalSize > mVariableModuleGlobal->CommonRuntimeVariableSpace))
+ || (IsCommonUserVariable &&
+ (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace)))
+ {
+ if (AtRuntime ()) {
+ if (IsCommonUserVariable &&
+ ((VariableSize + mVariableModuleGlobal->CommonUserVariableTotalSize)
+ > mVariableModuleGlobal->CommonMaxUserVariableSpace))
+ {
+ RecordVarErrorFlag (
+ VAR_ERROR_FLAG_USER_ERROR,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ VariableSize
+ );
+ }
+
+ if (IsCommonVariable &&
+ ((VariableSize + mVariableModuleGlobal->CommonVariableTotalSize)
+ > mVariableModuleGlobal->CommonRuntimeVariableSpace))
+ {
+ RecordVarErrorFlag (
+ VAR_ERROR_FLAG_SYSTEM_ERROR,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ VariableSize
+ );
+ }
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Fill specific data of auth-variable in buffer.
+
+ @param[in,out] NewVariable Pointer to buffer of new variable.
+ @param[in] OldVariable Pointer to buffer of old copy of the variable.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in] TimeStamp Value of associated TimeStamp.
+
+**/
+VOID
+SetVariableAuthData (
+ IN OUT AUTHENTICATED_VARIABLE_HEADER *NewVariable,
+ IN AUTHENTICATED_VARIABLE_HEADER *OldVariable,
+ IN UINT32 Attributes,
+ IN UINT32 KeyIndex,
+ IN UINT64 MonotonicCount,
+ IN EFI_TIME *TimeStamp
+ )
+{
+ NewVariable->PubKeyIndex = KeyIndex;
+ NewVariable->MonotonicCount = MonotonicCount;
+
+ if ((TimeStamp != NULL) &&
+ ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0))
+ {
+ //
+ // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
+ // when the new TimeStamp value is later than the current timestamp associated
+ // with the variable, we need associate the new timestamp with the updated value.
+ //
+ if (((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) &&
+ (OldVariable != NULL) &&
+ !VariableCompareTimeStampInternal (&OldVariable->TimeStamp, TimeStamp))
+ {
+ TimeStamp = &OldVariable->TimeStamp;
+ }
+
+ CopyMem (&NewVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
+ } else {
+ ZeroMem (&NewVariable->TimeStamp, sizeof (EFI_TIME));
+ }
+}
+
+/**
+ Fill the variable data buffer according to variable format on storage.
+
+ @param[in,out] NewVariable Pointer to buffer of new variable.
+ @param[in] OldVariable Pointer to buffer of old copy of the variable.
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Variable data.
+ @param[in] DataSize Size of data. 0 means delete.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in] TimeStamp Value of associated TimeStamp.
+
+ @retval Size of the new variable.
+
+**/
+UINTN
+SetVariableData (
+ IN OUT VARIABLE_HEADER *NewVariable,
+ IN VARIABLE_HEADER *OldVariable,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes,
+ IN UINT32 KeyIndex,
+ IN UINT64 MonotonicCount,
+ IN EFI_TIME *TimeStamp
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AuthFormat;
+ UINT8 *DataPtr;
+ UINTN NameSize;
+ UINTN OldDataSize;
+
+ AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ if (AuthFormat) {
+ SetVariableAuthData (
+ (AUTHENTICATED_VARIABLE_HEADER *)NewVariable,
+ (AUTHENTICATED_VARIABLE_HEADER *)OldVariable,
+ Attributes,
+ KeyIndex,
+ MonotonicCount,
+ TimeStamp
+ );
+ }
+
+ NewVariable->StartId = VARIABLE_DATA;
+ NewVariable->State = VAR_ADDED;
+ NewVariable->Reserved = 0;
+ NewVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);
+
+ CopyMem (
+ GetVendorGuidPtr (NewVariable, AuthFormat),
+ VendorGuid,
+ sizeof (EFI_GUID)
+ );
+
+ NameSize = StrSize (VariableName);
+ SetNameSizeOfVariable (NewVariable, NameSize, AuthFormat);
+ CopyMem (
+ (UINT8 *)GetVariableNamePtr (NewVariable, AuthFormat),
+ VariableName,
+ NameSize
+ );
+
+ //
+ // Set data size first otherwise we can't get correct data pointer in the
+ // buffer of new variable.
+ //
+ SetDataSizeOfVariable (NewVariable, DataSize, AuthFormat);
+ DataPtr = GetVariableDataPtr (NewVariable, AuthFormat);
+ if (((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) &&
+ (OldVariable != NULL) &&
+ ((OldVariable->State == VAR_ADDED) ||
+ (OldVariable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))))
+ {
+ //
+ // Get old data, which might be encrypted.
+ //
+ OldDataSize = mVariableModuleGlobal->ScratchBufferSize
+ - ((UINTN)DataPtr - (UINTN)NewVariable);
+ Status = ProtectedVariableLibGetByBuffer (
+ OldVariable,
+ DataPtr,
+ (UINT32 *)&OldDataSize,
+ AuthFormat
+ );
+ if (Status == EFI_UNSUPPORTED) {
+ OldDataSize = DataSizeOfVariable (OldVariable, AuthFormat);
+ CopyMem (DataPtr, GetVariableDataPtr (OldVariable, AuthFormat), OldDataSize);
+ } else if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return 0;
+ }
+
+ DataPtr += OldDataSize;
+ //
+ // Update data size.
+ //
+ SetDataSizeOfVariable (NewVariable, DataSize + OldDataSize, AuthFormat);
+ }
+
+ CopyMem (DataPtr, Data, DataSize);
+
+ //
+ // The actual size of the variable stored in storage should include padding.
+ //
+ return ((UINTN)GetNextVariablePtr (NewVariable, AuthFormat) - (UINTN)NewVariable);
+}
+
+/**
+ Update state of given variable as well as its cached copy.
+
+ @param[in,out] Variable Pointer to the buffer of the variable.
+ @param[in,out] CacheVariable Cache copy of the variable.
+ @param[in] NewState New state value.
+ @param[in] Volatile Volatile/non-volatile variable indicator.
+
+ @retval EFI_SUCCESS Variable state was updated successfully.
+ @retval Others Failed to update the variable state.
+
+**/
+EFI_STATUS
+UpdateVariableState (
+ IN OUT VARIABLE_HEADER *Variable,
+ IN OUT VARIABLE_HEADER *CacheVariable,
+ IN UINT8 NewState,
+ IN BOOLEAN Volatile
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ Volatile,
+ FALSE,
+ mVariableModuleGlobal->FvbInstance,
+ (UINTN)&Variable->State,
+ sizeof (NewState),
+ &NewState
+ );
+ if (!EFI_ERROR (Status) && (CacheVariable != NULL)) {
+ CacheVariable->State = NewState;
+ }
+
+ return Status;
+}
+
+/**
+ Flush variable data to variable storage.
+
+ @param[in] VarStoreBase Base address of variable storage.
+ @param[in,out] Offset Offset to write the variable from.
+ Offset from where next variable can be written.
+ @param[in,out] NewVariable Pointer to the buffer of new variable.
+ @param[in] VariableSize Size of new variable.
+ @param[in] Volatile Volatile/non-volatile variable indicator.
+ @param[in] AuthFormat Auth-variable indicator.
+
+ @retval EFI_SUCCESS Variable(s) were written successfully.
+ @retval Others Failed to write the variable data.
+
+**/
+EFI_STATUS
+WriteVariable (
+ IN EFI_PHYSICAL_ADDRESS VarStoreBase,
+ IN OUT UINTN *Offset,
+ IN OUT VARIABLE_HEADER **NewVariable,
+ IN UINT32 VariableSize,
+ IN BOOLEAN Volatile,
+ IN BOOLEAN AuthFormat
+ )
+{
+ EFI_STATUS Status;
+
+ struct {
+ UINTN Offset;
+ UINT8 *Buffer;
+ UINT32 Size;
+ UINT8 State;
+ } WriteSteps[4];
+ UINTN Index;
+ UINTN Steps;
+ VARIABLE_HEADER *Variable;
+
+ Variable = *NewVariable;
+ if (Volatile) {
+ //
+ // For non-volatile variable, one step only :
+ //
+ WriteSteps[0].Offset = *Offset;
+ WriteSteps[0].Buffer = (UINT8 *)Variable;
+ WriteSteps[0].Size = VariableSize;
+
+ Steps = 1;
+ } else {
+ //
+ // Four steps for non-volatile variable:
+ //
+ // 1. Write variable header
+ // 2. Set variable state to header valid
+ // 3. Write variable name and data
+ // 4. Set variable state to valid
+ //
+ Variable->State = 0xff;
+ WriteSteps[0].Offset = *Offset;
+ WriteSteps[0].Buffer = (UINT8 *)Variable;
+ WriteSteps[0].Size = (UINT32)GetVariableHeaderSize (AuthFormat);
+
+ WriteSteps[1].State = VAR_HEADER_VALID_ONLY;
+ WriteSteps[1].Offset = *Offset + OFFSET_OF (VARIABLE_HEADER, State);
+ WriteSteps[1].Buffer = &WriteSteps[1].State;
+ WriteSteps[1].Size = sizeof (Variable->State);
+
+ WriteSteps[2].Offset = *Offset + GetVariableHeaderSize (AuthFormat);
+ WriteSteps[2].Buffer = (UINT8 *)Variable + GetVariableHeaderSize (AuthFormat);
+ WriteSteps[2].Size = VariableSize - (UINT32)GetVariableHeaderSize (AuthFormat);
+
+ WriteSteps[3].State = VAR_ADDED;
+ WriteSteps[3].Offset = *Offset + OFFSET_OF (VARIABLE_HEADER, State);
+ WriteSteps[3].Buffer = &WriteSteps[3].State;
+ WriteSteps[3].Size = sizeof (Variable->State);
+
+ Steps = ARRAY_SIZE (WriteSteps);
+ }
+
+ for (Index = 0; Index < Steps; ++Index) {
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ Volatile,
+ TRUE,
+ mVariableModuleGlobal->FvbInstance,
+ WriteSteps[Index].Offset,
+ WriteSteps[Index].Size,
+ WriteSteps[Index].Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ }
+
+ Variable->State = VAR_ADDED;
+ if (!Volatile) {
+ CopyMem ((UINT8 *)mNvVariableCache + *Offset, Variable, VariableSize);
+ }
+
+ *NewVariable = (VARIABLE_HEADER *)((UINTN)VarStoreBase + *Offset);
+ *Offset += HEADER_ALIGN (VariableSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Rebase the given variable pointer(s) to the equivalent one in given variable
+ storage via VarStore.
+
+ @param[in] InVarTrackPtr Pointer to current variable in cache.
+ @param[out] OutVarTrackPtr Pointer to rebased variable against VarStore.
+ @param[in] VarStore Start of variable storage to rebase against.
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] ByOffset If TRUE, don't do variable search in VarStore.
+
+ @retval EFI_SUCCESS Variable(s) were deleted successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameters passed.
+ @retval EFI_NOT_FOUND Given variable (VariableName & VendorGuid) was
+ not found in VarStore, if ByOffset is FALSE.
+
+**/
+EFI_STATUS
+RebaseVariablePtr (
+ IN VARIABLE_POINTER_TRACK *InVarTrackPtr,
+ OUT VARIABLE_POINTER_TRACK *OutVarTrackPtr,
+ IN VARIABLE_STORE_HEADER *VarStore,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN BOOLEAN ByOffset
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AuthFormat;
+ VARIABLE_HEADER *NewStart;
+
+ if ((InVarTrackPtr == NULL) || (OutVarTrackPtr == NULL) || (VarStore == NULL)) {
+ ASSERT (InVarTrackPtr != NULL);
+ ASSERT (OutVarTrackPtr != NULL);
+ ASSERT (VarStore != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ if ( (InVarTrackPtr->CurrPtr == NULL)
+ || (InVarTrackPtr->StartPtr == GetStartPointer (VarStore)))
+ {
+ CopyMem (OutVarTrackPtr, InVarTrackPtr, sizeof (VARIABLE_POINTER_TRACK));
+ return EFI_SUCCESS;
+ }
+
+ NewStart = GetStartPointer (VarStore);
+ if (ByOffset) {
+ OutVarTrackPtr->CurrPtr = (VARIABLE_HEADER *)
+ ((UINTN)NewStart + ((UINTN)InVarTrackPtr->CurrPtr -
+ (UINTN)InVarTrackPtr->StartPtr));
+
+ if (InVarTrackPtr->InDeletedTransitionPtr != NULL) {
+ OutVarTrackPtr->InDeletedTransitionPtr =
+ (VARIABLE_HEADER *)((UINTN)NewStart +
+ ((UINTN)InVarTrackPtr->InDeletedTransitionPtr -
+ (UINTN)InVarTrackPtr->StartPtr));
+ } else {
+ OutVarTrackPtr->InDeletedTransitionPtr = NULL;
+ }
+
+ OutVarTrackPtr->StartPtr = NewStart;
+ OutVarTrackPtr->EndPtr = GetEndPointer (VarStore);
+ } else {
+ OutVarTrackPtr->StartPtr = NewStart;
+ OutVarTrackPtr->EndPtr = GetEndPointer (VarStore);
+
+ Status = FindVariableEx (VariableName, VendorGuid, FALSE, OutVarTrackPtr, AuthFormat);
+ if ((OutVarTrackPtr->CurrPtr == NULL) || EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ if ( (VarStore == mNvVariableCache)
+ || ((UINTN)VarStore == (UINTN)mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))
+ {
+ OutVarTrackPtr->Volatile = FALSE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if the given variable is from HOB.
+
+ @param[in] CacheVariable Pointer to current variable in cache.
+
+ @retval TRUE The variable is from HOB.
+ @retval FALSE The variable is NOT from HOB.
+
+**/
+BOOLEAN
+IsHobVariable (
+ IN VARIABLE_POINTER_TRACK *CacheVariable
+ )
+{
+ VARIABLE_STORE_HEADER *HobVarStore;
+
+ HobVarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+ return (CacheVariable->CurrPtr != NULL &&
+ HobVarStore != NULL &&
+ CacheVariable->StartPtr == GetStartPointer (HobVarStore));
+}
+
+/**
+ Get temporary buffer for a new variable data.
+
+ @retval Pointer to the buffer address.
+
+**/
+VARIABLE_HEADER *
+GetNewVariableBuffer (
+ VOID
+ )
+{
+ VARIABLE_HEADER *NewVariable;
+ VARIABLE_STORE_HEADER *VarStore;
+
+ //
+ // Tricky part: Use scratch data area at the end of volatile variable store
+ // as a temporary storage.
+ //
+ VarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+ mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+ NewVariable = GetEndPointer (VarStore);
+
+ SetMem (NewVariable, mVariableModuleGlobal->ScratchBufferSize, 0xff);
+
+ return NewVariable;
+}
+
+/**
+ Delete old copies of variable completely.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Variable Pointer to current variable on storage.
+ @param[in,out] CacheVariable Pointer to current variable in cache.
+ @param[in] VolatileFlag Auth-variable indicator.
+
+ @retval EFI_SUCCESS Variable(s) were deleted successfully.
+ @retval Others Failed to update variable state.
+
+**/
+EFI_STATUS
+DeleteVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VARIABLE_POINTER_TRACK *Variable,
+ IN OUT VARIABLE_POINTER_TRACK *CacheVariable,
+ IN BOOLEAN VolatileFlag
+ )
+{
+ EFI_STATUS Status;
+
+ if (Variable->InDeletedTransitionPtr != NULL) {
+ ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
+ //
+ // Both ADDED and IN_DELETED_TRANSITION variable are present,
+ // set IN_DELETED_TRANSITION one to DELETED state first.
+ //
+ Status = UpdateVariableState (
+ Variable->InDeletedTransitionPtr,
+ CacheVariable->InDeletedTransitionPtr,
+ CacheVariable->InDeletedTransitionPtr->State & VAR_DELETED,
+ VolatileFlag
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ ASSERT (CacheVariable->CurrPtr != NULL);
+ Status = UpdateVariableState (
+ Variable->CurrPtr,
+ CacheVariable->CurrPtr,
+ CacheVariable->CurrPtr->State & VAR_DELETED,
+ VolatileFlag
+ );
+
+ if (!EFI_ERROR (Status)) {
+ UpdateVariableInfo (
+ VariableName,
+ VendorGuid,
+ Variable->Volatile,
+ FALSE,
+ FALSE,
+ TRUE,
+ FALSE,
+ &gVariableInfo
+ );
+ if (!Variable->Volatile) {
+ FlushHobVariableToFlash (VariableName, VendorGuid);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Check if it's the right time to update a variable.
+
+ @param[in] Attributes Attributes of a variable.
+
+ @retval TRUE It's ready for variable update.
+ @retval FALSE It's NOT ready for variable update.
+
+**/
+BOOLEAN
+ReadyForUpdate (
+ IN UINT32 Attributes
+ )
+{
+ if ((mVariableModuleGlobal->FvbInstance == NULL) &&
+ !mVariableModuleGlobal->VariableGlobal.EmuNvMode)
+ {
+ //
+ // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL
+ // is not installed.
+ //
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ //
+ // Trying to update NV variable prior to the installation of
+ // EFI_VARIABLE_WRITE_ARCH_PROTOCOL
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n",
+ EFI_NOT_AVAILABLE_YET
+ ));
+ return FALSE;
+ } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+ //
+ // Trying to update volatile authenticated variable prior to the
+ // installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL. The authenticated
+ // variable perhaps is not initialized, just return here.
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n",
+ EFI_NOT_AVAILABLE_YET
+ ));
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Check parameters associated with the variable to update.
+
+ @param[in] Variable Pointer to current variable on storage.
+ @param[in] CacheVariable Pointer to current variable in cache.
@param[in] VariableName Name of variable.
@param[in] VendorGuid Guid of variable.
@param[in] Data Variable data.
@@ -1667,9 +1999,130 @@ AutoUpdateLangVariable (
@param[in] Attributes Attributes of the variable.
@param[in] KeyIndex Index of associated public key.
@param[in] MonotonicCount Value of associated monotonic count.
- @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
@param[in] TimeStamp Value of associated TimeStamp.
+ @retval EFI_SUCCESS The variable is ok to be updated.
+ @retval EFI_ALREADY_STARTED No need to update the variable.
+ @retval EFI_WRITE_PROTECTED The variable cannot be updated.
+ @retval EFI_INVALID_PARAMETER The variable attributes are not valid.
+ @retval EFI_NOT_FOUND Trying to delete non-existing variable.
+
+**/
+EFI_STATUS
+ValidateVariableParameters (
+ IN VARIABLE_POINTER_TRACK *Variable,
+ IN VARIABLE_POINTER_TRACK *CacheVariable,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes,
+ IN UINT32 KeyIndex,
+ IN UINT64 MonotonicCount,
+ IN EFI_TIME *TimeStamp
+ )
+{
+ BOOLEAN AuthFlag;
+
+ AuthFlag = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (Variable->CurrPtr != NULL) {
+ //
+ // Update/Delete existing variable.
+ //
+ if (AtRuntime ()) {
+ //
+ // If AtRuntime and the variable is Volatile and Runtime Access,
+ // the volatile is ReadOnly, and SetVariable should be aborted and
+ // return EFI_WRITE_PROTECTED.
+ //
+ if (Variable->Volatile) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ //
+ // Only variable that have NV attributes can be updated/deleted in Runtime.
+ //
+ if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Only variable that have RT attributes can be updated/deleted in Runtime.
+ //
+ if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Variable content unchanged and no need to update timestamp, just return.
+ //
+ if ( ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)
+ && (TimeStamp == NULL)
+ && (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFlag) == DataSize)
+ && (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr, AuthFlag), DataSize) == 0))
+ {
+ UpdateVariableInfo (
+ VariableName,
+ VendorGuid,
+ Variable->Volatile,
+ FALSE,
+ TRUE,
+ FALSE,
+ FALSE,
+ &gVariableInfo
+ );
+ return EFI_ALREADY_STARTED;
+ }
+ } else {
+ //
+ // Create a new variable.
+ //
+
+ //
+ // Make sure we are trying to create a new variable. You cannot delete a new
+ // variable.
+ //
+ if ((DataSize == 0) ||
+ ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS|EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0))
+ {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Only variable have NV|RT attribute can be created in Runtime.
+ //
+ if ( AtRuntime ()
+ && ( ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)
+ || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
+ index of associated public key is needed.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Variable data.
+ @param[in] DataSize Size of data. 0 means delete.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in,out] CacheVariable The variable information which is used
+ to keep track of variable usage.
+ @param[in] TimeStamp Value of associated TimeStamp.
+
@retval EFI_SUCCESS The update operation is success.
@retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
@@ -1687,710 +2140,381 @@ UpdateVariable (
IN EFI_TIME *TimeStamp OPTIONAL
)
{
- EFI_STATUS Status;
- VARIABLE_HEADER *NextVariable;
- UINTN ScratchSize;
- UINTN MaxDataSize;
- UINTN VarNameOffset;
- UINTN VarDataOffset;
- UINTN VarNameSize;
- UINTN VarSize;
- BOOLEAN Volatile;
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
- UINT8 State;
- VARIABLE_POINTER_TRACK *Variable;
- VARIABLE_POINTER_TRACK NvVariable;
- VARIABLE_STORE_HEADER *VariableStoreHeader;
- VARIABLE_RUNTIME_CACHE *VolatileCacheInstance;
- UINT8 *BufferForMerge;
- UINTN MergedBufSize;
- BOOLEAN DataReady;
- UINTN DataOffset;
- BOOLEAN IsCommonVariable;
- BOOLEAN IsCommonUserVariable;
- AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
- BOOLEAN AuthFormat;
+ EFI_STATUS Status;
+ VARIABLE_GLOBAL *VarGlobal;
+ VARIABLE_HEADER *NewVariable;
+ VARIABLE_HEADER *NextVariable;
+ VARIABLE_HEADER *UpdatingVariable;
+ UINTN VarSize;
+ UINTN UpdateSize;
+ UINTN Offset;
+ VARIABLE_POINTER_TRACK *Variable;
+ VARIABLE_POINTER_TRACK NvVariable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_RUNTIME_CACHE *VolatileCacheInstance;
+ BOOLEAN IsCommonVariable;
+ BOOLEAN IsCommonUserVariable;
+ BOOLEAN DeleteFlag;
+ BOOLEAN VolatileFlag;
+ BOOLEAN HobVarOnlyFlag;
+ EFI_PHYSICAL_ADDRESS VarStoreBase;
+ UINTN *LastVariableOffset;
- if ((mVariableModuleGlobal->FvbInstance == NULL) && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
- //
- // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
- //
- if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
- //
- // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
- //
- DEBUG ((DEBUG_ERROR, "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));
- return EFI_NOT_AVAILABLE_YET;
- } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
- //
- // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
- // The authenticated variable perhaps is not initialized, just return here.
- //
- DEBUG ((DEBUG_ERROR, "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));
- return EFI_NOT_AVAILABLE_YET;
- }
+ if (!ReadyForUpdate (Attributes)) {
+ return EFI_NOT_AVAILABLE_YET;
}
- AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+ VarGlobal = &mVariableModuleGlobal->VariableGlobal;
+
+ if ( (((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0))
+ || (Attributes == 0)
+ || (AtRuntime () && ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS
+ |EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)))
+ {
+ DeleteFlag = TRUE;
+ } else {
+ DeleteFlag = FALSE;
+ }
+
+ if ( ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)
+ || ((CacheVariable->CurrPtr != NULL) &&
+ ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)))
+ {
+ VolatileFlag = FALSE;
+ } else {
+ VolatileFlag = TRUE;
+ }
//
// Check if CacheVariable points to the variable in variable HOB.
// If yes, let CacheVariable points to the variable in NV variable cache.
//
- if ((CacheVariable->CurrPtr != NULL) &&
- (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) &&
- (CacheVariable->StartPtr == GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase))
- )
- {
- CacheVariable->StartPtr = GetStartPointer (mNvVariableCache);
- CacheVariable->EndPtr = GetEndPointer (mNvVariableCache);
- CacheVariable->Volatile = FALSE;
- Status = FindVariableEx (VariableName, VendorGuid, FALSE, CacheVariable, AuthFormat);
+ HobVarOnlyFlag = FALSE;
+ if (IsHobVariable (CacheVariable)) {
+ Status = RebaseVariablePtr (
+ CacheVariable,
+ CacheVariable,
+ mNvVariableCache,
+ VariableName,
+ VendorGuid,
+ FALSE
+ );
if ((CacheVariable->CurrPtr == NULL) || EFI_ERROR (Status)) {
//
// There is no matched variable in NV variable cache.
//
- if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
+ if (DeleteFlag) {
//
- // It is to delete variable,
- // go to delete this variable in variable HOB and
- // try to flush other variables from HOB to flash.
+ // Leave the deletion to FlushHobVariableToFlash() before return.
//
- UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, FALSE, TRUE, FALSE, &gVariableInfo);
- FlushHobVariableToFlash (VariableName, VendorGuid);
- return EFI_SUCCESS;
+ HobVarOnlyFlag = TRUE;
+ Status = EFI_SUCCESS;
+ goto Done;
}
}
}
+ //
+ // Determine the physical position of variable store to update, due to cache
+ // mechanims of variable service.
+ //
if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {
+ //
+ // - Add new variable (volatile or non-volatile); Or
+ // - Update/delete volatile variable in place.
+ //
Variable = CacheVariable;
} else {
//
- // Update/Delete existing NV variable.
- // CacheVariable points to the variable in the memory copy of Flash area
- // Now let Variable points to the same variable in Flash area.
+ // - Update/Delete existing NV variable.
+ // CacheVariable points to the variable in the memory copy of Flash area.
+ // Now let Variable points to the same variable in Flash area.
//
- VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
- Variable = &NvVariable;
- Variable->StartPtr = GetStartPointer (VariableStoreHeader);
- Variable->EndPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->EndPtr - (UINTN)CacheVariable->StartPtr));
-
- Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));
- if (CacheVariable->InDeletedTransitionPtr != NULL) {
- Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr - (UINTN)CacheVariable->StartPtr));
- } else {
- Variable->InDeletedTransitionPtr = NULL;
- }
-
- Variable->Volatile = FALSE;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)
+ VarGlobal->NonVolatileVariableBase;
+ Variable = &NvVariable;
+ Status = RebaseVariablePtr (
+ CacheVariable,
+ Variable,
+ VariableStoreHeader,
+ VariableName,
+ VendorGuid,
+ TRUE
+ );
+ ASSERT_EFI_ERROR (Status);
}
- Fvb = mVariableModuleGlobal->FvbInstance;
-
//
- // Tricky part: Use scratch data area at the end of volatile variable store
- // as a temporary storage.
+ // Validate variable parameters.
//
- NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
- ScratchSize = mVariableModuleGlobal->ScratchBufferSize;
- SetMem (NextVariable, ScratchSize, 0xff);
- DataReady = FALSE;
-
- if (Variable->CurrPtr != NULL) {
- //
- // Update/Delete existing variable.
- //
- if (AtRuntime ()) {
- //
- // If AtRuntime and the variable is Volatile and Runtime Access,
- // the volatile is ReadOnly, and SetVariable should be aborted and
- // return EFI_WRITE_PROTECTED.
- //
- if (Variable->Volatile) {
- Status = EFI_WRITE_PROTECTED;
- goto Done;
- }
-
- //
- // Only variable that have NV attributes can be updated/deleted in Runtime.
- //
- if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- //
- // Only variable that have RT attributes can be updated/deleted in Runtime.
- //
- if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- }
-
- //
- // Setting a data variable with no access, or zero DataSize attributes
- // causes it to be deleted.
- // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
- // not delete the variable.
- //
- if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {
- if (Variable->InDeletedTransitionPtr != NULL) {
- //
- // Both ADDED and IN_DELETED_TRANSITION variable are present,
- // set IN_DELETED_TRANSITION one to DELETED state first.
- //
- ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
- State = CacheVariable->InDeletedTransitionPtr->State;
- State &= VAR_DELETED;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- Variable->Volatile,
- FALSE,
- Fvb,
- (UINTN)&Variable->InDeletedTransitionPtr->State,
- sizeof (UINT8),
- &State
- );
- if (!EFI_ERROR (Status)) {
- if (!Variable->Volatile) {
- CacheVariable->InDeletedTransitionPtr->State = State;
- }
- } else {
- goto Done;
- }
- }
-
- State = CacheVariable->CurrPtr->State;
- State &= VAR_DELETED;
-
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- Variable->Volatile,
- FALSE,
- Fvb,
- (UINTN)&Variable->CurrPtr->State,
- sizeof (UINT8),
- &State
- );
- if (!EFI_ERROR (Status)) {
- UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE, &gVariableInfo);
- if (!Variable->Volatile) {
- CacheVariable->CurrPtr->State = State;
- FlushHobVariableToFlash (VariableName, VendorGuid);
- }
- }
+ Status = ValidateVariableParameters (
+ Variable,
+ CacheVariable,
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Attributes,
+ KeyIndex,
+ MonotonicCount,
+ TimeStamp
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
- goto Done;
- }
+ //
+ // Add or update a variable. Allocate a buffer to hold it temporarily.
+ //
+ NewVariable = GetNewVariableBuffer ();
+ //
+ // Fill-up variable data first, if necessary.
+ //
+ IsCommonVariable = FALSE;
+ IsCommonUserVariable = FALSE;
+ if (DeleteFlag) {
//
- // If the variable is marked valid, and the same data has been passed in,
- // then return to the caller immediately.
+ // No need to fill up variable buffer when deleting a variable. But the
+ // buffer is still needed if variable protection is employed.
//
- if ((DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) == DataSize) &&
- (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr, AuthFormat), DataSize) == 0) &&
- ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) &&
- (TimeStamp == NULL))
- {
- //
- // Variable content unchanged and no need to update timestamp, just return.
- //
- UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
- Status = EFI_SUCCESS;
- goto Done;
- } else if ((CacheVariable->CurrPtr->State == VAR_ADDED) ||
- (CacheVariable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)))
- {
- //
- // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.
- //
- if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {
- //
- // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
- // From DataOffset of NextVariable is to save the existing variable data.
- //
- DataOffset = GetVariableDataOffset (CacheVariable->CurrPtr, AuthFormat);
- BufferForMerge = (UINT8 *)((UINTN)NextVariable + DataOffset);
- CopyMem (
- BufferForMerge,
- (UINT8 *)((UINTN)CacheVariable->CurrPtr + DataOffset),
- DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat)
- );
-
- //
- // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default MaxDataSize.
- //
- if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
- MaxDataSize = mVariableModuleGlobal->MaxAuthVariableSize - DataOffset;
- } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
- MaxDataSize = mVariableModuleGlobal->MaxVariableSize - DataOffset;
- } else {
- MaxDataSize = mVariableModuleGlobal->MaxVolatileVariableSize - DataOffset;
- }
-
- //
- // Append the new data to the end of existing data.
- // Max Harware error record variable data size is different from common/auth variable.
- //
- if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
- MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - DataOffset;
- }
-
- if (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) + DataSize > MaxDataSize) {
- //
- // Existing data size + new data size exceed maximum variable size limitation.
- //
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- CopyMem (
- (UINT8 *)(
- (UINTN)BufferForMerge + DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat)
- ),
- Data,
- DataSize
- );
- MergedBufSize = DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) +
- DataSize;
-
- //
- // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
- //
- Data = BufferForMerge;
- DataSize = MergedBufSize;
- DataReady = TRUE;
- }
-
- //
- // Mark the old variable as in delete transition.
- //
- State = CacheVariable->CurrPtr->State;
- State &= VAR_IN_DELETED_TRANSITION;
-
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- Variable->Volatile,
- FALSE,
- Fvb,
- (UINTN)&Variable->CurrPtr->State,
- sizeof (UINT8),
- &State
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if (!Variable->Volatile) {
- CacheVariable->CurrPtr->State = State;
- }
- }
+ VarSize = 0;
} else {
- //
- // Not found existing variable. Create a new variable.
- //
+ VarSize = SetVariableData (
+ NewVariable,
+ CacheVariable->CurrPtr,
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Attributes,
+ KeyIndex,
+ MonotonicCount,
+ TimeStamp
+ );
- if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- //
- // Make sure we are trying to create a new variable.
- // Setting a data variable with zero DataSize or no access attributes means to delete it.
- //
- if ((DataSize == 0) || ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- //
- // Only variable have NV|RT attribute can be created in Runtime.
- //
- if (AtRuntime () &&
- (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)))
- {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- }
-
- //
- // Function part - create a new variable and copy the data.
- // Both update a variable and create a variable will come here.
- //
- NextVariable->StartId = VARIABLE_DATA;
- //
- // NextVariable->State = VAR_ADDED;
- //
- NextVariable->Reserved = 0;
- if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
- AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)NextVariable;
- AuthVariable->PubKeyIndex = KeyIndex;
- AuthVariable->MonotonicCount = MonotonicCount;
- ZeroMem (&AuthVariable->TimeStamp, sizeof (EFI_TIME));
-
- if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
- (TimeStamp != NULL))
- {
- if ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) {
- CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
- } else {
- //
- // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
- // when the new TimeStamp value is later than the current timestamp associated
- // with the variable, we need associate the new timestamp with the updated value.
- //
- if (Variable->CurrPtr != NULL) {
- if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER *)CacheVariable->CurrPtr)->TimeStamp), TimeStamp)) {
- CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
- } else {
- CopyMem (&AuthVariable->TimeStamp, &(((AUTHENTICATED_VARIABLE_HEADER *)CacheVariable->CurrPtr)->TimeStamp), sizeof (EFI_TIME));
- }
- }
- }
- }
- }
-
- //
- // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
- // Attributes bitmask parameter of a GetVariable() call.
- //
- NextVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);
-
- VarNameOffset = GetVariableHeaderSize (AuthFormat);
- VarNameSize = StrSize (VariableName);
- CopyMem (
- (UINT8 *)((UINTN)NextVariable + VarNameOffset),
- VariableName,
- VarNameSize
- );
- VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
-
- //
- // If DataReady is TRUE, it means the variable data has been saved into
- // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
- //
- if (!DataReady) {
- CopyMem (
- (UINT8 *)((UINTN)NextVariable + VarDataOffset),
- Data,
- DataSize
- );
- }
-
- CopyMem (
- GetVendorGuidPtr (NextVariable, AuthFormat),
- VendorGuid,
- sizeof (EFI_GUID)
- );
- //
- // There will be pad bytes after Data, the NextVariable->NameSize and
- // NextVariable->DataSize should not include pad size so that variable
- // service can get actual size in GetVariable.
- //
- SetNameSizeOfVariable (NextVariable, VarNameSize, AuthFormat);
- SetDataSizeOfVariable (NextVariable, DataSize, AuthFormat);
-
- //
- // The actual size of the variable that stores in storage should
- // include pad size.
- //
- VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
- if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
- //
- // Create a nonvolatile variable.
- //
- Volatile = FALSE;
-
- IsCommonVariable = FALSE;
- IsCommonUserVariable = FALSE;
if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {
IsCommonVariable = TRUE;
- IsCommonUserVariable = IsUserVariable (NextVariable);
+ IsCommonUserVariable = IsUserVariable (NewVariable);
}
+ }
- if ( ( ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
- && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))
- || (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace))
- || (IsCommonVariable && AtRuntime () && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace))
- || (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)))
- {
- if (AtRuntime ()) {
- if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
- RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);
- }
-
- if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace)) {
- RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);
- }
-
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- //
- // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
- //
- Status = Reclaim (
- mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
- &mVariableModuleGlobal->NonVolatileLastVariableOffset,
- FALSE,
- Variable,
- NextVariable,
- HEADER_ALIGN (VarSize)
- );
- if (!EFI_ERROR (Status)) {
- //
- // The new variable has been integrated successfully during reclaiming.
- //
- if (Variable->CurrPtr != NULL) {
- CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN)CacheVariable->StartPtr + ((UINTN)Variable->CurrPtr - (UINTN)Variable->StartPtr));
- CacheVariable->InDeletedTransitionPtr = NULL;
- }
-
- UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
- FlushHobVariableToFlash (VariableName, VendorGuid);
- } else {
- if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
- RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);
- }
+ //
+ // We might need to do protection for non-volatile variable before flushing
+ // the data to storage. A null version (meaning no protection) of following
+ // APIs should simply return EFI_SUCCESS or EFI_UNSUPPORTED without any
+ // changes to original data.
+ //
+ if (!VolatileFlag) {
+ Status = ProtectedVariableLibUpdate (
+ Variable->CurrPtr,
+ Variable->InDeletedTransitionPtr,
+ NewVariable,
+ &VarSize
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ return Status;
+ }
- if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace)) {
- RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);
- }
- }
+ Status = EFI_SUCCESS;
+ }
+ //
+ // Mark the old variable as in delete transition first. There's no such need
+ // for deleting a variable, even if variable protection is employed.
+ //
+ if ( !DeleteFlag
+ && (CacheVariable->CurrPtr != NULL)
+ && ( (CacheVariable->CurrPtr->State == VAR_ADDED)
+ || (CacheVariable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))))
+ {
+ Status = UpdateVariableState (
+ Variable->CurrPtr,
+ CacheVariable->CurrPtr,
+ CacheVariable->CurrPtr->State & VAR_IN_DELETED_TRANSITION,
+ Variable->Volatile
+ );
+ if (EFI_ERROR (Status)) {
goto Done;
}
-
- if (!mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
- //
- // Four steps
- // 1. Write variable header
- // 2. Set variable state to header valid
- // 3. Write variable data
- // 4. Set variable state to valid
- //
- //
- // Step 1:
- //
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- FALSE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->NonVolatileLastVariableOffset,
- (UINT32)GetVariableHeaderSize (AuthFormat),
- (UINT8 *)NextVariable
- );
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Step 2:
- //
- NextVariable->State = VAR_HEADER_VALID_ONLY;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- FALSE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),
- sizeof (UINT8),
- &NextVariable->State
- );
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Step 3:
- //
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- FALSE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (AuthFormat),
- (UINT32)(VarSize - GetVariableHeaderSize (AuthFormat)),
- (UINT8 *)NextVariable + GetVariableHeaderSize (AuthFormat)
+ }
+
+ //
+ // Have enough space to store the variable?
+ //
+ Status = CheckVariableStoreSpace (
+ NewVariable,
+ VarSize,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ VolatileFlag
+ );
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ //
+ // Not a chance.
+ //
+ goto Done;
+ }
+
+ //
+ // Maybe not...
+ //
+ VarStoreBase = (VolatileFlag) ? VarGlobal->VolatileVariableBase
+ : VarGlobal->NonVolatileVariableBase;
+ LastVariableOffset = (VolatileFlag)
+ ? &mVariableModuleGlobal->VolatileLastVariableOffset
+ : &mVariableModuleGlobal->NonVolatileLastVariableOffset;
+ if (!EFI_ERROR (Status)) {
+ //
+ // There's enough free space at the tail of variable storage.
+ //
+
+ //
+ // If non-volatile variable is protected, a separate variable (MetaDataHmacVar)
+ // is always updated along with current updating variable. The buffer pointed
+ // by NewVariable must have two variables. They should be written at this
+ // time orderly.
+ //
+ NextVariable = NewVariable;
+ UpdatingVariable = NULL;
+ UpdateSize = 0;
+ while ( !EFI_ERROR (Status)
+ && ((UINTN)NextVariable - (UINTN)NewVariable) < VarSize)
+ {
+ UpdatingVariable = NextVariable;
+ NextVariable = GetNextVariablePtr (UpdatingVariable, VarGlobal->AuthFormat);
+ UpdateSize = (UINTN)NextVariable - (UINTN)UpdatingVariable;
+
+ Status = WriteVariable (
+ VarStoreBase,
+ LastVariableOffset,
+ &UpdatingVariable,
+ (UINT32)UpdateSize,
+ VolatileFlag,
+ VarGlobal->AuthFormat
);
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Step 4:
- //
- NextVariable->State = VAR_ADDED;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- FALSE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),
- sizeof (UINT8),
- &NextVariable->State
- );
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Update the memory copy of Flash region.
- //
- CopyMem ((UINT8 *)mNvVariableCache + mVariableModuleGlobal->NonVolatileLastVariableOffset, (UINT8 *)NextVariable, VarSize);
- } else {
- //
- // Emulated non-volatile variable mode.
- //
- NextVariable->State = VAR_ADDED;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- FALSE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->NonVolatileLastVariableOffset,
- (UINT32)VarSize,
- (UINT8 *)NextVariable
- );
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
}
- mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);
-
+ //
+ // UpdatingVariable must point to the last written variable. Restore it to
+ // the first one so that we can calculate the offset in variable storage.
+ //
+ UpdatingVariable = (VARIABLE_HEADER *)((UINTN)UpdatingVariable + UpdateSize
+ - VarSize);
if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
- mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);
+ mVariableModuleGlobal->HwErrVariableTotalSize += VarSize;
} else {
- mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);
+ mVariableModuleGlobal->CommonVariableTotalSize += VarSize;
if (IsCommonUserVariable) {
- mVariableModuleGlobal->CommonUserVariableTotalSize += HEADER_ALIGN (VarSize);
+ mVariableModuleGlobal->CommonUserVariableTotalSize += VarSize;
}
}
- } else {
- //
- // Create a volatile variable.
- //
- Volatile = TRUE;
- if ((UINT32)(VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >
- ((VARIABLE_STORE_HEADER *)((UINTN)(mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size)
- {
- //
- // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
- //
- Status = Reclaim (
- mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,
- &mVariableModuleGlobal->VolatileLastVariableOffset,
- TRUE,
+ //
+ // Mark the old variable(s) as deleted.
+ //
+ if (!EFI_ERROR (Status) && (Variable->CurrPtr != NULL)) {
+ Status = DeleteVariable (
+ VariableName,
+ VendorGuid,
Variable,
- NextVariable,
- HEADER_ALIGN (VarSize)
+ CacheVariable,
+ VolatileFlag
);
- if (!EFI_ERROR (Status)) {
- //
- // The new variable has been integrated successfully during reclaiming.
- //
- if (Variable->CurrPtr != NULL) {
- CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN)CacheVariable->StartPtr + ((UINTN)Variable->CurrPtr - (UINTN)Variable->StartPtr));
- CacheVariable->InDeletedTransitionPtr = NULL;
- }
-
- UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
- }
-
- goto Done;
}
-
- NextVariable->State = VAR_ADDED;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- TRUE,
- TRUE,
- Fvb,
- mVariableModuleGlobal->VolatileLastVariableOffset,
- (UINT32)VarSize,
- (UINT8 *)NextVariable
- );
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);
- }
-
- //
- // Mark the old variable as deleted.
- //
- if (!EFI_ERROR (Status) && (Variable->CurrPtr != NULL)) {
- if (Variable->InDeletedTransitionPtr != NULL) {
- //
- // Both ADDED and IN_DELETED_TRANSITION old variable are present,
- // set IN_DELETED_TRANSITION one to DELETED state first.
- //
- ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
- State = CacheVariable->InDeletedTransitionPtr->State;
- State &= VAR_DELETED;
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- Variable->Volatile,
- FALSE,
- Fvb,
- (UINTN)&Variable->InDeletedTransitionPtr->State,
- sizeof (UINT8),
- &State
- );
- if (!EFI_ERROR (Status)) {
- if (!Variable->Volatile) {
- CacheVariable->InDeletedTransitionPtr->State = State;
- }
- } else {
- goto Done;
- }
- }
-
- State = CacheVariable->CurrPtr->State;
- State &= VAR_DELETED;
-
- Status = UpdateVariableStore (
- &mVariableModuleGlobal->VariableGlobal,
- Variable->Volatile,
- FALSE,
- Fvb,
- (UINTN)&Variable->CurrPtr->State,
- sizeof (UINT8),
- &State
+ } else {
+ //
+ // There's not enough space at the tail of variable storage but there's
+ // enough free space holes in the whole storage. Perform garbage collection
+ // & reclaim operation, and integrate the new variable at the same time.
+ //
+ Status = Reclaim (
+ VarStoreBase,
+ LastVariableOffset,
+ VolatileFlag,
+ Variable,
+ NewVariable,
+ VarSize
);
- if (!EFI_ERROR (Status) && !Variable->Volatile) {
- CacheVariable->CurrPtr->State = State;
- }
- }
+ UpdatingVariable = Variable->CurrPtr;
- if (!EFI_ERROR (Status)) {
- UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
- if (!Volatile) {
- FlushHobVariableToFlash (VariableName, VendorGuid);
+ if (EFI_ERROR (Status) &&
+ ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0))
+ {
+ //
+ // Out of space.
+ //
+ IsCommonUserVariable = IsUserVariable (NewVariable);
+ IsCommonVariable = TRUE;
+
+ if (IsCommonUserVariable &&
+ ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize)
+ > mVariableModuleGlobal->CommonMaxUserVariableSpace))
+ {
+ RecordVarErrorFlag (
+ VAR_ERROR_FLAG_USER_ERROR,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ VarSize
+ );
+ }
+
+ if (IsCommonVariable &&
+ ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize)
+ > mVariableModuleGlobal->CommonVariableSpace))
+ {
+ RecordVarErrorFlag (
+ VAR_ERROR_FLAG_SYSTEM_ERROR,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ VarSize
+ );
+ }
}
}
Done:
if (!EFI_ERROR (Status)) {
- if (((Variable->CurrPtr != NULL) && !Variable->Volatile) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)) {
- VolatileCacheInstance = &(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache);
+ if (!VolatileFlag) {
+ Offset = (UpdatingVariable != NULL) ? (UINTN)UpdatingVariable - (UINTN)VarStoreBase
+ : 0;
+ Status = ProtectedVariableLibWriteFinal (
+ NewVariable,
+ VarSize,
+ Offset
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ return Status;
+ }
+
+ Status = EFI_SUCCESS;
+ }
+
+ UpdateVariableInfo (
+ VariableName,
+ VendorGuid,
+ VolatileFlag,
+ FALSE,
+ TRUE,
+ FALSE,
+ FALSE,
+ &gVariableInfo
+ );
+ //
+ // HOB copy of the same variable is no longer needed, no matter it has
+ // been deleted, updated or added from/to real variable storage.
+ //
+ if (HobVarOnlyFlag || !VolatileFlag) {
+ FlushHobVariableToFlash (VariableName, VendorGuid);
+ }
+
+ if (!VolatileFlag) {
+ VolatileCacheInstance = &(VarGlobal->VariableRuntimeCacheContext.VariableRuntimeNvCache);
} else {
- VolatileCacheInstance = &(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache);
+ VolatileCacheInstance = &(VarGlobal->VariableRuntimeCacheContext.VariableRuntimeVolatileCache);
}
if (VolatileCacheInstance->Store != NULL) {
@@ -2401,6 +2525,11 @@ Done:
);
ASSERT_EFI_ERROR (Status);
}
+ } else if (Status == EFI_ALREADY_STARTED) {
+ //
+ // Meaning nothing needs to be done. Just return success.
+ //
+ Status = EFI_SUCCESS;
}
return Status;
@@ -2440,7 +2569,6 @@ VariableServiceGetVariable (
{
EFI_STATUS Status;
VARIABLE_POINTER_TRACK Variable;
- UINTN VarDataSize;
if ((VariableName == NULL) || (VendorGuid == NULL) || (DataSize == NULL)) {
return EFI_INVALID_PARAMETER;
@@ -2458,28 +2586,26 @@ VariableServiceGetVariable (
}
//
- // Get data size
+ // Get data and its size
//
- VarDataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
- ASSERT (VarDataSize != 0);
+ if (!Variable.Volatile) {
+ //
+ // Currently only non-volatile variable needs protection.
+ //
+ Status = ProtectedVariableLibGetByBuffer (
+ Variable.CurrPtr,
+ Data,
+ (UINT32 *)DataSize,
+ mVariableModuleGlobal->VariableGlobal.AuthFormat
+ );
+ }
- if (*DataSize >= VarDataSize) {
- if (Data == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
+ if (Variable.Volatile || (Status == EFI_UNSUPPORTED)) {
+ Status = GetVariableData (Variable.CurrPtr, Data, (UINT32 *)DataSize, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ }
- CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat), VarDataSize);
-
- *DataSize = VarDataSize;
+ if (!EFI_ERROR (Status)) {
UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE, &gVariableInfo);
-
- Status = EFI_SUCCESS;
- goto Done;
- } else {
- *DataSize = VarDataSize;
- Status = EFI_BUFFER_TOO_SMALL;
- goto Done;
}
Done:
@@ -2860,7 +2986,7 @@ VariableServiceSetVariable (
// Parse non-volatile variable data and get last variable offset.
//
NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point);
- while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point))) {
+ while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point), AuthFormat)) {
NextVariable = GetNextVariablePtr (NextVariable, AuthFormat);
}
@@ -3022,7 +3148,12 @@ VariableServiceQueryVariableInfoInternal (
//
// Now walk through the related variable store.
//
- while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
+ while (IsValidVariableHeader (
+ Variable,
+ GetEndPointer (VariableStoreHeader),
+ mVariableModuleGlobal->VariableGlobal.AuthFormat
+ ))
+ {
NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);
VariableSize = (UINT64)(UINTN)NextVariable - (UINT64)(UINTN)Variable;
@@ -3315,7 +3446,7 @@ FlushHobVariableToFlash (
//
mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
for ( Variable = GetStartPointer (VariableStoreHeader)
- ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))
+ ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader), AuthFormat)
; Variable = GetNextVariablePtr (Variable, AuthFormat)
)
{
@@ -3525,11 +3656,11 @@ ConvertNormalVarStorageToAuthVarStorage (
VARIABLE_HEADER *StartPtr;
UINT8 *NextPtr;
VARIABLE_HEADER *EndPtr;
- UINTN AuthVarStroageSize;
+ UINTN AuthVarStorageSize;
AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr;
VARIABLE_STORE_HEADER *AuthVarStorage;
- AuthVarStroageSize = sizeof (VARIABLE_STORE_HEADER);
+ AuthVarStorageSize = sizeof (VARIABLE_STORE_HEADER);
//
// Set AuthFormat as FALSE for normal variable storage
//
@@ -3542,10 +3673,10 @@ ConvertNormalVarStorageToAuthVarStorage (
EndPtr = GetEndPointer (NormalVarStorage);
while (StartPtr < EndPtr) {
if (StartPtr->State == VAR_ADDED) {
- AuthVarStroageSize = HEADER_ALIGN (AuthVarStroageSize);
- AuthVarStroageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);
- AuthVarStroageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr->NameSize);
- AuthVarStroageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr->DataSize);
+ AuthVarStorageSize = HEADER_ALIGN (AuthVarStorageSize);
+ AuthVarStorageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ AuthVarStorageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr->NameSize);
+ AuthVarStorageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr->DataSize);
}
StartPtr = GetNextVariablePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
@@ -3554,7 +3685,7 @@ ConvertNormalVarStorageToAuthVarStorage (
//
// Allocate Runtime memory for Auth Variable Storage
//
- AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStroageSize);
+ AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStorageSize);
ASSERT (AuthVarStorage != NULL);
if (AuthVarStorage == NULL) {
return NULL;
@@ -3608,7 +3739,7 @@ ConvertNormalVarStorageToAuthVarStorage (
AuthVarStorage->State = NormalVarStorage->State;
AuthVarStorage->Size = (UINT32)((UINTN)AuthStartPtr - (UINTN)AuthVarStorage);
CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid);
- ASSERT (AuthVarStorage->Size <= AuthVarStroageSize);
+ ASSERT (AuthVarStorage->Size <= AuthVarStorageSize);
//
// Restore AuthFormat
@@ -3774,7 +3905,7 @@ VariableCommonInitialize (
//
// Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
//
- ScratchSize = GetMaxVariableSize ();
+ ScratchSize = GetMaxVariableSize () * 2;
mVariableModuleGlobal->ScratchBufferSize = ScratchSize;
VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
if (VolatileVariableStore == NULL) {
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
index 03fec3048dc4..52bf29ec4c5c 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
@@ -3,7 +3,7 @@
and volatile storage space and install variable architecture protocol.
Copyright (C) 2013, Red Hat, Inc.
-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
Copyright (c) Microsoft Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -14,6 +14,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Protocol/VariablePolicy.h>
#include <Library/VariablePolicyLib.h>
+#include "VariableParsing.h"
EFI_STATUS
EFIAPI
@@ -534,6 +535,29 @@ VariableServiceInitialize (
EFI_EVENT ReadyToBootEvent;
EFI_EVENT EndOfDxeEvent;
+ PROTECTED_VARIABLE_CONTEXT_IN ContextIn;
+
+ //
+ // Initialze protected variable service, if enabled.
+ //
+ ContextIn.StructSize = sizeof (ContextIn);
+ ContextIn.StructVersion = PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
+
+ ContextIn.FindVariableSmm = NULL;
+ ContextIn.GetVariableInfo = GetVariableInfo;
+ ContextIn.GetNextVariableInfo = GetNextVariableInfo;
+ ContextIn.UpdateVariableStore = VariableExLibUpdateNvVariable;
+ ContextIn.UpdateVariable = VariableExLibUpdateVariable;
+
+ ContextIn.MaxVariableSize = (UINT32)GetMaxVariableSize ();
+ ContextIn.VariableServiceUser = FromSmmModule;
+
+ Status = ProtectedVariableLibInitialize (&ContextIn);
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
Status = VariableCommonInitialize ();
ASSERT_EFI_ERROR (Status);
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
index 62cde0335512..5904bcbff78a 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
@@ -1,13 +1,14 @@
/** @file
Provides variable driver extended services.
-Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Variable.h"
#include "VariableParsing.h"
+#include "VariableRuntimeCache.h"
/**
Finds variable in storage blocks of volatile and non-volatile storage areas.
@@ -38,6 +39,7 @@ VariableExLibFindVariable (
EFI_STATUS Status;
VARIABLE_POINTER_TRACK Variable;
AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+ PROTECTED_VARIABLE_INFO VarInfo;
Status = FindVariable (
VariableName,
@@ -56,9 +58,12 @@ VariableExLibFindVariable (
return Status;
}
- AuthVariableInfo->DataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
- AuthVariableInfo->Data = GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
- AuthVariableInfo->Attributes = Variable.CurrPtr->Attributes;
+ AuthVariableInfo->NameSize = NameSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->VariableName = GetVariableNamePtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->VendorGuid = GetVendorGuidPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->DataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->Data = GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->Attributes = Variable.CurrPtr->Attributes;
if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable.CurrPtr;
AuthVariableInfo->PubKeyIndex = AuthVariable->PubKeyIndex;
@@ -66,6 +71,24 @@ VariableExLibFindVariable (
AuthVariableInfo->TimeStamp = &AuthVariable->TimeStamp;
}
+ CopyMem (&VarInfo.Header, AuthVariableInfo, sizeof (VarInfo.Header));
+
+ VarInfo.Buffer = Variable.CurrPtr;
+ VarInfo.PlainData = NULL;
+ VarInfo.PlainDataSize = 0;
+ VarInfo.Flags.Auth = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ //
+ // In case the variable is encrypted.
+ //
+ Status = ProtectedVariableLibGetByInfo (&VarInfo);
+ if (!EFI_ERROR (Status)) {
+ if (VarInfo.PlainData != NULL) {
+ AuthVariableInfo->Data = VarInfo.PlainData;
+ AuthVariableInfo->DataSize = VarInfo.PlainDataSize;
+ }
+ }
+
return EFI_SUCCESS;
}
@@ -99,6 +122,7 @@ VariableExLibFindNextVariable (
VARIABLE_HEADER *VariablePtr;
AUTHENTICATED_VARIABLE_HEADER *AuthVariablePtr;
VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
+ PROTECTED_VARIABLE_INFO VarInfo;
VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase;
@@ -123,6 +147,7 @@ VariableExLibFindNextVariable (
return Status;
}
+ AuthVariableInfo->NameSize = NameSizeOfVariable (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
AuthVariableInfo->VariableName = GetVariableNamePtr (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
AuthVariableInfo->VendorGuid = GetVendorGuidPtr (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
AuthVariableInfo->DataSize = DataSizeOfVariable (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
@@ -135,6 +160,20 @@ VariableExLibFindNextVariable (
AuthVariableInfo->TimeStamp = &AuthVariablePtr->TimeStamp;
}
+ CopyMem (&VarInfo.Header, AuthVariableInfo, sizeof (VarInfo.Header));
+
+ VarInfo.Buffer = VariablePtr;
+ VarInfo.PlainData = NULL;
+ VarInfo.PlainDataSize = 0;
+
+ Status = ProtectedVariableLibGetByInfo (&VarInfo);
+ if (!EFI_ERROR (Status)) {
+ if (VarInfo.PlainData != NULL) {
+ AuthVariableInfo->Data = VarInfo.PlainData;
+ AuthVariableInfo->DataSize = VarInfo.PlainDataSize;
+ }
+ }
+
return EFI_SUCCESS;
}
@@ -256,3 +295,123 @@ VariableExLibAtRuntime (
{
return AtRuntime ();
}
+
+/**
+ Update partial data of a variable on NV storage and/or cached copy.
+
+ @param[in] VariableInfo Pointer to a variable with detailed information.
+ @param[in] Offset Offset to write from.
+ @param[in] Size Size of data Buffer to update.
+ @param[in] Buffer Pointer to data buffer to update.
+
+ @retval EFI_SUCCESS The variable data was updated successfully.
+ @retval EFI_UNSUPPORTED If this function is called directly in runtime.
+ @retval EFI_INVALID_PARAMETER If VariableInfo, Buffer or Size are not valid.
+ @retval Others Failed to update NV storage or variable cache.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibUpdateNvVariable (
+ IN PROTECTED_VARIABLE_INFO *VariableInfo,
+ IN UINTN Offset,
+ IN UINT32 Size,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_GLOBAL *Global;
+ VARIABLE_RUNTIME_CACHE *CacheInstance;
+ VARIABLE_HEADER *VariableCache;
+
+ if ((mVariableModuleGlobal == NULL) || (mNvVariableCache == NULL)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Flush the cache to store.
+ //
+ if (Size == (UINT32)-1) {
+ Status = FtwVariableSpace (
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
+ mNvVariableCache
+ );
+ if ( !EFI_ERROR (Status)
+ && (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0))
+ {
+ FlushHobVariableToFlash (NULL, NULL);
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
+ FreePool ((VOID *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase);
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
+ }
+ }
+
+ return Status;
+ }
+
+ if ( (VariableInfo == NULL)
+ || (VariableInfo->StoreIndex == VAR_INDEX_INVALID)
+ || (Buffer == NULL)
+ || (Size == 0))
+ {
+ ASSERT (VariableInfo != NULL);
+ ASSERT (VariableInfo->StoreIndex != VAR_INDEX_INVALID);
+ ASSERT (Buffer != NULL);
+ ASSERT (Size != 0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Global = &mVariableModuleGlobal->VariableGlobal;
+
+ VariableCache = (VARIABLE_HEADER *)((UINTN)mNvVariableCache + (UINTN)VariableInfo->StoreIndex);
+
+ ASSERT (
+ StrCmp (
+ VariableInfo->Header.VariableName,
+ GetVariableNamePtr (VariableCache, Global->AuthFormat)
+ ) == 0
+ );
+ ASSERT (
+ CompareGuid (
+ VariableInfo->Header.VendorGuid,
+ GetVendorGuidPtr (VariableCache, Global->AuthFormat)
+ )
+ );
+
+ //
+ // Forcibly update part data of flash copy of the variable ...
+ //
+ Status = UpdateVariableStore (
+ Global,
+ FALSE,
+ FALSE,
+ mVariableModuleGlobal->FvbInstance,
+ (UINTN)(Global->NonVolatileVariableBase + VariableInfo->StoreIndex + Offset),
+ Size,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ //
+ // ... as well as the local cached copy.
+ //
+ CopyMem ((VOID *)((UINTN)VariableCache + Offset), Buffer, Size);
+
+ //
+ // Sync remote cached copy.
+ //
+ CacheInstance = &Global->VariableRuntimeCacheContext.VariableRuntimeNvCache;
+ if (CacheInstance->Store != NULL) {
+ Status = SynchronizeRuntimeVariableCache (
+ CacheInstance,
+ (UINTN)VariableInfo->StoreIndex + Offset,
+ Size
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
index 5e9d40b67ac2..e8b8f0b7f705 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
@@ -1,7 +1,7 @@
/** @file
Common variable non-volatile store routines.
-Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -120,6 +120,181 @@ InitEmuNonVolatileVariableStore (
return EFI_SUCCESS;
}
+/**
+
+ Create a dummy variable used to fill the gap in NV variable storage caused by
+ the invalid variables found in HMAC verification phase.
+
+ @param[out] Variable Variable buffer.
+ @param[in] Name Variable Name.
+ @param[in] Guid Vendor GUID of the variable.
+ @param[in] Size Whole size of the variable requested.
+ @param[in] AuthFlag Variable format flag.
+
+**/
+STATIC
+VOID
+CreateDummyVariable (
+ OUT VARIABLE_HEADER *Variable,
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN UINT32 Size,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ ASSERT (Variable != NULL);
+
+ if (Name == NULL) {
+ Name = L"Dummy";
+ }
+
+ if (AuthFlag) {
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+
+ AuthVariable->StartId = VARIABLE_DATA;
+ AuthVariable->State = VAR_ADDED & VAR_DELETED;
+ AuthVariable->Attributes = EFI_VARIABLE_NON_VOLATILE;
+ AuthVariable->NameSize = (UINT32)StrSize (Name);
+ AuthVariable->DataSize = Size - sizeof (AUTHENTICATED_VARIABLE_HEADER)
+ - AuthVariable->NameSize;
+ if (Guid != NULL) {
+ CopyMem ((VOID *)&AuthVariable->VendorGuid, (VOID *)Guid, sizeof (EFI_GUID));
+ }
+
+ CopyMem (GetVariableNamePtr (Variable, AuthFlag), (VOID *)Name, AuthVariable->NameSize);
+ } else {
+ Variable->StartId = VARIABLE_DATA;
+ Variable->State = VAR_ADDED & VAR_DELETED;
+ Variable->Attributes = EFI_VARIABLE_NON_VOLATILE;
+ Variable->NameSize = (UINT32)StrSize (Name);
+ Variable->DataSize = Size - sizeof (VARIABLE_HEADER) - Variable->NameSize;
+ if (Guid != NULL) {
+ CopyMem ((VOID *)&Variable->VendorGuid, (VOID *)Guid, sizeof (EFI_GUID));
+ }
+
+ CopyMem (GetVariableNamePtr (Variable, AuthFlag), (VOID *)Name, Variable->NameSize);
+ }
+}
+
+/**
+
+ Init protected variable store.
+
+ @param[in, out] VariableStore Pointer to real protected variable store base.
+
+**/
+EFI_STATUS
+InitProtectedVariableStore (
+ IN OUT VARIABLE_STORE_HEADER *VariableStore
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_INFO VarInfo;
+ UINTN Size;
+ UINTN Index;
+ BOOLEAN AuthFlag;
+ EFI_PHYSICAL_ADDRESS NextVariableStore;
+ EFI_PHYSICAL_ADDRESS *VarList;
+ UINTN NumVars;
+ UINTN CurrVar;
+
+ SetMem (
+ (UINT8 *)VariableStore + sizeof (VARIABLE_STORE_HEADER),
+ VariableStore->Size - sizeof (VARIABLE_STORE_HEADER),
+ 0xFF
+ );
+ Index = sizeof (VARIABLE_STORE_HEADER);
+
+ VarList = NULL;
+ NumVars = 0;
+ ProtectedVariableLibGetSortedList (&VarList, &NumVars);
+
+ //
+ // Search variable in the order of StoreIndex
+ //
+ ZeroMem (&VarInfo, sizeof (VarInfo));
+
+ for (CurrVar = 0; CurrVar < NumVars; CurrVar++) {
+ VarInfo.Buffer = NULL;
+ VarInfo.StoreIndex = VarList[CurrVar];
+ if (VarInfo.StoreIndex == VAR_INDEX_INVALID) {
+ break;
+ }
+
+ Status = ProtectedVariableLibFind (&VarInfo);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ASSERT (VarInfo.Buffer != NULL);
+
+ AuthFlag = VarInfo.Flags.Auth;
+ if (VarInfo.StoreIndex == VAR_INDEX_INVALID) {
+ continue;
+ } else {
+ ASSERT (VarInfo.StoreIndex == HEADER_ALIGN (VarInfo.StoreIndex));
+ ASSERT (VarInfo.StoreIndex < (VariableStore->Size - sizeof (VARIABLE_STORE_HEADER)));
+ ASSERT ((VariableStore->Size - VarInfo.StoreIndex) > GetVariableHeaderSize (AuthFlag));
+ }
+
+ //
+ // Fill gap caused by invalid variable.
+ //
+ if (VarInfo.StoreIndex > Index) {
+ Size = (UINTN)VarInfo.StoreIndex - Index;
+ CreateDummyVariable (
+ (VARIABLE_HEADER *)((UINT8 *)VariableStore + Index),
+ NULL,
+ NULL,
+ (UINT32)Size,
+ AuthFlag
+ );
+ Index += Size;
+ }
+
+ Size = (UINTN)GetNextVariablePtr (VarInfo.Buffer, AuthFlag)
+ - (UINTN)VarInfo.Buffer;
+ CopyMem ((UINT8 *)VariableStore + VarInfo.StoreIndex, VarInfo.Buffer, Size);
+
+ Index += Size;
+ Index = HEADER_ALIGN (Index);
+
+ NextVariableStore = (EFI_PHYSICAL_ADDRESS)((UINTN)VariableStore + VarInfo.StoreIndex + Size);
+ }
+
+ //
+ // Search variable in the order of StoreIndex
+ //
+ ZeroMem (&VarInfo, sizeof (VarInfo));
+ for ( ; CurrVar < NumVars; CurrVar++) {
+ VarInfo.Buffer = NULL;
+ VarInfo.StoreIndex = VarList[CurrVar];
+ Status = ProtectedVariableLibFind (&VarInfo);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ASSERT (VarInfo.Buffer != NULL);
+
+ AuthFlag = VarInfo.Flags.Auth;
+ if (VarInfo.StoreIndex == VAR_INDEX_INVALID) {
+ Size = (UINTN)GetNextVariablePtr (VarInfo.Buffer, AuthFlag)
+ - (UINTN)VarInfo.Buffer;
+ CopyMem ((UINT8 *)&NextVariableStore, VarInfo.Buffer, Size);
+ Status = ProtectedVariableLibRefresh (VarInfo.Buffer, 0, NextVariableStore - (UINTN)VariableStore, FALSE);
+ NextVariableStore = NextVariableStore + Size;
+ }
+ }
+
+ if (Status == EFI_UNSUPPORTED) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
/**
Init real non-volatile variable store.
@@ -230,6 +405,16 @@ InitRealNonVolatileVariableStore (
return EFI_VOLUME_CORRUPTED;
}
+ //
+ // Overwrite the store with verified copy of protected variables, if enabled.
+ //
+ Status = InitProtectedVariableStore (VariableStore);
+ if ((Status != EFI_SUCCESS) && (Status != EFI_UNSUPPORTED)) {
+ FreePool (NvStorageData);
+ DEBUG ((DEBUG_ERROR, "Variable integrity might have been compromised\n"));
+ return Status;
+ }
+
mNvFvHeaderCache = FvHeader;
*VariableStoreBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStore;
@@ -323,7 +508,12 @@ InitNonVolatileVariableStore (
// Parse non-volatile variable data and get last variable offset.
//
Variable = GetStartPointer (mNvVariableCache);
- while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
+ while (IsValidVariableHeader (
+ Variable,
+ GetEndPointer (mNvVariableCache),
+ mVariableModuleGlobal->VariableGlobal.AuthFormat
+ ))
+ {
NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);
VariableSize = (UINTN)NextVariable - (UINTN)Variable;
if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
index 39060ed405b8..000e4b546888 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
@@ -2,11 +2,12 @@
Functions in this module are associated with variable parsing operations and
are intended to be usable across variable driver source files.
-Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
+#include "Variable.h"
#include "VariableParsing.h"
/**
@@ -15,6 +16,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
@param[in] Variable Pointer to the Variable Header.
@param[in] VariableStoreEnd Pointer to the Variable Store End.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
@retval TRUE Variable header is valid.
@retval FALSE Variable header is not valid.
@@ -23,10 +26,14 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
BOOLEAN
IsValidVariableHeader (
IN VARIABLE_HEADER *Variable,
- IN VARIABLE_HEADER *VariableStoreEnd
+ IN VARIABLE_HEADER *VariableStoreEnd,
+ IN BOOLEAN AuthFormat
)
{
- if ((Variable == NULL) || (Variable >= VariableStoreEnd) || (Variable->StartId != VARIABLE_DATA)) {
+ if ( (Variable == NULL)
+ || (((UINTN)Variable + GetVariableHeaderSize (AuthFormat)) >= (UINTN)VariableStoreEnd)
+ || (Variable->StartId != VARIABLE_DATA))
+ {
//
// Variable is NULL or has reached the end of variable store,
// or the StartId is not correct.
@@ -341,6 +348,52 @@ GetVariableDataOffset (
return Value;
}
+/**
+ Get variable data payload.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in,out] Data Pointer to buffer used to store the variable data.
+ @param[in,out] DataSize Size of buffer passed by Data.
+ Size of data copied into Data buffer.
+ @param[in] AuthFlag Auth-variable indicator.
+
+ @return EFI_SUCCESS Data was fetched.
+ @return EFI_INVALID_PARAMETER DataSize is NULL.
+ @return EFI_BUFFER_TOO_SMALL DataSize is smaller than size of variable data.
+
+**/
+EFI_STATUS
+GetVariableData (
+ IN VARIABLE_HEADER *Variable,
+ IN OUT VOID *Data,
+ IN OUT UINT32 *DataSize,
+ IN BOOLEAN AuthFlag
+ )
+{
+ UINT32 Size;
+
+ if (DataSize == NULL) {
+ ASSERT (DataSize != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Size = (UINT32)DataSizeOfVariable (Variable, AuthFlag);
+ if (*DataSize < Size) {
+ *DataSize = Size;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (Data == NULL) {
+ ASSERT (Data != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (Data, GetVariableDataPtr (Variable, AuthFlag), Size);
+ *DataSize = Size;
+
+ return EFI_SUCCESS;
+}
+
/**
This code gets the pointer to the next variable header.
@@ -479,7 +532,7 @@ FindVariableEx (
InDeletedVariable = NULL;
for ( PtrTrack->CurrPtr = PtrTrack->StartPtr
- ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr)
+ ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr, AuthFormat)
; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr, AuthFormat)
)
{
@@ -608,7 +661,7 @@ VariableServiceGetNextVariableInternal (
//
// Switch to the next variable store if needed
//
- while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr)) {
+ while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr, AuthFormat)) {
//
// Find current storage index
//
@@ -804,3 +857,260 @@ UpdateVariableInfo (
}
}
}
+
+/**
+
+ Retrieve details about a variable and return them in VariableInfo->Header.
+
+ If VariableInfo->Address is given, this function will calculate its offset
+ relative to given variable storage via VariableStore; Otherwise, it will try
+ other internal variable storages or cached copies. It's assumed that, for all
+ copies of NV variable storage, all variables are stored in the same relative
+ position. If VariableInfo->Address is found in the range of any storage copies,
+ its offset relative to that storage should be the same in other copies.
+
+ If VariableInfo->Offset is given (non-zero) but not VariableInfo->Address,
+ this function will return the variable memory address inside VariableStore,
+ if given, via VariableInfo->Address; Otherwise, the address of other storage
+ copies will be returned, if any.
+
+ For a new variable whose offset has not been determined, a value of -1 as
+ VariableInfo->Offset should be passed to skip the offset calculation.
+
+ @param[in,out] VariableInfo Pointer to variable information.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo->Address
+ and VariableInfo->Offset are NULL (0).
+ @retval EFI_NOT_FOUND If given Address or Offset is out of range of
+ any given or internal storage copies.
+ @retval EFI_SUCCESS Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
+ )
+{
+ VARIABLE_STORE_HEADER *Stores[2];
+ UINTN Index;
+ VARIABLE_HEADER *VariablePtr;
+ VARIABLE_HEADER *VariableBuffer;
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariablePtr;
+ BOOLEAN AuthFlag;
+ UINTN NameSize;
+ UINTN DataSize;
+ UINTN VariableSize;
+
+ if ((VariableInfo == NULL) || ( (VariableInfo->Buffer == NULL)
+ && (VariableInfo->StoreIndex == VAR_INDEX_INVALID)))
+ {
+ ASSERT (VariableInfo != NULL);
+ ASSERT (VariableInfo->Buffer != NULL || VariableInfo->StoreIndex != VAR_INDEX_INVALID);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Stores[0] = mNvVariableCache;
+ Stores[1] = (mVariableModuleGlobal != NULL)
+ ? (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase
+ : NULL;
+
+ VariableBuffer = VariableInfo->Buffer;
+ VariablePtr = NULL;
+ if (VariableInfo->StoreIndex != VAR_INDEX_INVALID) {
+ for (Index = 0; Index < ARRAY_SIZE (Stores); ++Index) {
+ if (Stores[Index] == NULL) {
+ continue;
+ }
+
+ if ((UINTN)VariableInfo->StoreIndex
+ < ((UINTN)GetEndPointer (Stores[Index]) - (UINTN)Stores[Index]))
+ {
+ VariablePtr = (VARIABLE_HEADER *)((UINTN)Stores[Index] + (UINTN)VariableInfo->StoreIndex);
+ VariableInfo->Buffer = VariablePtr;
+ break;
+ }
+ }
+ } else {
+ VariablePtr = VariableInfo->Buffer;
+ }
+
+ if (VariablePtr == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ AuthFlag = VariableInfo->Flags.Auth;
+ ASSERT (AuthFlag == TRUE || AuthFlag == FALSE);
+
+ //
+ // Make a copy of the whole variable if a buffer is passed in.
+ //
+ if ((VariableBuffer != NULL) && (VariableBuffer != VariablePtr)) {
+ VariableSize = (UINTN)GetNextVariablePtr (VariablePtr, AuthFlag)
+ - (UINTN)VariablePtr;
+ CopyMem (VariableBuffer, VariablePtr, VariableSize);
+ }
+
+ //
+ // AuthVariable header
+ //
+ if (AuthFlag) {
+ AuthVariablePtr = (AUTHENTICATED_VARIABLE_HEADER *)VariablePtr;
+
+ VariableInfo->Header.State = AuthVariablePtr->State;
+ VariableInfo->Header.Attributes = AuthVariablePtr->Attributes;
+ VariableInfo->Header.PubKeyIndex = AuthVariablePtr->PubKeyIndex;
+ VariableInfo->Header.MonotonicCount = ReadUnaligned64 (
+ &(AuthVariablePtr->MonotonicCount)
+ );
+ if (VariableInfo->Header.TimeStamp != NULL) {
+ CopyMem (
+ VariableInfo->Header.TimeStamp,
+ &AuthVariablePtr->TimeStamp,
+ sizeof (EFI_TIME)
+ );
+ } else if (VariableBuffer != NULL) {
+ AuthVariablePtr = (AUTHENTICATED_VARIABLE_HEADER *)VariableBuffer;
+ VariableInfo->Header.TimeStamp = &AuthVariablePtr->TimeStamp;
+ }
+ } else {
+ VariableInfo->Header.State = VariablePtr->State;
+ VariableInfo->Header.Attributes = VariablePtr->Attributes;
+ VariableInfo->Header.PubKeyIndex = 0;
+ VariableInfo->Header.MonotonicCount = 0;
+ VariableInfo->Header.TimeStamp = NULL;
+ }
+
+ //
+ // VendorGuid
+ //
+ if (VariableInfo->Header.VendorGuid != NULL) {
+ CopyGuid (
+ VariableInfo->Header.VendorGuid,
+ GetVendorGuidPtr (VariablePtr, AuthFlag)
+ );
+ } else {
+ VariableInfo->Header.VendorGuid = GetVendorGuidPtr (VariablePtr, AuthFlag);
+ }
+
+ //
+ // VariableName
+ //
+ NameSize = NameSizeOfVariable (VariablePtr, AuthFlag);
+ if ( (VariableInfo->Header.VariableName != NULL)
+ && (VariableInfo->Header.NameSize >= NameSize))
+ {
+ CopyMem (
+ VariableInfo->Header.VariableName,
+ GetVariableNamePtr (VariablePtr, AuthFlag),
+ NameSize
+ );
+ } else if (VariableInfo->Header.VariableName != NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ } else {
+ VariableInfo->Header.VariableName = GetVariableNamePtr (VariablePtr, AuthFlag);
+ }
+
+ //
+ // Data
+ //
+ DataSize = DataSizeOfVariable (VariablePtr, AuthFlag);
+ if ( (VariableInfo->Header.Data != NULL)
+ && (VariableInfo->Header.DataSize >= DataSize))
+ {
+ CopyMem (
+ VariableInfo->Header.Data,
+ GetVariableDataPtr (VariablePtr, AuthFlag),
+ NameSize
+ );
+ } else if (VariableInfo->Header.Data != NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ } else {
+ VariableInfo->Header.Data = GetVariableDataPtr (VariablePtr, AuthFlag);
+ }
+
+ //
+ // Update size information about name & data.
+ //
+ VariableInfo->Header.NameSize = NameSize;
+ VariableInfo->Header.DataSize = DataSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Retrieve details of the variable next to given variable within VariableStore.
+
+ If VarInfo->Address is NULL, the first one in VariableStore is returned.
+
+ VariableStart and/or VariableEnd can be given optionally for the situation
+ in which the valid storage space is smaller than the VariableStore->Size.
+ This usually happens when PEI variable services make a compact variable
+ cache to save memory, which cannot make use VariableStore->Size to determine
+ the correct variable storage range.
+
+ @param[in,out] VariableInfo Pointer to variable information.
+
+ @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL.
+ @retval EFI_NOT_FOUND If the end of VariableStore is reached.
+ @retval EFI_SUCCESS The next variable is retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextVariableInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
+ )
+{
+ VARIABLE_STORE_HEADER *VarStore;
+ VARIABLE_HEADER *VariablePtr;
+ VARIABLE_HEADER *VariableStart;
+ VARIABLE_HEADER *VariableEnd;
+ BOOLEAN AuthFlag;
+
+ if (VariableInfo == NULL) {
+ ASSERT (VariableInfo != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mNvVariableCache != NULL) {
+ VarStore = mNvVariableCache;
+ } else if (mVariableModuleGlobal != NULL) {
+ VarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+
+ VariableStart = GetStartPointer (VarStore);
+ VariableEnd = GetEndPointer (VarStore);
+
+ if ((VariableInfo->Flags.Auth != TRUE) && (VariableInfo->Flags.Auth != FALSE)) {
+ VariableInfo->Flags.Auth = CompareGuid (
+ &VarStore->Signature,
+ &gEfiAuthenticatedVariableGuid
+ );
+ }
+
+ AuthFlag = VariableInfo->Flags.Auth;
+
+ if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
+ VariablePtr = VariableStart;
+ } else {
+ VariablePtr = (VARIABLE_HEADER *)
+ ((UINTN)VarStore + (UINTN)VariableInfo->StoreIndex);
+ if (VariablePtr >= VariableEnd) {
+ return EFI_NOT_FOUND;
+ }
+
+ VariablePtr = GetNextVariablePtr (VariablePtr, AuthFlag);
+ }
+
+ if (!IsValidVariableHeader (VariablePtr, VariableEnd, AuthFlag)) {
+ return EFI_NOT_FOUND;
+ }
+
+ VariableInfo->StoreIndex = (UINTN)VariablePtr - (UINTN)VarStore;
+ return GetVariableInfo (VariableInfo);
+}
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
index 9bb30bc1e804..dc319feee727 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
@@ -7,7 +7,7 @@
This external input must be validated carefully to avoid security issue like
buffer overflow, integer overflow.
-Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
index 517cae7b00f8..c2b689f6202d 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
@@ -14,7 +14,7 @@
VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
SmmVariableGetStatistics() should also do validation based on its own knowledge.
-Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -1045,6 +1045,13 @@ VariableWriteServiceInitializeSmm (
{
EFI_STATUS Status;
+ Status = ProtectedVariableLibWriteInit ();
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ DEBUG ((DEBUG_ERROR, "Variable protection service: write-init failed. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return;
+ }
+
Status = VariableWriteServiceInitialize ();
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. Status = %r\n", Status));
@@ -1143,10 +1150,32 @@ MmVariableServiceInitialize (
VOID
)
{
- EFI_STATUS Status;
- EFI_HANDLE VariableHandle;
- VOID *SmmFtwRegistration;
- VOID *SmmEndOfDxeRegistration;
+ EFI_STATUS Status;
+ EFI_HANDLE VariableHandle;
+ VOID *SmmFtwRegistration;
+ VOID *SmmEndOfDxeRegistration;
+ PROTECTED_VARIABLE_CONTEXT_IN ContextIn;
+
+ //
+ // Initialize protected variable service, if enabled.
+ //
+ ContextIn.StructSize = sizeof (ContextIn);
+ ContextIn.StructVersion = PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
+
+ ContextIn.FindVariableSmm = NULL;
+ ContextIn.GetVariableInfo = GetVariableInfo;
+ ContextIn.GetNextVariableInfo = GetNextVariableInfo;
+ ContextIn.UpdateVariableStore = VariableExLibUpdateNvVariable;
+ ContextIn.UpdateVariable = VariableExLibUpdateVariable;
+
+ ContextIn.MaxVariableSize = (UINT32)GetMaxVariableSize ();
+ ContextIn.VariableServiceUser = FromSmmModule;
+
+ Status = ProtectedVariableLibInitialize (&ContextIn);
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
//
// Variable initialize.
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
index 4aaeb5ba8806..8fb8679671ad 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
@@ -13,7 +13,7 @@
InitCommunicateBuffer() is really function to check the variable data size.
-Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
Copyright (c) Microsoft Corporation.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -36,11 +36,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/MmUnblockMemoryLib.h>
+#include <Library/IoLib.h>
#include <Guid/EventGroup.h>
#include <Guid/SmmVariableCommon.h>
#include "PrivilegePolymorphic.h"
+#include "Variable.h"
#include "VariableParsing.h"
EFI_HANDLE mHandle = NULL;
@@ -53,6 +55,8 @@ VARIABLE_INFO_ENTRY *mVariableInfo = NULL;
VARIABLE_STORE_HEADER *mVariableRuntimeHobCacheBuffer = NULL;
VARIABLE_STORE_HEADER *mVariableRuntimeNvCacheBuffer = NULL;
VARIABLE_STORE_HEADER *mVariableRuntimeVolatileCacheBuffer = NULL;
+VARIABLE_STORE_HEADER *mNvVariableCache = NULL;
+VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal = NULL;
UINTN mVariableBufferSize;
UINTN mVariableRuntimeHobCacheBufferSize;
UINTN mVariableRuntimeNvCacheBufferSize;
@@ -616,7 +620,6 @@ FindVariableInRuntimeCache (
)
{
EFI_STATUS Status;
- UINTN TempDataSize;
VARIABLE_POINTER_TRACK RtPtrTrack;
VARIABLE_STORE_TYPE StoreType;
VARIABLE_STORE_HEADER *VariableStoreList[VariableStoreTypeMax];
@@ -669,31 +672,23 @@ FindVariableInRuntimeCache (
//
// Get data size
//
- TempDataSize = DataSizeOfVariable (RtPtrTrack.CurrPtr, mVariableAuthFormat);
- ASSERT (TempDataSize != 0);
-
- if (*DataSize >= TempDataSize) {
- if (Data == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- CopyMem (Data, GetVariableDataPtr (RtPtrTrack.CurrPtr, mVariableAuthFormat), TempDataSize);
- *DataSize = TempDataSize;
-
- UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE, FALSE, FALSE, TRUE, &mVariableInfo);
-
- Status = EFI_SUCCESS;
- goto Done;
- } else {
- *DataSize = TempDataSize;
- Status = EFI_BUFFER_TOO_SMALL;
- goto Done;
+ if (!RtPtrTrack.Volatile) {
+ //
+ // Currently only non-volatile variable needs protection.
+ //
+ Status = ProtectedVariableLibGetByBuffer (RtPtrTrack.CurrPtr, Data, (UINT32 *)DataSize, mVariableAuthFormat);
+ }
+
+ if (RtPtrTrack.Volatile || (Status == EFI_UNSUPPORTED)) {
+ Status = GetVariableData (RtPtrTrack.CurrPtr, Data, (UINT32 *)DataSize, mVariableAuthFormat);
+ }
+
+ if (!EFI_ERROR (Status)) {
+ UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE, FALSE, FALSE, FALSE, &mVariableInfo);
}
}
}
-Done:
if ((Status == EFI_SUCCESS) || (Status == EFI_BUFFER_TOO_SMALL)) {
if ((Attributes != NULL) && (RtPtrTrack.CurrPtr != NULL)) {
*Attributes = RtPtrTrack.CurrPtr->Attributes;
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 10/28] SecurityPkg: Add new KeyService types and defines
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (8 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 09/28] MdeModulePkg: Add support for Protected Variables Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-22 14:06 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 11/28] SecurityPkg: Update RPMC APIs with index Judah Vang
` (19 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add new KeyService types and defines.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
SecurityPkg/Include/Ppi/KeyServicePpi.h | 57 ++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/SecurityPkg/Include/Ppi/KeyServicePpi.h b/SecurityPkg/Include/Ppi/KeyServicePpi.h
new file mode 100644
index 000000000000..f126913d2d81
--- /dev/null
+++ b/SecurityPkg/Include/Ppi/KeyServicePpi.h
@@ -0,0 +1,57 @@
+/** @file
+ Provides Key Services.
+
+Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+@par Specification Reference:
+**/
+
+#ifndef PEI_KEY_SERVICE_PPI_H_
+#define PEI_KEY_SERVICE_PPI_H_
+///
+/// KEY SERVICE PPI GUID
+///
+extern EFI_GUID gKeyServicePpiGuid;
+
+/**
+ Generate a new key from root key.
+
+ @param[in] Salt Pointer to the salt(non-secret) value.
+ @param[in] SaltSize Salt size in bytes.
+ @param[out] NewKey Pointer to buffer to receive new key.
+ @param[in] NewKeySize Size of new key bytes to generate.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval OTHER The function completed with failure.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *KEY_SERVICE_GEN_KEY)(
+ IN UINT8 *Salt,
+ IN UINTN SaltSize,
+ OUT UINT8 *NewKey,
+ IN UINTN NewKeySize
+ );
+
+#define KEY_SERVICE_PPI_REVISION 1
+#define ROOT_KEY_LEN 64
+#define SALT_SIZE_MIN_LEN 64
+#define KEY_SERVICE_KEY_NAME L"KEY_SERVICE_KEY"
+
+typedef struct {
+ UINT8 RootKey[ROOT_KEY_LEN];
+ UINT8 PreviousRootKey[ROOT_KEY_LEN];
+} KEY_SERVICE_DATA;
+
+typedef struct _KEY_SERVICE_PPI KEY_SERVICE_PPI;
+
+///
+/// KEY SERVICE PPI
+/// The interface functions are for Key Service in PEI Phase
+///
+struct _KEY_SERVICE_PPI {
+ KEY_SERVICE_GEN_KEY GenerateKey; /// Generate Key
+};
+
+#endif
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 11/28] SecurityPkg: Update RPMC APIs with index
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (9 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 10/28] SecurityPkg: Add new KeyService types and defines Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-22 14:07 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 12/28] SecurityPkg: Add new variable types and functions Judah Vang
` (18 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Update RPMC APIs with index parameter because sometimes
there are more than 1 RPMC counter on the platform.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c b/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c
index 792e48250e5d..557aeb6abf09 100644
--- a/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c
+++ b/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c
@@ -1,7 +1,7 @@
/** @file
NULL RpmcLib instance for build purpose.
-Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -12,6 +12,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
/**
Requests the monotonic counter from the designated RPMC counter.
+ @param[in] CounterIndex The RPMC index
@param[out] CounterValue A pointer to a buffer to store the RPMC value.
@retval EFI_SUCCESS The operation completed successfully.
@@ -21,6 +22,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
EFI_STATUS
EFIAPI
RequestMonotonicCounter (
+ IN UINT8 CounterIndex,
OUT UINT32 *CounterValue
)
{
@@ -31,6 +33,8 @@ RequestMonotonicCounter (
/**
Increments the monotonic counter in the SPI flash device by 1.
+ @param[in] CounterIndex The RPMC index
+
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_DEVICE_ERROR A device error occurred while attempting to update the counter.
@retval EFI_UNSUPPORTED The operation is un-supported.
@@ -38,7 +42,7 @@ RequestMonotonicCounter (
EFI_STATUS
EFIAPI
IncrementMonotonicCounter (
- VOID
+ IN UINT8 CounterIndex
)
{
ASSERT (FALSE);
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 12/28] SecurityPkg: Add new variable types and functions
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (10 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 11/28] SecurityPkg: Update RPMC APIs with index Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-22 14:12 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 13/28] SecurityPkg: Fix GetVariableKey API Judah Vang
` (17 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add new variable encryption/decryption function prototypes.
Add new variable digest structure. Add new Protected
variable function prototypes. Update RPMC APIs to Add
an index because there is could more than one counter.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
SecurityPkg/Include/Library/RpmcLib.h | 15 +++++---
SecurityPkg/Include/Library/VariableKeyLib.h | 37 +++-----------------
2 files changed, 16 insertions(+), 36 deletions(-)
diff --git a/SecurityPkg/Include/Library/RpmcLib.h b/SecurityPkg/Include/Library/RpmcLib.h
index df4ba34ba8cf..cb71dfcd7e4d 100644
--- a/SecurityPkg/Include/Library/RpmcLib.h
+++ b/SecurityPkg/Include/Library/RpmcLib.h
@@ -1,19 +1,23 @@
/** @file
Public definitions for the Replay Protected Monotonic Counter (RPMC) Library.
-Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
-#ifndef _RPMC_LIB_H_
-#define _RPMC_LIB_H_
+#ifndef RPMC_LIB_H_
+#define RPMC_LIB_H_
#include <Uefi/UefiBaseType.h>
+#define RPMC_COUNTER_1 0
+#define RPMC_COUNTER_2 1
+
/**
Requests the monotonic counter from the designated RPMC counter.
+ @param[in] CounterIndex The RPMC index
@param[out] CounterValue A pointer to a buffer to store the RPMC value.
@retval EFI_SUCCESS The operation completed successfully.
@@ -23,12 +27,15 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
EFI_STATUS
EFIAPI
RequestMonotonicCounter (
+ IN UINT8 CounterIndex,
OUT UINT32 *CounterValue
);
/**
Increments the monotonic counter in the SPI flash device by 1.
+ @param[in] CounterIndex The RPMC index
+
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_DEVICE_ERROR A device error occurred while attempting to update the counter.
@retval EFI_UNSUPPORTED The operation is un-supported.
@@ -36,7 +43,7 @@ RequestMonotonicCounter (
EFI_STATUS
EFIAPI
IncrementMonotonicCounter (
- VOID
+ IN UINT8 CounterIndex
);
#endif
diff --git a/SecurityPkg/Include/Library/VariableKeyLib.h b/SecurityPkg/Include/Library/VariableKeyLib.h
index 561ebad09da2..6076c4d4731b 100644
--- a/SecurityPkg/Include/Library/VariableKeyLib.h
+++ b/SecurityPkg/Include/Library/VariableKeyLib.h
@@ -1,13 +1,13 @@
/** @file
Public definitions for Variable Key Library.
-Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
-#ifndef _VARIABLE_KEY_LIB_H_
-#define _VARIABLE_KEY_LIB_H_
+#ifndef VARIABLE_KEY_LIB_H_
+#define VARIABLE_KEY_LIB_H_
#include <Uefi/UefiBaseType.h>
@@ -25,35 +25,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
EFI_STATUS
EFIAPI
GetVariableKey (
- OUT VOID **VariableKey,
- IN OUT UINTN *VariableKeySize
- );
-
-/**
- Regenerates the variable key.
-
- @retval EFI_SUCCESS The variable key was regenerated successfully.
- @retval EFI_DEVICE_ERROR An error occurred while attempting to regenerate the key.
- @retval EFI_ACCESS_DENIED The function was invoked after locking the key interface.
- @retval EFI_UNSUPPORTED Key regeneration is not supported in the current boot configuration.
-**/
-EFI_STATUS
-EFIAPI
-RegenerateVariableKey (
- VOID
- );
-
-/**
- Locks the regenerate key interface.
-
- @retval EFI_SUCCESS The key interface was locked successfully.
- @retval EFI_UNSUPPORTED Locking the key interface is not supported in the current boot configuration.
- @retval Others An error occurred while attempting to lock the key interface.
-**/
-EFI_STATUS
-EFIAPI
-LockVariableKeyInterface (
- VOID
+ OUT VOID *VariableKey,
+ IN UINTN VariableKeySize
);
#endif
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 13/28] SecurityPkg: Fix GetVariableKey API
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (11 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 12/28] SecurityPkg: Add new variable types and functions Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-22 14:15 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 14/28] SecurityPkg: Add null encryption variable libs Judah Vang
` (16 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Fix GetVariableKey API to match changes in header files.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c b/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c
index a08def767b5f..cfbad54ba106 100644
--- a/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c
+++ b/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c
@@ -1,7 +1,7 @@
/** @file
Null version of VariableKeyLib for build purpose. Don't use it in real product.
-Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -22,8 +22,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
EFI_STATUS
EFIAPI
GetVariableKey (
- OUT VOID **VariableKey,
- IN OUT UINTN *VariableKeySize
+ OUT VOID *VariableKey,
+ IN UINTN VariableKeySize
)
{
ASSERT (FALSE);
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 14/28] SecurityPkg: Add null encryption variable libs
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (12 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 13/28] SecurityPkg: Fix GetVariableKey API Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-22 14:20 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 15/28] SecurityPkg: Add VariableKey library function Judah Vang
` (15 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Provide null ecryption variable libraries.
These will be used by default for platforms that don't
support protected variable encryption.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf | 38 +++++++
SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c | 107 ++++++++++++++++++++
SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni | 16 +++
3 files changed, 161 insertions(+)
diff --git a/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
new file mode 100644
index 000000000000..ff5631b336eb
--- /dev/null
+++ b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
@@ -0,0 +1,38 @@
+## @file
+# Provides NULL version of encryption variable services.
+#
+# Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EncryptionVariableLibNull
+ MODULE_UNI_FILE = EncryptionVariableLib.uni
+ FILE_GUID = 3972E6FE-74D5-45C3-A9FB-DB9E5E5C9C17
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = EncryptionVariableLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ EncryptionVariable.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+
+[Guids]
+
diff --git a/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
new file mode 100644
index 000000000000..58a4ae9f4282
--- /dev/null
+++ b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
@@ -0,0 +1,107 @@
+/** @file
+ The common variable operation routines shared by DXE_RUNTIME variable
+ module and DXE_SMM variable module.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable data. They may be input in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ VariableServiceGetNextVariableName () and VariableServiceQueryVariableInfo() are external API.
+ They need check input parameter.
+
+ VariableServiceGetVariable() and VariableServiceSetVariable() are external API
+ to receive datasize and data buffer. The size should be checked carefully.
+
+ VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,
+ integer overflow. It should also check attribute to avoid authentication bypass.
+
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Library/EncryptionVariableLib.h>
+#include <Library/DebugLib.h>
+
+/**
+ Encrypt variable data.
+
+ Null version.
+
+ @param[in, out] VarEncInfo Pointer to structure containing detailed
+ information about a variable.
+
+ @retval EFI_UNSUPPORTED Unsupported to encrypt variable.
+
+**/
+EFI_STATUS
+EFIAPI
+EncryptVariable (
+ IN OUT VARIABLE_ENCRYPTION_INFO *VarEncInfo
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Decrypt variable data.
+
+ Null version.
+
+ @param[in, out] VarEncInfo Pointer to structure containing detailed
+ information about a variable.
+
+ @retval EFI_UNSUPPORTED Unsupported to encrypt variable.
+
+**/
+EFI_STATUS
+EFIAPI
+DecryptVariable (
+ IN OUT VARIABLE_ENCRYPTION_INFO *VarEncInfo
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Get cipher information.
+
+ Null version.
+
+ @param[in] VarEncInfo Pointer to structure containing detailed
+ information about a variable.
+
+ @retval EFI_UNSUPPORTED Unsupported interface.
+
+**/
+EFI_STATUS
+EFIAPI
+GetCipherDataInfo (
+ IN VARIABLE_ENCRYPTION_INFO *VarEncInfo
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Set cipher information for a variable.
+
+ Null version.
+
+ @param[in] VarEncInfo Pointer to structure containing detailed
+ information about a variable.
+
+ @retval EFI_UNSUPPORTED If this method is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SetCipherDataInfo (
+ IN VARIABLE_ENCRYPTION_INFO *VarEncInfo
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni
new file mode 100644
index 000000000000..856fa201b8df
--- /dev/null
+++ b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Provides authenticated variable services.
+//
+// Provides authenticated variable services.
+//
+// Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides authenticated variable services"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides authenticated variable services."
+
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 15/28] SecurityPkg: Add VariableKey library function
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (13 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 14/28] SecurityPkg: Add null encryption variable libs Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-04-29 18:04 ` [Patch v2 16/28] SecurityPkg: Add EncryptionVariable lib with AES Judah Vang
` (14 subsequent siblings)
29 siblings, 0 replies; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Provide function that retrieves the key for protected
variables.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf | 36 ++++++++++++
SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c | 59 ++++++++++++++++++++
2 files changed, 95 insertions(+)
diff --git a/SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf b/SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
new file mode 100644
index 000000000000..f62c80ce9943
--- /dev/null
+++ b/SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
@@ -0,0 +1,36 @@
+## @file
+# Provides default implementation of VariableKeyLib.
+#
+# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010029
+ BASE_NAME = VariableKeyLib
+ FILE_GUID = 7DF5A0BA-1DBB-4E67-A9F7-9FCCB1F9D250
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = VariableKeyLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 Arm AArch64
+#
+
+[Sources]
+ VariableKeyLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+
+[PpiS]
+ gKeyServicePpiGuid ## CONSUMES
+
diff --git a/SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c b/SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c
new file mode 100644
index 000000000000..31b22782cb0c
--- /dev/null
+++ b/SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c
@@ -0,0 +1,59 @@
+/** @file
+ VariableKeyLib implementation.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <Library/PeiServicesLib.h>
+#include <Library/DebugLib.h>
+#include <Library/VariableKeyLib.h>
+
+#include <Ppi/KeyServicePpi.h>
+
+#define VAR_KEY_SALT L"Key for RPMC Variable"
+#define VAR_KEY_SALT_SIZE sizeof (VAR_KEY_SALT)
+
+/**
+ Retrieves the key for integrity and/or confidentiality of variables.
+
+ @param[out] VariableKey A pointer to pointer for the variable key buffer.
+ @param[in] VariableKeySize The size in bytes of the variable key.
+
+ @retval EFI_SUCCESS The variable key was returned.
+ @retval EFI_DEVICE_ERROR An error occurred while attempting to get the variable key.
+ @retval EFI_ACCESS_DENIED The function was invoked after locking the key interface.
+ @retval EFI_UNSUPPORTED The variable key is not supported in the current boot configuration.
+**/
+EFI_STATUS
+EFIAPI
+GetVariableKey (
+ OUT VOID *VariableKey,
+ IN UINTN VariableKeySize
+ )
+{
+ EFI_STATUS Status;
+ KEY_SERVICE_PPI *KeyService;
+
+ Status = PeiServicesLocatePpi (
+ &gKeyServicePpiGuid,
+ 0,
+ NULL,
+ (void **)&KeyService
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ Status = KeyService->GenerateKey (
+ (UINT8 *)VAR_KEY_SALT,
+ VAR_KEY_SALT_SIZE,
+ VariableKey,
+ VariableKeySize
+ );
+ return Status;
+}
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 16/28] SecurityPkg: Add EncryptionVariable lib with AES
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (14 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 15/28] SecurityPkg: Add VariableKey library function Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-04-29 18:04 ` [Patch v2 17/28] SecurityPkg: Add Protected Variable Services Judah Vang
` (13 subsequent siblings)
29 siblings, 0 replies; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add encryption/decryption of protected variable functionality.
Add functions to get/set cipher data of a protected variable.
This is use for supporting confidentiality for protected
variables.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf | 43 ++
SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h | 49 ++
SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c | 728 ++++++++++++++++++++
3 files changed, 820 insertions(+)
diff --git a/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
new file mode 100644
index 000000000000..7ece52f2fb58
--- /dev/null
+++ b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
@@ -0,0 +1,43 @@
+## @file
+# Provides variable encryption/decryption services.
+#
+# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010029
+ BASE_NAME = EncryptionVariableLib
+ FILE_GUID = 459E2CB0-AF4B-4415-B6A1-335E71FD8B85
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = EncryptionVariableLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ EncryptionVariable.c
+ EncryptionVariable.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ BaseCryptLib
+
+[Guids]
+ gEfiVariableGuid
+ gEfiAuthenticatedVariableGuid
diff --git a/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
new file mode 100644
index 000000000000..f35f9f9e3ad7
--- /dev/null
+++ b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
@@ -0,0 +1,49 @@
+/** @file
+ Definitions used by this library implementation.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef ENCRYPTION_VARIABLE_H_
+#define ENCRYPTION_VARIABLE_H_
+
+#define ENC_KEY_SEP L":"
+#define ENC_KEY_SEP_SIZE 2
+#define ENC_KEY_NAME L"VAR_ENC_KEY"
+#define ENC_KEY_NAME_SIZE 22
+
+#define ENC_KEY_SIZE (256/8)
+#define ENC_BLOCK_SIZE AES_BLOCK_SIZE
+#define ENC_IVEC_SIZE ENC_BLOCK_SIZE
+
+#define ENC_PADDING_BYTE 0x0F
+
+//
+// PKCS#5 padding
+//
+// #define AES_CIPHER_DATA_SIZE(PlainDataSize)
+// (AES_BLOCK_SIZE + (PlainDataSize)) & (~(AES_BLOCK_SIZE - 1))
+//
+#define AES_CIPHER_DATA_SIZE(PlainDataSize) ALIGN_VALUE (PlainDataSize, AES_BLOCK_SIZE)
+
+#define FREE_POOL(Address) \
+ if ((Address) != NULL) { \
+ FreePool (Address); \
+ (Address) = NULL; \
+ }
+
+#pragma pack(1)
+
+typedef struct {
+ UINT32 DataType; // SYM_TYPE_AES
+ UINT32 HeaderSize; // sizeof(VARIABLE_ENCRYPTION_HEADER)
+ UINT32 PlainDataSize; // Plain data size
+ UINT32 CipherDataSize; // Cipher data size
+ UINT8 KeyIvec[ENC_IVEC_SIZE];
+} VARIABLE_ENCRYPTION_HEADER;
+
+#pragma pack()
+
+#endif // _ENCRYPTION_VARIABLE_H_
diff --git a/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
new file mode 100644
index 000000000000..58ffb09e0373
--- /dev/null
+++ b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
@@ -0,0 +1,728 @@
+/** @file
+ Implementation of EncryptionVariableLib with AES algorithm support.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Guid/VariableFormat.h>
+#include <Library/EncryptionVariableLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+
+#include "EncryptionVariable.h"
+
+/**
+ Derive encryption key for given variable from variable root key.
+
+ The derivation algorithm is depicted below
+
+ HKDF_Expand(SHA256, RootKey, Name||':'||Guid||':'||Attr||"VAR_ENC_KEY")
+
+ @param[in] VarEncInfo Pointer to structure containing detailed
+ information about a variable.
+ @param[in] EncKeySize Size of key requested.
+ @param[out] EncKey Buffer of key.
+
+ @retval TRUE The key was derived successfully.
+ @retval FALSE Failed to generate encryption key.
+
+**/
+STATIC
+BOOLEAN
+EncVarLibGenEncKey (
+ IN VARIABLE_ENCRYPTION_INFO *VarEncInfo,
+ IN UINTN EncKeySize,
+ OUT UINT8 *EncKey
+ )
+{
+ BOOLEAN Status;
+
+ struct {
+ VOID *Data;
+ UINTN Size;
+ } InfoGroup[6];
+ UINT8 *Info;
+ UINTN InfoSize;
+ UINTN Index;
+ UINT8 Salt[16];
+
+ //
+ // info: Name||':'||Guid||':'||Attr||"VAR_ENC_KEY"
+ //
+ InfoGroup[0].Size = VarEncInfo->Header.NameSize;
+ InfoGroup[0].Data = VarEncInfo->Header.VariableName;
+
+ InfoGroup[1].Size = ENC_KEY_SEP_SIZE;
+ InfoGroup[1].Data = ENC_KEY_SEP;
+
+ InfoGroup[2].Size = sizeof (*VarEncInfo->Header.VendorGuid);
+ InfoGroup[2].Data = VarEncInfo->Header.VendorGuid;
+
+ InfoGroup[3].Size = ENC_KEY_SEP_SIZE;
+ InfoGroup[3].Data = ENC_KEY_SEP;
+
+ InfoGroup[4].Size = sizeof (VarEncInfo->Header.Attributes);
+ InfoGroup[4].Data = &VarEncInfo->Header.Attributes;
+
+ InfoGroup[5].Size = ENC_KEY_NAME_SIZE;
+ InfoGroup[5].Data = ENC_KEY_NAME;
+
+ for (InfoSize = 0, Index = 0; Index < ARRAY_SIZE (InfoGroup); ++Index) {
+ InfoSize += InfoGroup[Index].Size;
+ }
+
+ Info = AllocateZeroPool (InfoSize);
+ if (Info == NULL) {
+ ASSERT (Info != NULL);
+ return FALSE;
+ }
+
+ for (InfoSize = 0, Index = 0; Index < ARRAY_SIZE (InfoGroup); ++Index) {
+ CopyMem (Info + InfoSize, InfoGroup[Index].Data, InfoGroup[Index].Size);
+ InfoSize += InfoGroup[Index].Size;
+ }
+
+ Status = HkdfSha256ExtractAndExpand (
+ VarEncInfo->Key,
+ VarEncInfo->KeySize,
+ Salt,
+ 0,
+ Info,
+ InfoSize,
+ EncKey,
+ EncKeySize
+ );
+
+ FreePool (Info);
+
+ return Status;
+}
+
+/**
+ Generate init-vector for AES encryption.
+
+ @param[out] InitVector IVEC buffer.
+ @param[in] Size Size of IVEC requested.
+
+ @retval TRUE IVEC was generated successfully.
+ @retval FALSE Failed to generate IVEC.
+
+**/
+STATIC
+BOOLEAN
+EncVarLibGenIvec (
+ OUT UINT8 *InitVector,
+ IN UINTN Size
+ )
+{
+ return RandomBytes (InitVector, Size);
+}
+
+/**
+ Check if there's valid variable information needed by encrypting or decrypting.
+
+ @param[in] VarEncInfo Buffer conveying details about a variable.
+ @param[in] CheckForEnc Flag indicating check for encrypting (TRUE) or
+ decrypting (FALSE).
+
+ @retval TRUE VarEncInfo is valid.
+ @retval FALSE VarEncInfo is invalid.
+
+**/
+STATIC
+BOOLEAN
+IsValidVariableInfo (
+ IN VARIABLE_ENCRYPTION_INFO *VarEncInfo,
+ IN BOOLEAN CheckForEnc
+ )
+{
+ BOOLEAN Valid;
+
+ if (CheckForEnc) {
+ Valid = (VarEncInfo->Header.Data != NULL && VarEncInfo->Header.DataSize > 0)
+ || (VarEncInfo->PlainData != NULL && VarEncInfo->PlainDataSize > 0);
+ if (!Valid) {
+ ASSERT (
+ (VarEncInfo->Header.Data != NULL && VarEncInfo->Header.DataSize > 0)
+ || (VarEncInfo->PlainData != NULL && VarEncInfo->PlainDataSize > 0)
+ );
+ }
+ } else {
+ Valid = (VarEncInfo->Header.Data != NULL && VarEncInfo->Header.DataSize > 0)
+ || (VarEncInfo->CipherData != NULL && VarEncInfo->CipherDataSize > 0);
+ if (!Valid) {
+ ASSERT (
+ (VarEncInfo->Header.Data != NULL && VarEncInfo->Header.DataSize > 0)
+ || (VarEncInfo->CipherData != NULL && VarEncInfo->CipherDataSize > 0)
+ );
+ }
+ }
+
+ Valid = Valid
+ && VarEncInfo->Header.VariableName != NULL
+ && VarEncInfo->Header.NameSize > 0
+ && VarEncInfo->Header.VendorGuid != NULL
+ && VarEncInfo->Key != NULL
+ && VarEncInfo->KeySize > 0;
+ if (!Valid) {
+ ASSERT (VarEncInfo->Header.VariableName != NULL);
+ ASSERT (VarEncInfo->Header.NameSize != 0);
+ ASSERT (VarEncInfo->Header.VendorGuid != NULL);
+ ASSERT (VarEncInfo->Key != NULL);
+ ASSERT (VarEncInfo->KeySize > 0);
+ }
+
+ return Valid;
+}
+
+/**
+ Sanity check of encrption header prefixed to encrypted data.
+
+ @param[in] EncHeader Pointer to VARIABLE_ENCRYPTION_HEADER.
+ @param[in] DataSize Size of variable data payload.
+
+ @retval TRUE EncHeader is valid.
+ @retval FALSE EncHeader is invalid.
+
+**/
+STATIC
+BOOLEAN
+IsValidEncrptionHeader (
+ IN VARIABLE_ENCRYPTION_HEADER *EncHeader,
+ IN UINT32 DataSize
+ )
+{
+ if ( (DataSize > sizeof (VARIABLE_ENCRYPTION_HEADER))
+ && ((EncHeader->DataType == ENC_TYPE_AES) || (EncHeader->DataType == ENC_TYPE_NULL))
+ && (EncHeader->HeaderSize >= sizeof (VARIABLE_ENCRYPTION_HEADER))
+ && (EncHeader->CipherDataSize > 0)
+ && ((EncHeader->CipherDataSize % ENC_BLOCK_SIZE) == 0)
+ && (EncHeader->PlainDataSize > 0)
+ && (EncHeader->PlainDataSize <= EncHeader->CipherDataSize)
+ && ((EncHeader->CipherDataSize + EncHeader->HeaderSize) <= DataSize))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Encrypt variable data.
+
+ If VarEncInfo->PlainData is not NULL, VarEncInfo->PlainData holds the plain
+ data. Otherwise, VarEncInfo->Headr.Data is supposed to be the plain data.
+
+ If VarEncInfo->CipherData is not NULL, The encrypted data is stored in
+ VarEncInfo->CipherData. Otherwise, the encrypted data is stored directly
+ in variable data buffer, i.e. VarEncInfo->Headr.Data.
+
+ @param[in, out] VarEncInfo Pointer to structure containing detailed
+ information about a variable.
+
+ @retval EFI_SUCCESS Variable was encrypted successfully.
+ @retval EFI_INVALID_PARAMETER Variable information in VarEncInfo is invalid.
+ @retval EFI_BUFFER_TOO_SMALL VarEncInfo->CipherData is not NULL but
+ VarEncInfo->CipherDataSize is too small.
+ @retval EFI_ABORTED Uknown error occurred during encrypting.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
+ @retval EFI_UNSUPPORTED Unsupported to encrypt variable.
+
+**/
+EFI_STATUS
+EFIAPI
+EncryptVariable (
+ IN OUT VARIABLE_ENCRYPTION_INFO *VarEncInfo
+ )
+{
+ EFI_STATUS Status;
+ VOID *AesContext;
+ UINT8 EncKey[ENC_KEY_SIZE];
+ UINT8 Ivec[ENC_IVEC_SIZE];
+ UINT8 *PlainBuffer;
+ UINT8 *CipherBuffer;
+ UINT8 *PlainData;
+ UINT32 PlainDataSize;
+ VARIABLE_ENCRYPTION_HEADER *CipherData;
+ UINT32 CipherDataSize;
+ UINT32 PaddingBytes;
+
+ Status = EFI_ABORTED;
+ AesContext = NULL;
+ PlainBuffer = NULL;
+ CipherBuffer = NULL;
+
+ if (!IsValidVariableInfo (VarEncInfo, TRUE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VarEncInfo->PlainData != NULL) {
+ PlainData = VarEncInfo->PlainData;
+ PlainDataSize = VarEncInfo->PlainDataSize;
+ } else {
+ PlainData = VarEncInfo->Header.Data;
+ PlainDataSize = (UINT32)VarEncInfo->Header.DataSize;
+ }
+
+ CipherDataSize = AES_CIPHER_DATA_SIZE (PlainDataSize);
+ if (VarEncInfo->CipherData != NULL) {
+ if (VarEncInfo->CipherDataSize
+ < (CipherDataSize + sizeof (VARIABLE_ENCRYPTION_HEADER)))
+ {
+ VarEncInfo->CipherDataSize = CipherDataSize
+ + sizeof (VARIABLE_ENCRYPTION_HEADER);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ CipherData = VarEncInfo->CipherData;
+ } else {
+ CipherData = VarEncInfo->Header.Data;
+ }
+
+ //
+ // Prepare buffer for encrypted data.
+ //
+ if ((UINTN)CipherData == (UINTN)PlainData) {
+ //
+ // Need buffer to store the encrypted data temporarily.
+ //
+ CipherBuffer = (UINT8 *)AllocateZeroPool (
+ CipherDataSize
+ + sizeof (VARIABLE_ENCRYPTION_HEADER)
+ );
+ if (CipherBuffer == NULL) {
+ ASSERT (CipherBuffer != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ CipherBuffer = (UINT8 *)CipherData;
+ }
+
+ //
+ // Plain variable data must also be multiple of ENC_BLOCK_SIZE.
+ //
+ PaddingBytes = ALIGN_VALUE (PlainDataSize, ENC_BLOCK_SIZE) - PlainDataSize;
+ if (PaddingBytes != 0) {
+ //
+ // Since the plain data size will be saved in the VARIABLE_ENCRYPTION_HEADER,
+ // there's no need to do PKCS way of padding. To save space, just padding
+ // the plain data to be of the nearest n*ENC_BLOCK_SIZE.
+ //
+ PlainBuffer = AllocateZeroPool (PlainDataSize + PaddingBytes);
+ if (PlainBuffer == NULL) {
+ ASSERT (PlainBuffer != NULL);
+ goto Done;
+ }
+
+ CopyMem (PlainBuffer, PlainData, PlainDataSize);
+ SetMem (PlainBuffer + PlainDataSize, PaddingBytes, ENC_PADDING_BYTE);
+ } else {
+ PlainBuffer = PlainData;
+ }
+
+ //
+ // Skip EFI_VARIABLE_APPEND_WRITE bit in generating encryption key.
+ //
+ VarEncInfo->Header.Attributes &= (~EFI_VARIABLE_APPEND_WRITE);
+ if (!EncVarLibGenEncKey (VarEncInfo, ENC_KEY_SIZE, EncKey)) {
+ ASSERT (FALSE);
+ return EFI_ABORTED;
+ }
+
+ if (!EncVarLibGenIvec (Ivec, ENC_IVEC_SIZE)) {
+ ASSERT (FALSE);
+ return EFI_ABORTED;
+ }
+
+ AesContext = AllocateZeroPool (AesGetContextSize ());
+ if (AesContext == NULL) {
+ ASSERT (AesContext != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (!AesInit (AesContext, EncKey, ENC_KEY_SIZE * 8)) {
+ ASSERT (FALSE);
+ goto Done;
+ }
+
+ if (AesCbcEncrypt (
+ AesContext,
+ PlainBuffer,
+ PlainDataSize + PaddingBytes,
+ Ivec,
+ CipherBuffer + sizeof (VARIABLE_ENCRYPTION_HEADER)
+ ))
+ {
+ //
+ // Keep the IV for decryption.
+ //
+ CopyMem (CipherData->KeyIvec, Ivec, ENC_BLOCK_SIZE);
+
+ if ((UINTN)CipherBuffer != (UINTN)CipherData) {
+ CopyMem (
+ CipherData + 1,
+ CipherBuffer + sizeof (VARIABLE_ENCRYPTION_HEADER),
+ CipherDataSize
+ );
+ }
+
+ CipherData->CipherDataSize = CipherDataSize;
+ CipherData->PlainDataSize = PlainDataSize;
+ CipherData->DataType = ENC_TYPE_AES;
+ CipherData->HeaderSize = sizeof (VARIABLE_ENCRYPTION_HEADER);
+
+ VarEncInfo->CipherData = CipherData;
+ VarEncInfo->CipherDataSize = CipherDataSize + sizeof (VARIABLE_ENCRYPTION_HEADER);
+ VarEncInfo->CipherHeaderSize = sizeof (VARIABLE_ENCRYPTION_HEADER);
+ VarEncInfo->CipherDataType = ENC_TYPE_AES;
+
+ Status = EFI_SUCCESS;
+ } else {
+ VarEncInfo->CipherData = NULL;
+ VarEncInfo->CipherDataSize = 0;
+ VarEncInfo->CipherHeaderSize = 0;
+ VarEncInfo->CipherDataType = ENC_TYPE_NULL;
+
+ ASSERT (FALSE);
+ }
+
+Done:
+ FREE_POOL (AesContext);
+ if (PlainBuffer != PlainData) {
+ FREE_POOL (PlainBuffer);
+ }
+
+ if (CipherBuffer != (UINT8 *)CipherData) {
+ FREE_POOL (CipherBuffer);
+ }
+
+ return Status;
+}
+
+/**
+ Decrypt variable data.
+
+ If VarEncInfo->CipherData is not NULL, it must holds the cipher data to be
+ decrypted. Otherwise, assume the cipher data from variable data buffer, i.e.
+ VarEncInfo->Header.Data.
+
+ If VarEncInfo->Flags.DecryptInPlace is TRUE, the decrypted data will be put
+ back in the same buffer as cipher buffer got above, after encryption header,
+ which helps to identify later if the data in buffer is decrypted or not. This
+ can avoid repeat decryption when accessing the same variable more than once.
+
+ If VarEncInfo->Flags.DecryptInPlace is FALSE, VarEncInfo->PlainData must be
+ passed in with a valid buffer with VarEncInfo->PlainDataSize set correctly
+ with its size.
+
+ Note the VarEncInfo->PlainData is always pointing to the buffer address with
+ decrypted data without encryption header, and VarEncInfo->PlainDataSize is
+ always the size of original variable data, if this function returned
+ successfully.
+
+ @param[in, out] VarEncInfo Pointer to structure containing detailed
+ information about a variable.
+
+ @retval EFI_SUCCESS Variable was decrypted successfully.
+ @retval EFI_INVALID_PARAMETER Variable information in VarEncInfo is invalid.
+ @retval EFI_BUFFER_TOO_SMALL VarEncInfo->PlainData is not NULL but
+ VarEncInfo->PlainDataSize is too small.
+ @retval EFI_ABORTED Uknown error occurred during decrypting.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
+ @retval EFI_COMPROMISED_DATA The cipher header is not valid.
+ @retval EFI_UNSUPPORTED Unsupported to encrypt variable.
+
+**/
+EFI_STATUS
+EFIAPI
+DecryptVariable (
+ IN OUT VARIABLE_ENCRYPTION_INFO *VarEncInfo
+ )
+{
+ VOID *AesContext;
+ UINT8 EncKey[ENC_KEY_SIZE];
+ UINT8 *PlainBuffer;
+ UINT8 *PlainData;
+ VARIABLE_ENCRYPTION_HEADER *CipherData;
+ UINT32 CipherDataSize;
+ EFI_STATUS Status;
+
+ Status = EFI_ABORTED;
+ AesContext = NULL;
+ PlainBuffer = NULL;
+
+ if (!IsValidVariableInfo (VarEncInfo, FALSE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VarEncInfo->CipherData != NULL) {
+ CipherData = VarEncInfo->CipherData;
+ CipherDataSize = VarEncInfo->CipherDataSize;
+ } else {
+ CipherData = VarEncInfo->Header.Data;
+ CipherDataSize = (UINT32)VarEncInfo->Header.DataSize;
+ }
+
+ //
+ // Sanity check of cipher header.
+ //
+ if (!IsValidEncrptionHeader (CipherData, CipherDataSize)) {
+ return EFI_COMPROMISED_DATA;
+ }
+
+ if ( (VarEncInfo->PlainData != NULL)
+ && (VarEncInfo->PlainDataSize < CipherData->PlainDataSize))
+ {
+ VarEncInfo->PlainDataSize = CipherData->PlainDataSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (CipherData->DataType == ENC_TYPE_AES) {
+ if (VarEncInfo->Flags.DecryptInPlace) {
+ //
+ // Reusing cipher data buffer needs to keep the encryption header.
+ //
+ PlainData = (UINT8 *)CipherData + CipherData->HeaderSize;
+ } else {
+ PlainData = VarEncInfo->PlainData;
+ }
+
+ if (PlainData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Always need buffer to store the decrypted data temporarily, due to
+ // padding bytes or buffer reuse. Then the buffer must be larger than
+ // CipherData->PlainDataSize.
+ //
+ PlainBuffer = AllocatePages (EFI_SIZE_TO_PAGES (CipherDataSize));
+ if (PlainBuffer == NULL) {
+ ASSERT (PlainBuffer != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (!EncVarLibGenEncKey (VarEncInfo, ENC_KEY_SIZE, EncKey)) {
+ ASSERT (FALSE);
+ goto Done;
+ }
+
+ AesContext = AllocatePages (EFI_SIZE_TO_PAGES (AesGetContextSize ()));
+ if (AesContext == NULL) {
+ ASSERT (AesContext != NULL);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ if (!AesInit (AesContext, EncKey, ENC_KEY_SIZE * 8)) {
+ ASSERT (FALSE);
+ goto Done;
+ }
+
+ if (AesCbcDecrypt (
+ AesContext,
+ (UINT8 *)CipherData + CipherData->HeaderSize,
+ CipherDataSize - CipherData->HeaderSize,
+ CipherData->KeyIvec,
+ PlainBuffer
+ ))
+ {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_COMPROMISED_DATA;
+ }
+ } else {
+ //
+ // The data has been decrypted already.
+ //
+ PlainBuffer = (UINT8 *)CipherData + CipherData->HeaderSize;
+
+ if (VarEncInfo->PlainData != NULL) {
+ PlainData = VarEncInfo->PlainData;
+ } else {
+ PlainData = PlainBuffer;
+ }
+
+ Status = EFI_SUCCESS;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ if (PlainBuffer != PlainData) {
+ CopyMem (PlainData, PlainBuffer, CipherData->PlainDataSize);
+ }
+
+ if (VarEncInfo->PlainData != NULL) {
+ if (VarEncInfo->PlainData != PlainBuffer) {
+ CopyMem (VarEncInfo->PlainData, PlainBuffer, CipherData->PlainDataSize);
+ }
+ } else {
+ VarEncInfo->PlainData = PlainData;
+ }
+
+ VarEncInfo->PlainDataSize = CipherData->PlainDataSize;
+ VarEncInfo->CipherHeaderSize = CipherData->HeaderSize;
+ VarEncInfo->CipherDataType = CipherData->DataType;
+
+ if (VarEncInfo->Flags.DecryptInPlace) {
+ CipherData->DataType = ENC_TYPE_NULL;
+ }
+ }
+
+Done:
+ FreePages (PlainBuffer, EFI_SIZE_TO_PAGES ((CipherDataSize)));
+ FreePages (AesContext, EFI_SIZE_TO_PAGES (AesGetContextSize ()));
+ return Status;
+}
+
+/**
+ Get cipher information about a variable, including plaindata size,
+ cipher algorithm type, etc.
+
+ For data passed in with VarEncInfo,
+
+ VarEncInfo->Header.Data
+ - The variable data in normal variable structure.
+ VarEncInfo->Header.DataSize
+ - The size of variable data.
+
+ For data passed out with VarEncInfo (valid only if EFI_SUCCESS is returned),
+
+ VarEncInfo->CipherDataType
+ - ENC_TYPE_NULL, if the variable is not encrypted or has been decrypted;
+ - ENC_TYPE_AES, if the variable is encrypted.
+ VarEncInfo->CipherHeaderSize
+ - Size of cipher header put before encrypted or decrypted data.
+ VarEncInfo->PlainData
+ - NULL, if the variable is encrypted; Or
+ - pointer to original variable data, if the variable has been decrypted.
+ VarEncInfo->PlainDataSize
+ - The size of original variable data
+ VarEncInfo->CipherData
+ - NULL, if the variable is decrypted; Or
+ - pointer to start of encrypted variable data, including encryption header;
+ VarEncInfo->CipherDataSize
+ - The size of encrypted variable data, including encryption header.
+
+ @param[in] VarEncInfo Pointer to structure containing detailed
+ information about a variable.
+
+ @retval EFI_SUCCESS The information was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER Variable information in VarEncInfo is invalid.
+ @retval EFI_NOT_FOUND No cipher information recognized.
+ @retval EFI_UNSUPPORTED Unsupported interface.
+
+**/
+EFI_STATUS
+EFIAPI
+GetCipherDataInfo (
+ IN VARIABLE_ENCRYPTION_INFO *VarEncInfo
+ )
+{
+ VARIABLE_ENCRYPTION_HEADER *EncHeader;
+
+ if ((VarEncInfo->Header.Data == NULL) || (VarEncInfo->Header.DataSize == 0)) {
+ ASSERT (VarEncInfo->Header.Data != NULL);
+ ASSERT (VarEncInfo->Header.DataSize != 0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Validate encryption header.
+ //
+ EncHeader = (VARIABLE_ENCRYPTION_HEADER *)VarEncInfo->Header.Data;
+ if (!IsValidEncrptionHeader (EncHeader, (UINT32)VarEncInfo->Header.DataSize)) {
+ //
+ // Not an encrypted variable.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ if (EncHeader->DataType == ENC_TYPE_NULL) {
+ //
+ // The data must have been decrypted.
+ //
+ VarEncInfo->PlainData = (UINT8 *)VarEncInfo->Header.Data + EncHeader->HeaderSize;
+ VarEncInfo->CipherData = NULL;
+ VarEncInfo->Flags.DecryptInPlace = TRUE;
+ } else {
+ //
+ // The data is encrypted.
+ //
+ VarEncInfo->CipherData = VarEncInfo->Header.Data;
+ VarEncInfo->PlainData = NULL;
+ VarEncInfo->Flags.DecryptInPlace = FALSE;
+ }
+
+ VarEncInfo->PlainDataSize = EncHeader->PlainDataSize;
+ VarEncInfo->CipherDataSize = EncHeader->CipherDataSize + EncHeader->HeaderSize;
+ VarEncInfo->CipherDataType = EncHeader->DataType;
+ VarEncInfo->CipherHeaderSize = EncHeader->HeaderSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Force set cipher information for a variable, like plaindata size,
+ cipher algorithm type, cipher data etc.
+
+ The destination buffer must be passed via VarEncInfo->Header.Data.
+
+ This method is only used to update and/or change plain data information.
+
+ @param[in] VarEncInfo Pointer to structure containing detailed
+ information about a variable.
+
+ @retval EFI_SUCCESS The information was updated successfully.
+ @retval EFI_INVALID_PARAMETER Variable information in VarEncInfo is invalid.
+ @retval EFI_UNSUPPORTED If this method is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SetCipherDataInfo (
+ IN VARIABLE_ENCRYPTION_INFO *VarEncInfo
+ )
+{
+ VARIABLE_ENCRYPTION_HEADER *EncHeader;
+ UINT8 *Data;
+
+ if ( (VarEncInfo->Header.Data == NULL)
+ || (VarEncInfo->Header.DataSize < sizeof (VARIABLE_ENCRYPTION_HEADER))
+ || (VarEncInfo->CipherDataType != ENC_TYPE_NULL))
+ {
+ ASSERT (VarEncInfo->Header.Data != NULL);
+ ASSERT (VarEncInfo->Header.DataSize >= sizeof (VARIABLE_ENCRYPTION_HEADER));
+ ASSERT (VarEncInfo->CipherDataType == ENC_TYPE_NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data = VarEncInfo->Header.Data;
+ EncHeader = (VARIABLE_ENCRYPTION_HEADER *)Data;
+
+ if ( !IsValidEncrptionHeader (EncHeader, (UINT32)VarEncInfo->Header.DataSize)
+ || (VarEncInfo->PlainDataSize > EncHeader->CipherDataSize))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((VarEncInfo->PlainData != NULL) && (VarEncInfo->PlainDataSize > 0)) {
+ CopyMem (
+ Data + EncHeader->HeaderSize,
+ VarEncInfo->PlainData,
+ VarEncInfo->PlainDataSize
+ );
+ }
+
+ EncHeader->DataType = VarEncInfo->CipherDataType;
+ if (VarEncInfo->PlainDataSize != 0) {
+ EncHeader->PlainDataSize = VarEncInfo->PlainDataSize;
+ }
+
+ return EFI_SUCCESS;
+}
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 17/28] SecurityPkg: Add Protected Variable Services
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (15 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 16/28] SecurityPkg: Add EncryptionVariable lib with AES Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-04-29 18:04 ` [Patch v2 18/28] MdeModulePkg: Reference Null ProtectedVariableLib Judah Vang
` (12 subsequent siblings)
29 siblings, 0 replies; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add Protected Variable Services across the different UEFI phases.
Functions includes creating variable digest, performing integrity
check, initializing protected variables, updating protected
variables, and verifying the MetaDataHmacVar variable.
This module prevents UEFI variable tampering. It provides
variable integrity and confidentiality.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf | 64 +
SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf | 68 +
SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf | 67 +
SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf | 62 +
SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h | 611 ++++++
SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c | 2095 ++++++++++++++++++++
SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c | 163 ++
SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c | 1331 +++++++++++++
SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c | 209 ++
SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c | 975 +++++++++
SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c | 233 +++
11 files changed, 5878 insertions(+)
diff --git a/SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf b/SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
new file mode 100644
index 000000000000..74a0285af7ef
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
@@ -0,0 +1,64 @@
+## @file
+# Provides protected variable services for EmulatorPkg.
+#
+# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010029
+ BASE_NAME = DxeProtectedVariableLib
+ MODULE_UNI_FILE = ProtectedVariableLib.uni
+ FILE_GUID = 6F424E10-0F75-4716-9F97-58C2E1C643AD
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 0.1
+ LIBRARY_CLASS = ProtectedVariableLib|DXE_RUNTIME_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ ProtectedVariableDxe.c
+ ProtectedVariableCommon.c
+ ProtectedVariableSmmDxeCommon.c
+ ProtectedVariableInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ HobLib
+ BaseCryptLib
+ EncryptionVariableLib
+ RpmcLib
+ HashApiLib
+ SortLib
+
+[Protocols]
+ gEfiVariableWriteArchProtocolGuid
+
+[Guids]
+ gEdkiiMetaDataHmacVariableGuid
+ gEdkiiProtectedVariableGlobalGuid
+ gEdkiiVarErrorFlagGuid
+ gEdkiiProtectedVariableContextGuid
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName
+ gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid
+ gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity
+ gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize
diff --git a/SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf b/SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
new file mode 100644
index 000000000000..44c959a94ca3
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
@@ -0,0 +1,68 @@
+## @file
+# Provides protected variable services.
+#
+# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010029
+ BASE_NAME = PeiProtectedVariableLib
+ MODULE_UNI_FILE = ProtectedVariableLib.uni
+ FILE_GUID = 76FBFBCE-ACBB-4084-A348-8FCC97AAEB9D
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 0.1
+ LIBRARY_CLASS = ProtectedVariableLib|PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+#
+
+[Sources]
+ ProtectedVariablePei.c
+ ProtectedVariableCommon.c
+ ProtectedVariableInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ HobLib
+ BaseCryptLib
+ RpmcLib
+ VariableKeyLib
+ EncryptionVariableLib
+ ReportStatusCodeLib
+ PeiServicesLib
+ HashApiLib
+ SortLib
+
+[Guids]
+ gEdkiiMetaDataHmacVariableGuid
+ gEdkiiProtectedVariableGlobalGuid
+ gEdkiiVarErrorFlagGuid
+ gEdkiiProtectedVariableContextGuid
+
+[Ppis]
+ gEfiPeiMemoryDiscoveredPpiGuid
+ gEfiPeiVariableStoreDiscoveredPpiGuid
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeVariableIntegrity
+ gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName
+ gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid
+ gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity
+ gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize
diff --git a/SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf b/SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
new file mode 100644
index 000000000000..ecf0b1a43d30
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
@@ -0,0 +1,67 @@
+## @file
+# Provides protected variable services.
+#
+# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010029
+ BASE_NAME = SmmProtectedVariableLib
+ MODULE_UNI_FILE = ProtectedVariableLib.uni
+ FILE_GUID = 2BEE71E5-259B-4057-A2C1-2115DF43C76A
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 0.1
+ LIBRARY_CLASS = ProtectedVariableLib|DXE_SMM_DRIVER MM_STANDALONE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ ProtectedVariableSmm.c
+ ProtectedVariableCommon.c
+ ProtectedVariableSmmDxeCommon.c
+ ProtectedVariableInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ HobLib
+ BaseCryptLib
+ EncryptionVariableLib
+ RpmcLib
+ VariableKeyLib
+ HashApiLib
+ SortLib
+
+[Protocols]
+ gEfiMmEndOfDxeProtocolGuid
+
+[Guids]
+ gSmmVariableWriteGuid
+ gEdkiiMetaDataHmacVariableGuid
+ gEdkiiProtectedVariableGlobalGuid
+ gEdkiiVarErrorFlagGuid
+ gEdkiiProtectedVariableContextGuid
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName
+ gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid
+ gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity
+ gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize
+
diff --git a/SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf b/SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf
new file mode 100644
index 000000000000..011ccdce2db8
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf
@@ -0,0 +1,62 @@
+## @file
+# Provides protected variable services.
+#
+# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010029
+ BASE_NAME = SmmRuntimeProtectedVariableLib
+ MODULE_UNI_FILE = ProtectedVariableLib.uni
+ FILE_GUID = 99A623DE-1AD3-4AB3-909D-E3AADD7845EF
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 0.1
+ LIBRARY_CLASS = ProtectedVariableLib|DXE_DRIVER DXE_RUNTIME_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ ProtectedVariableSmmRuntime.c
+ ProtectedVariableCommon.c
+ ProtectedVariableInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ HobLib
+ BaseCryptLib
+ EncryptionVariableLib
+ RpmcLib
+ HashApiLib
+ SortLib
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid
+ gEdkiiMetaDataHmacVariableGuid
+ gEdkiiProtectedVariableGlobalGuid
+ gEdkiiVarErrorFlagGuid
+ gEdkiiProtectedVariableContextGuid
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName
+ gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid
+ gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity
+ gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize
+
diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
new file mode 100644
index 000000000000..fd38b5bd2019
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
@@ -0,0 +1,611 @@
+/** @file
+ Definitions shared among different implementation of ProtectedVariableLib.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PROTECTED_VARIABLE_INTERNAL_H_
+#define PROTECTED_VARIABLE_INTERNAL_H_
+
+#include <Guid/VariableFormat.h>
+#include <Guid/ProtectedVariable.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/RpmcLib.h>
+#include <Library/VariableKeyLib.h>
+#include <Library/EncryptionVariableLib.h>
+#include <Library/ProtectedVariableLib.h>
+#include <Library/HashApiLib.h>
+
+#define VARIABLE_KEY_SIZE (256/8)
+
+#define METADATA_HMAC_SIZE (256/8)
+#define METADATA_HMAC_KEY_NAME L"HMAC_KEY"
+#define METADATA_HMAC_KEY_NAME_SIZE 0x10
+
+#define METADATA_HMAC_SEP L":"
+#define METADATA_HMAC_SEP_SIZE 2
+
+#define METADATA_HMAC_VARIABLE_NAME L"MetaDataHmacVar"
+#define METADATA_HMAC_VARIABLE_NAME_SIZE sizeof (METADATA_HMAC_VARIABLE_NAME)
+#define METADATA_HMAC_VARIABLE_GUID gEdkiiMetaDataHmacVariableGuid
+#define METADATA_HMAC_VARIABLE_ATTR VARIABLE_ATTRIBUTE_NV_BS_RT
+
+#define DIGEST_CONTEXT_SIZE (HashApiGetContextSize())
+
+#define MAX_VARIABLE_SIZE \
+ MAX (MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)), \
+ PcdGet32 (PcdMaxHardwareErrorVariableSize))
+
+#define IS_VARIABLE(Var, Name, Guid) \
+ (StrCmp ((Var)->VariableName, (Name)) == 0 \
+ && CompareGuid ((CONST EFI_GUID *)(Var)->VendorGuid, (CONST EFI_GUID *)(Guid)))
+
+#define VARIABLE_SIZE(VarInfo) \
+ (((UINTN)(VarInfo)->Header.Data - (UINTN)(VarInfo)->Buffer) \
+ + (VarInfo)->Header.DataSize \
+ + GET_PAD_SIZE ((VarInfo)->Header.DataSize))
+
+#define VARIABLE_HEADER_SIZE(AuthFlag) \
+ ((AuthFlag) ? sizeof (AUTHENTICATED_VARIABLE_HEADER) \
+ : sizeof (VARIABLE_HEADER))
+
+#define VARIABLE_NAME(Var, AuthFlag) \
+ ((CHAR16 *)((UINTN)(Var) + VARIABLE_HEADER_SIZE(AuthFlag)))
+
+#define VARIABLE_START(VarStore) \
+ ((VARIABLE_HEADER *)HEADER_ALIGN ((VARIABLE_STORE_HEADER *)(VarStore) + 1))
+
+#define VARIABLE_END(VarStore) \
+ ((VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)(VarStore) \
+ + ((VARIABLE_STORE_HEADER *)(VarStore))->Size))
+
+#define SET_VARIABLE_DATA_SIZE(VarInfo, Size) \
+ if ((VarInfo)->Flags.Auth) { \
+ ((AUTHENTICATED_VARIABLE_HEADER *)((VarInfo)->Buffer))->DataSize = Size; \
+ (VarInfo)->Header.DataSize = Size; \
+ } else { \
+ ((VARIABLE_HEADER *)((VarInfo)->Buffer))->DataSize = Size; \
+ (VarInfo)->Header.DataSize = Size; \
+ }
+
+#define IS_KNOWN_UNPROTECTED_VARIABLE(Global, VarInfo) \
+ (CheckKnownUnprotectedVariable ((Global), (VarInfo)) < UnprotectedVarIndexMax)
+
+#define GET_CNTX(Global) ((PROTECTED_VARIABLE_CONTEXT_IN *)(UINTN)((Global)->ContextIn))
+#define GET_BUFR(Address) ((VOID *)(UINTN)(Address))
+#define GET_ADRS(Buffer) ((EFI_PHYSICAL_ADDRESS)(UINTN)(Buffer))
+
+typedef struct _VARIABLE_IDENTIFIER {
+ CHAR16 *VariableName;
+ EFI_GUID *VendorGuid;
+ UINT8 State;
+} VARIABLE_IDENTIFIER;
+
+typedef enum {
+ IndexHmacInDel = 0, /// MetaDataHmacVar with state VAR_IN_DELETED_TRANSITION
+ IndexHmacAdded, /// MetaDataHmacVar with state VAR_ADDED
+ IndexErrorFlag, /// VarErrorFlag
+ IndexPlatformVar, /// Platform Variable
+ UnprotectedVarIndexMax
+} UNPROTECTED_VARIABLE_INDEX;
+
+#pragma pack(1)
+
+#define PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION 0x02
+
+typedef struct _PROTECTED_VARIABLE_FLAG {
+ BOOLEAN Auth; // Authenticated variable format
+ BOOLEAN WriteInit; // Write-init-done
+ BOOLEAN WriteReady; // Ready-to-write
+ BOOLEAN RecoveryMode; // Variable storage recovery or provisioning
+ BOOLEAN CacheReady; // Indicates Cache is available
+ BOOLEAN Reserved; // reserved
+} PROTECTED_VARIABLE_FLAG;
+
+typedef struct _PROTECTED_VARIABLE_GLOBAL {
+ UINT32 StructVersion;
+ UINT32 StructSize;
+
+ ///
+ /// Variable root key used to derive Encryption key and HMAC key.
+ ///
+ UINT8 RootKey[VARIABLE_KEY_SIZE];
+ ///
+ /// HMAC key derived from RootKey.
+ ///
+ UINT8 MetaDataHmacKey[VARIABLE_KEY_SIZE];
+ ///
+ /// Number of variables in linked list pointed by VariableDigests.
+ ///
+ UINT32 VariableNumber;
+ ///
+ /// Size of memory reserved by VariableCache.
+ ///
+ UINT32 VariableCacheSize;
+ ///
+ /// Memory reserved to temporarily hold data of one variable, for integrity
+ /// validation purpose.
+ ///
+ EFI_PHYSICAL_ADDRESS VariableCache;
+ ///
+ /// Pointer to linked list, in which each node holds the digest value of each
+ /// variable.
+ ///
+ EFI_PHYSICAL_ADDRESS VariableDigests;
+ ///
+ /// Memory reserved for Context used in hash API to avoid repeat alloc/free.
+ ///
+ EFI_PHYSICAL_ADDRESS DigestContext;
+ ///
+ /// Pointer to one of node in linked list pointed by VariableDigests, which
+ /// has been just accessed. This is mainly used to facilitate the two calls
+ /// use case of GetVariable().
+ ///
+ EFI_PHYSICAL_ADDRESS LastAccessedVariable;
+ ///
+ /// Cached copy of pointers to nodes of unprotected variables in the linked
+ /// list pointed by VariableDigests.
+ ///
+ EFI_PHYSICAL_ADDRESS Unprotected[UnprotectedVarIndexMax];
+ ///
+ /// Pointer to data structure holding helper functions passed by user of
+ /// ProtectedVariableLib, most of which are used to complete operations on
+ /// variable storage.
+ ///
+ EFI_PHYSICAL_ADDRESS ContextIn;
+
+ ///
+ /// Pointer to Global data structure. This is to hold pre-mem address value.
+ /// Later to be used to identify pre-mem to post-mem transition.
+ ///
+ EFI_PHYSICAL_ADDRESS GlobalSelf;
+
+ PROTECTED_VARIABLE_FLAG Flags;
+} PROTECTED_VARIABLE_GLOBAL;
+
+#pragma pack()
+
+/* Sort method function pointer taking two parameters */
+typedef
+INTN
+(*SORT_METHOD) (
+ IN VARIABLE_DIGEST *Variable1,
+ IN VARIABLE_DIGEST *Variable2
+ );
+
+/* Update variable digest data function pointer */
+typedef
+BOOLEAN
+(*DIGEST_UPDATE) (
+ IN OUT VOID *Context,
+ IN VOID *Data,
+ IN UINTN DataSize
+ );
+
+/**
+
+ Print variable information
+
+ @param[in] Data8 Pointer to data
+ @param[out] DataSize Size of data
+
+**/
+VOID
+PrintVariableData (
+ IN UINT8 *Data8,
+ IN UINTN DataSize
+ );
+
+/**
+
+ Derive HMAC key from given variable root key.
+
+ @param[in] RootKey Pointer to root key to derive from.
+ @param[in] RootKeySize Size of root key.
+ @param[out] HmacKey Pointer to generated HMAC key.
+ @param[in] HmacKeySize Size of HMAC key.
+
+ @retval TRUE The HMAC key is derived successfully.
+ @retval FALSE Failed to generate HMAC key from given root key.
+
+**/
+BOOLEAN
+EFIAPI
+GenerateMetaDataHmacKey (
+ IN CONST UINT8 *RootKey,
+ IN UINTN RootKeySize,
+ OUT UINT8 *HmacKey,
+ IN UINTN HmacKeySize
+ );
+
+/**
+
+ Digests the given variable data and updates HMAC context.
+
+ @param[in,out] Context Pointer to initialized HMAC context.
+ @param[in] VarInfo Pointer to variable data.
+
+ @retval TRUE HMAC context was updated successfully.
+ @retval FALSE Failed to update HMAC context.
+
+**/
+BOOLEAN
+UpdateVariableMetadataHmac (
+ IN VOID *Context,
+ IN PROTECTED_VARIABLE_INFO *VarInfo
+ );
+
+/**
+
+ Re-calculate HMAC based on new variable data and re-generate MetaDataHmacVar.
+
+ @param[in] Global Pointer to global configuration data.
+ @param[in] NewVarInfo Pointer to buffer of new variable data.
+ @param[in,out] NewHmacVarInfo Pointer to buffer of new MetaDataHmacVar.
+
+ @return EFI_SUCCESS The HMAC value was updated successfully.
+ @return EFI_ABORTED Failed to calculate the HMAC value.
+ @return EFI_OUT_OF_RESOURCES Not enough resource to calculate HMC value.
+ @return EFI_NOT_FOUND The MetaDataHmacVar was not found in storage.
+
+**/
+EFI_STATUS
+RefreshVariableMetadataHmac (
+ IN PROTECTED_VARIABLE_GLOBAL *Global,
+ IN PROTECTED_VARIABLE_INFO *NewVarInfo,
+ IN OUT PROTECTED_VARIABLE_INFO *NewHmacVarInfo
+ );
+
+/**
+
+ Retrieve the context and global configuration data structure from HOB.
+
+ Once protected NV variable storage is cached and verified in PEI phase,
+ all related information are stored in a HOB which can be used by PEI variable
+ service itself and passed to SMM along with the boot flow, which can avoid
+ many duplicate works, like generating HMAC key, verifying NV variable storage,
+ etc.
+
+ The HOB can be identified by gEdkiiProtectedVariableGlobalGuid.
+
+ @param[out] Global Pointer to global configuration data from PEI phase.
+
+ @retval EFI_SUCCESS The HOB was found, and Context and Global are retrieved.
+ @retval EFI_NOT_FOUND The HOB was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableGlobalFromHob (
+ OUT PROTECTED_VARIABLE_GLOBAL **Global OPTIONAL
+ );
+
+/**
+
+ Get context and/or global data structure used to process protected variable.
+
+ @param[out] Global Pointer to global configuration data.
+
+ @retval EFI_SUCCESS Get requested structure successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableGlobal (
+ OUT PROTECTED_VARIABLE_GLOBAL **Global OPTIONAL
+ );
+
+/**
+
+ Get context data structure used to process protected variable.
+
+ @param[out] ContextIn Pointer to context provided by variable runtime services.
+
+ @retval EFI_SUCCESS Get requested structure successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableContext (
+ PROTECTED_VARIABLE_CONTEXT_IN **ContextIn OPTIONAL
+ );
+
+/**
+
+ Check if a given variable is unprotected variable specified in advance
+ and return its index ID.
+
+ @param[in] Global Pointer to global configuration data.
+ @param[in] VarInfo Pointer to variable information data.
+
+ @retval IndexHmacInDel Variable is MetaDataHmacVar in delete-transition state.
+ @retval IndexHmacAdded Variable is MetaDataHmacVar in valid state.
+ @retval IndexErrorFlag Variable is VarErrorLog.
+ @retval Others Variable is not any known unprotected variables.
+
+**/
+UNPROTECTED_VARIABLE_INDEX
+CheckKnownUnprotectedVariable (
+ IN PROTECTED_VARIABLE_GLOBAL *Global,
+ IN PROTECTED_VARIABLE_INFO *VarInfo
+ );
+
+/**
+
+ Return the size of variable MetaDataHmacVar.
+
+ @param[in] AuthFlag Auth-variable indicator.
+
+ @retval size of variable MetaDataHmacVar.
+
+**/
+UINTN
+GetMetaDataHmacVarSize (
+ IN BOOLEAN AuthFlag
+ );
+
+/**
+
+ Fix state of MetaDataHmacVar on NV variable storage, if there's failure at
+ last boot during updating variable.
+
+ This must be done before the first writing of variable in current boot,
+ including storage reclaim.
+
+ @retval EFI_UNSUPPORTED Updating NV variable storage is not supported.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to complete the operation.
+ @retval EFI_SUCCESS Variable store was successfully updated.
+
+**/
+EFI_STATUS
+FixupHmacVariable (
+ VOID
+ );
+
+/**
+
+ Verify the variable digest.
+
+ @param[in] Global Pointer to global configuration data.
+ @param[in] VarInfo Pointer to verified copy of protected variables.
+ @param[in] VarDig Pointer to variable digest data.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter was passed in.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to calculate hash.
+ @retval EFI_ABORTED An error was encountered.
+ @retval EFI_COMPROMISED_DATA The data was compromised.
+ @retval EFI_SUCCESS Variable digest was successfully verified.
+
+**/
+EFI_STATUS
+VerifyVariableDigest (
+ IN PROTECTED_VARIABLE_GLOBAL *Global,
+ IN PROTECTED_VARIABLE_INFO *VarInfo,
+ IN VARIABLE_DIGEST *VarDig
+ );
+
+/**
+
+ Get the variable digest.
+
+ @param[in] Global Pointer to global configuration data.
+ @param[in] VarInfo Pointer to verified copy of protected variables.
+ @param[in,out] DigestValue Pointer to variable digest value.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter was passed in.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to calculate hash.
+ @retval EFI_ABORTED An error was encountered.
+ @retval EFI_COMPROMISED_DATA The data was compromised.
+ @retval EFI_SUCCESS Variable digest was successfully verified.
+
+**/
+EFI_STATUS
+GetVariableDigest (
+ IN PROTECTED_VARIABLE_GLOBAL *Global,
+ IN PROTECTED_VARIABLE_INFO *VarInfo,
+ IN OUT UINT8 *DigestValue
+ );
+
+/**
+
+ Compare variable name and Guid
+
+ @param[in] Name1 Name of first variable.
+ @param[in] Name1Size Size of first variable.
+ @param[in] Name2 Name of second variable.
+ @param[in] Name2Size Size of second variable.
+ @param[in] Guid1 Guid for first variable.
+ @param[in] Guid2 Guid for second variable.
+
+ @retval 0 First name is identical to Second name.
+ @return others First name is not identical to Second name.
+
+**/
+INTN
+CompareVariableNameAndGuid (
+ IN CONST CHAR16 *Name1,
+ IN UINTN Name1Size,
+ IN CONST CHAR16 *Name2,
+ IN UINTN Name2Size,
+ IN EFI_GUID *Guid1,
+ IN EFI_GUID *Guid2
+ );
+
+/**
+
+ Compare variable digest.
+
+ @param[in] Variable1 Pointer to first variable digest.
+ @param[in] Variable2 Pointer to second variable digest.
+
+ @retval 0 Variables are identical.
+ @return others Variables are not identical.
+
+**/
+INTN
+CompareVariableDigestInfo (
+ IN VARIABLE_DIGEST *Variable1,
+ IN VARIABLE_DIGEST *Variable2
+ );
+
+/**
+
+ Move a node backward in the order controlled by SortMethod.
+
+ @param[in] Node Pointer to node to be moved.
+ @param[in] SortMethod Method used to compare node in list.
+
+**/
+VOID
+MoveNodeBackward (
+ IN OUT VARIABLE_DIGEST *Node,
+ IN SORT_METHOD SortMethod
+ );
+
+/**
+
+ Remove variable digest node.
+
+ @param[in,out] Global Pointer to global configuration data.
+ @param[in,out] VarDig Pointer to variable digest value.
+ @param[in] FreeResource Flag to indicate whether to free resource.
+
+**/
+VOID
+RemoveVariableDigestNode (
+ IN OUT PROTECTED_VARIABLE_GLOBAL *Global,
+ IN OUT VARIABLE_DIGEST *VarDig,
+ IN BOOLEAN FreeResource
+ );
+
+/**
+
+ Insert variable digest node.
+
+ @param[in,out] Global Pointer to global configuration data.
+ @param[in] VarDig Pointer to variable digest value.
+ @param[in] SortMethod Method for sorting.
+
+**/
+VOID
+InsertVariableDigestNode (
+ IN OUT PROTECTED_VARIABLE_GLOBAL *Global,
+ IN VARIABLE_DIGEST *VarDig,
+ IN SORT_METHOD SortMethod
+ );
+
+/**
+
+ Create variable digest node.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] NameSize Size of variable name.
+ @param[in] DataSize Size of variable data.
+ @param[in] AuthVar Authenticated variable flag.
+ @param[in] Global Pointer to global configuration data.
+
+ @retval Ptr Pointer to variable digest
+
+**/
+VARIABLE_DIGEST *
+CreateVariableDigestNode (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT16 NameSize,
+ IN UINT32 DataSize,
+ IN BOOLEAN AuthVar,
+ IN PROTECTED_VARIABLE_GLOBAL *Global
+ );
+
+/**
+
+ This function is used to enumerate the variables managed by current
+ ProtectedVariableLib.
+
+ If the VarInfo->StoreIndex is invalid (VAR_INDEX_INVALID), the first variable
+ with the smallest StoreIndex will be returned. Otherwise, the variable with
+ StoreIndex just after than the VarInfo->StoreIndex will be returned.
+
+ @param[in,out] VarInfo Pointer to structure containing variable information.
+
+ @retval EFI_SUCCESS Found the specified variable.
+ @retval EFI_INVALID_PARAMETER VarInfo is NULL.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetNextInternal (
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ );
+
+/**
+
+ Find the specified variable digest
+
+ @param[in] Global Pointer to global configuration data.
+ @param[in] VarInfo Pointer to variable data.
+ @param[in] FindNext Flag to continue looking for variable.
+
+**/
+VARIABLE_DIGEST *
+FindVariableInternal (
+ IN PROTECTED_VARIABLE_GLOBAL *Global,
+ IN PROTECTED_VARIABLE_INFO *VarInfo,
+ IN BOOLEAN FindNext
+ );
+
+/**
+
+ Synchronize the RPMC counters
+
+ @param[in] Global Pointer to global configuration data.
+ @param[in] VarInfo Pointer to variable data.
+ @param[in] FindNext Flag to continue looking for variable.
+
+ @retval EFI_SUCCESS Successfully sync RPMC counters.
+ @return others Failed to sync RPMC counters.
+
+**/
+EFI_STATUS
+SyncRpmcCounter (
+ VOID
+ );
+
+/**
+
+ Perform for protected variable integrity check.
+
+ If this initialization failed upon any error, the whole variable services
+ should not be used. A system reset might be needed to re-construct NV
+ variable storage to be the default state.
+
+ @param[in] ContextIn Pointer to variable service context needed by
+ protected variable.
+
+ @retval EFI_SUCCESS Protected variable services are ready.
+ @retval EFI_INVALID_PARAMETER If ContextIn == NULL or something missing or
+ mismatching in the content in ContextIn.
+ @retval EFI_COMPROMISED_DATA If failed to check integrity of protected variables.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+PerformVariableIntegrityCheck (
+ IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn
+ );
+
+extern EFI_TIME mDefaultTimeStamp;
+extern VARIABLE_IDENTIFIER mUnprotectedVariables[UnprotectedVarIndexMax];
+extern PROTECTED_VARIABLE_CONTEXT_IN mVariableContextIn;
+extern PROTECTED_VARIABLE_GLOBAL mProtectedVariableGlobal;
+
+#endif
diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
new file mode 100644
index 000000000000..ed1a8e1ec545
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
@@ -0,0 +1,2095 @@
+/** @file
+ The common protected variable operation routines.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi.h>
+#include <PiPei.h>
+
+#include <Guid/VariableFormat.h>
+#include <Guid/VarErrorFlag.h>
+
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HashApiLib.h>
+#include <Library/SortLib.h>
+
+#include "ProtectedVariableInternal.h"
+
+EFI_TIME mDefaultTimeStamp = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+VARIABLE_IDENTIFIER mUnprotectedVariables[] = {
+ {
+ METADATA_HMAC_VARIABLE_NAME,
+ &METADATA_HMAC_VARIABLE_GUID,
+ VAR_ADDED & VAR_IN_DELETED_TRANSITION
+ },
+ {
+ METADATA_HMAC_VARIABLE_NAME,
+ &METADATA_HMAC_VARIABLE_GUID,
+ VAR_ADDED
+ },
+ {
+ VAR_ERROR_FLAG_NAME,
+ &gEdkiiVarErrorFlagGuid,
+ VAR_ADDED
+ },
+ {
+ (CHAR16 *)PcdGetPtr (PcdPlatformVariableName),
+ (EFI_GUID *)PcdGetPtr (PcdPlatformVariableGuid),
+ VAR_ADDED
+ }
+};
+
+/**
+ Print variable information.
+
+ @param[in] Data8 Pointer to data.
+ @param[in] DataSize Size of data.
+
+**/
+VOID
+PrintVariableData (
+ IN UINT8 *Data8,
+ IN UINTN DataSize
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < DataSize; Index++) {
+ if (Index % 0x10 == 0) {
+ DEBUG ((DEBUG_INFO, "\n%08X:", Index));
+ }
+
+ DEBUG ((DEBUG_INFO, " %02X", *Data8++));
+ }
+
+ DEBUG ((DEBUG_INFO, "\n"));
+}
+
+/**
+
+ Retrieve the context and global configuration data structure from HOB.
+
+ Once protected NV variable storage is cached and verified in PEI phase,
+ all related information are stored in a HOB which can be used by PEI variable
+ service itself and passed to SMM along with the boot flow, which can avoid
+ many duplicate works, like generating HMAC key, verifying NV variable storage,
+ etc.
+
+ The HOB can be identified by gEdkiiProtectedVariableGlobalGuid.
+
+ @param[out] Global Pointer to global configuration data from PEI phase.
+
+ @retval EFI_SUCCESS The HOB was found, and Context and Global are retrieved.
+ @retval EFI_NOT_FOUND The HOB was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableGlobalFromHob (
+ OUT PROTECTED_VARIABLE_GLOBAL **Global
+ )
+{
+ VOID *Data;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
+ PROTECTED_VARIABLE_CONTEXT_IN *ContextIn;
+ EFI_PHYSICAL_ADDRESS OldStart;
+ VARIABLE_DIGEST *VarDig;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ UINTN Index;
+
+ Hob.Raw = GetFirstGuidHob (&gEdkiiProtectedVariableGlobalGuid);
+ if (Hob.Raw != NULL) {
+ Data = GET_GUID_HOB_DATA (Hob);
+ } else {
+ //
+ // Search the global from allocated memory blob.
+ //
+ Data = NULL;
+ MemoryAllocationHob = NULL;
+
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
+ while (Hob.Raw != NULL) {
+ MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *)Hob.Raw;
+ if (CompareGuid (
+ &MemoryAllocationHob->AllocDescriptor.Name,
+ &gEdkiiProtectedVariableGlobalGuid
+ ))
+ {
+ Data = (VOID *)(UINTN)
+ MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress;
+ break;
+ }
+
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+ }
+ }
+
+ if (Data == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Global != NULL) {
+ GuidHob = GetFirstGuidHob (&gEdkiiProtectedVariableContextGuid);
+ if (GuidHob != NULL) {
+ ContextIn = (PROTECTED_VARIABLE_CONTEXT_IN *)GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ ASSERT (GuidHob == NULL);
+ }
+
+ *Global = (PROTECTED_VARIABLE_GLOBAL *)((UINT8 *)Data);
+ //
+ // Fix pointers in the HOB (due to physical memory readiness)
+ //
+ if ((*Global)->GlobalSelf != (EFI_PHYSICAL_ADDRESS)(UINTN)(*Global)) {
+ OldStart = (*Global)->GlobalSelf;
+ (*Global)->ContextIn = GET_ADRS (ContextIn);
+
+ //
+ // Mark Memory caching is available
+ //
+ (*Global)->Flags.CacheReady = TRUE;
+
+ //
+ // Re-allocate new minimum cache
+ //
+ (*Global)->VariableCache = GET_ADRS (Data)
+ + ((*Global)->VariableCache - OldStart);
+
+ (*Global)->DigestContext = GET_ADRS (((*Global) + 1));
+ for (Index = 0; Index < UnprotectedVarIndexMax; Index++) {
+ if ((*Global)->Unprotected[Index] != VAR_INDEX_INVALID) {
+ (*Global)->Unprotected[Index] = GET_ADRS (Data)
+ + ((*Global)->Unprotected[Index] - OldStart);
+ }
+ }
+
+ (*Global)->LastAccessedVariable = GET_ADRS (Data)
+ + ((*Global)->LastAccessedVariable - OldStart);
+
+ //
+ // Fix all linked-list pointers inside VARIABLE_SIGNATURE.
+ //
+ (*Global)->VariableDigests = GET_ADRS (Data)
+ + ((*Global)->VariableDigests - OldStart);
+ VarDig = VAR_DIG_PTR ((*Global)->VariableDigests);
+ while (VarDig != NULL) {
+ if (VarDig->Prev != 0) {
+ VarDig->Prev = GET_ADRS (Data) + (VarDig->Prev - OldStart);
+ }
+
+ if (VarDig->Next != 0) {
+ VarDig->Next = GET_ADRS (Data) + (VarDig->Next - OldStart);
+ }
+
+ VarDig = VAR_DIG_NEXT (VarDig);
+ }
+
+ (*Global)->GlobalSelf = (EFI_PHYSICAL_ADDRESS)(UINTN)(*Global);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Derive HMAC key from given variable root key.
+
+ @param[in] RootKey Pointer to root key to derive from.
+ @param[in] RootKeySize Size of root key.
+ @param[out] HmacKey Pointer to generated HMAC key.
+ @param[in] HmacKeySize Size of HMAC key.
+
+ @retval TRUE The HMAC key is derived successfully.
+ @retval FALSE Failed to generate HMAC key from given root key.
+
+**/
+BOOLEAN
+EFIAPI
+GenerateMetaDataHmacKey (
+ IN CONST UINT8 *RootKey,
+ IN UINTN RootKeySize,
+ OUT UINT8 *HmacKey,
+ IN UINTN HmacKeySize
+ )
+{
+ UINT8 Salt[AES_BLOCK_SIZE];
+
+ return HkdfSha256ExtractAndExpand (
+ RootKey,
+ RootKeySize,
+ Salt,
+ 0,
+ (UINT8 *)METADATA_HMAC_KEY_NAME,
+ METADATA_HMAC_KEY_NAME_SIZE,
+ HmacKey,
+ HmacKeySize
+ );
+}
+
+/**
+
+ Return the size of variable MetaDataHmacVar.
+
+ @param[in] AuthFlag Auth-variable indicator.
+
+ @retval size of variable MetaDataHmacVar.
+
+**/
+UINTN
+GetMetaDataHmacVarSize (
+ IN BOOLEAN AuthFlag
+ )
+{
+ UINTN Size;
+
+ if (AuthFlag) {
+ Size = sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ } else {
+ Size = sizeof (VARIABLE_HEADER);
+ }
+
+ Size += METADATA_HMAC_VARIABLE_NAME_SIZE;
+ Size += GET_PAD_SIZE (Size);
+ Size += METADATA_HMAC_SIZE;
+ Size += GET_PAD_SIZE (Size);
+
+ return Size;
+}
+
+/**
+
+ Digests the given variable data and updates HMAC context.
+
+ @param[in] Context Pointer to initialized HMAC context.
+ @param[in] VarInfo Pointer to variable data.
+ @param[in] UpdateMethod Function to run when updating variable digest.
+
+ @retval TRUE HMAC context was updated successfully.
+ @retval FALSE Failed to update HMAC context.
+
+**/
+STATIC
+BOOLEAN
+UpdateVariableDigestData (
+ IN VOID *Context,
+ IN PROTECTED_VARIABLE_INFO *VarInfo,
+ IN DIGEST_UPDATE UpdateMethod
+ )
+{
+ VOID *Buffer[12];
+ UINT32 BufferSize[12];
+ UINTN Index;
+ BOOLEAN Status;
+
+ //
+ // Empty variable is legal here (e.g. variable deletion case or write-init case).
+ //
+ if ((VarInfo == NULL) ||
+ (VarInfo->CipherData == NULL) ||
+ (VarInfo->CipherDataSize == 0))
+ {
+ return TRUE;
+ }
+
+ //
+ // HMAC (":" || VariableName)
+ //
+ Buffer[0] = METADATA_HMAC_SEP;
+ BufferSize[0] = METADATA_HMAC_SEP_SIZE;
+
+ Buffer[1] = VarInfo->Header.VariableName;
+ BufferSize[1] = (UINT32)VarInfo->Header.NameSize;
+
+ //
+ // HMAC (":" || VendorGuid || Attributes || DataSize)
+ //
+ Buffer[2] = METADATA_HMAC_SEP;
+ BufferSize[2] = METADATA_HMAC_SEP_SIZE;
+
+ Buffer[3] = VarInfo->Header.VendorGuid;
+ BufferSize[3] = sizeof (EFI_GUID);
+
+ Buffer[4] = &VarInfo->Header.Attributes;
+ BufferSize[4] = sizeof (VarInfo->Header.Attributes);
+
+ Buffer[5] = &VarInfo->CipherDataSize;
+ BufferSize[5] = sizeof (VarInfo->CipherDataSize);
+
+ //
+ // HMAC (":" || CipherData)
+ //
+ Buffer[6] = METADATA_HMAC_SEP;
+ BufferSize[6] = METADATA_HMAC_SEP_SIZE;
+
+ Buffer[7] = VarInfo->CipherData;
+ BufferSize[7] = VarInfo->CipherDataSize;
+
+ //
+ // HMAC (":" || PubKeyIndex || AuthMonotonicCount || TimeStamp)
+ //
+ Buffer[8] = METADATA_HMAC_SEP;
+ BufferSize[8] = METADATA_HMAC_SEP_SIZE;
+
+ Buffer[9] = &VarInfo->Header.PubKeyIndex;
+ BufferSize[9] = sizeof (VarInfo->Header.PubKeyIndex);
+
+ Buffer[10] = &VarInfo->Header.MonotonicCount;
+ BufferSize[10] = sizeof (VarInfo->Header.MonotonicCount);
+
+ Buffer[11] = (VarInfo->Header.TimeStamp != NULL) ?
+ VarInfo->Header.TimeStamp : &mDefaultTimeStamp;
+ BufferSize[11] = sizeof (EFI_TIME);
+
+ for (Index = 0; Index < ARRAY_SIZE (Buffer); ++Index) {
+ Status = UpdateMethod (Context, Buffer[Index], BufferSize[Index]);
+ if (!Status) {
+ ASSERT (FALSE);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+
+ Digests the given variable data and updates HMAC context.
+
+ @param[in] Context Pointer to initialized HMAC context.
+ @param[in] VarInfo Pointer to variable data.
+
+ @retval TRUE HMAC context was updated successfully.
+ @retval FALSE Failed to update HMAC context.
+
+**/
+BOOLEAN
+UpdateVariableMetadataHmac (
+ IN VOID *Context,
+ IN PROTECTED_VARIABLE_INFO *VarInfo
+ )
+{
+ return UpdateVariableDigestData (Context, VarInfo, (DIGEST_UPDATE)HmacSha256Update);
+}
+
+/**
+
+ Get the variable digest.
+
+ @param[in] Global Pointer to global configuration data.
+ @param[in] VarInfo Pointer to verified copy of protected variables.
+ @param[in,out] DigestValue Pointer to variable digest value.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter was passed in.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to calculate hash.
+ @retval EFI_ABORTED An error was encountered.
+ @retval EFI_COMPROMISED_DATA The data was compromised.
+ @retval EFI_SUCCESS Variable digest was successfully verified.
+
+**/
+EFI_STATUS
+GetVariableDigest (
+ IN PROTECTED_VARIABLE_GLOBAL *Global,
+ IN PROTECTED_VARIABLE_INFO *VarInfo,
+ IN OUT UINT8 *DigestValue
+ )
+{
+ EFI_STATUS Status;
+ VOID *Context;
+
+ if ((Global == NULL) || (VarInfo == NULL) || (DigestValue == NULL)) {
+ ASSERT (Global != NULL);
+ ASSERT (VarInfo != NULL);
+ ASSERT (DigestValue != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Context = GET_BUFR (Global->DigestContext);
+ if (!HashApiInit (Context)) {
+ ASSERT (Context != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (VarInfo->CipherData == NULL) {
+ VarInfo->CipherData = VarInfo->Header.Data;
+ VarInfo->CipherDataSize = (UINT32)VarInfo->Header.DataSize;
+ }
+
+ if ( !UpdateVariableDigestData (Context, VarInfo, (DIGEST_UPDATE)HashApiUpdate)
+ || !HashApiFinal (Context, DigestValue))
+ {
+ ASSERT (FALSE);
+ Status = EFI_ABORTED;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+/**
+
+ Verify the variable digest.
+
+ @param[in] Global Pointer to global configuration data.
+ @param[in] VarInfo Pointer to verified copy of protected variables.
+ @param[in] VarDig Pointer to variable digest data.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter was passed in.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to calculate hash.
+ @retval EFI_ABORTED An error was encountered.
+ @retval EFI_COMPROMISED_DATA The data was compromised.
+ @retval EFI_SUCCESS Variable digest was successfully verified.
+
+**/
+EFI_STATUS
+VerifyVariableDigest (
+ IN PROTECTED_VARIABLE_GLOBAL *Global,
+ IN PROTECTED_VARIABLE_INFO *VarInfo,
+ IN VARIABLE_DIGEST *VarDig
+ )
+{
+ EFI_STATUS Status;
+ UINT8 NewDigest[METADATA_HMAC_SIZE];
+
+ if (Global->Flags.RecoveryMode || !VarDig->Flags.Protected) {
+ return EFI_SUCCESS;
+ }
+
+ ASSERT (VarDig->DigestSize == sizeof (NewDigest));
+
+ Status = GetVariableDigest (Global, VarInfo, NewDigest);
+ if (!EFI_ERROR (Status)) {
+ if (CompareMem (VAR_DIG_VALUE (VarDig), NewDigest, VarDig->DigestSize) != 0) {
+ Status = EFI_COMPROMISED_DATA;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Initialize variable MetaDataHmacVar.
+
+ @param[in,out] Variable Pointer to buffer of MetaDataHmacVar.
+ @param[in] AuthFlag Variable format flag.
+
+**/
+VOID
+InitMetadataHmacVariable (
+ IN OUT VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ UINT8 *NamePtr;
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ Variable->StartId = VARIABLE_DATA;
+ Variable->State = VAR_ADDED;
+ Variable->Reserved = 0;
+ Variable->Attributes = VARIABLE_ATTRIBUTE_NV_BS_RT;
+
+ if (AuthFlag) {
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+
+ AuthVariable->NameSize = METADATA_HMAC_VARIABLE_NAME_SIZE;
+ AuthVariable->DataSize = METADATA_HMAC_SIZE;
+ AuthVariable->PubKeyIndex = 0;
+ AuthVariable->MonotonicCount = 0;
+
+ ZeroMem (&AuthVariable->TimeStamp, sizeof (EFI_TIME));
+ CopyMem (&AuthVariable->VendorGuid, &METADATA_HMAC_VARIABLE_GUID, sizeof (EFI_GUID));
+
+ NamePtr = (UINT8 *)AuthVariable + sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ } else {
+ Variable->NameSize = METADATA_HMAC_VARIABLE_NAME_SIZE;
+ Variable->DataSize = METADATA_HMAC_SIZE;
+
+ CopyMem (&Variable->VendorGuid, &METADATA_HMAC_VARIABLE_GUID, sizeof (EFI_GUID));
+
+ NamePtr = (UINT8 *)Variable + sizeof (VARIABLE_HEADER);
+ }
+
+ CopyMem (NamePtr, METADATA_HMAC_VARIABLE_NAME, METADATA_HMAC_VARIABLE_NAME_SIZE);
+}
+
+/**
+ Re-calculate HMAC based on new variable data and re-generate MetaDataHmacVar.
+
+ @param[in] Global Pointer to global configuration data.
+ @param[in] NewVarInfo Pointer to buffer of new variable data.
+ @param[in,out] NewHmacVarInfo Pointer to buffer of new MetaDataHmacVar.
+
+ @return EFI_SUCCESS The HMAC value was updated successfully.
+ @return EFI_ABORTED Failed to calculate the HMAC value.
+ @return EFI_OUT_OF_RESOURCES Not enough resource to calculate HMC value.
+ @return EFI_NOT_FOUND The MetaDataHmacVar was not found in storage.
+
+**/
+EFI_STATUS
+RefreshVariableMetadataHmac (
+ IN PROTECTED_VARIABLE_GLOBAL *Global,
+ IN PROTECTED_VARIABLE_INFO *NewVarInfo,
+ IN OUT PROTECTED_VARIABLE_INFO *NewHmacVarInfo
+ )
+{
+ EFI_STATUS Status;
+ VOID *Context;
+ UINT32 Counter;
+ PROTECTED_VARIABLE_INFO VarInfo;
+ PROTECTED_VARIABLE_INFO CurrHmacVarInfo;
+ UINT8 *HmacValue;
+ PROTECTED_VARIABLE_CONTEXT_IN *ContextIn;
+ VARIABLE_DIGEST *VarDig;
+ VARIABLE_DIGEST *HmacVarDig;
+
+ ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
+ ZeroMem ((VOID *)&CurrHmacVarInfo, sizeof (CurrHmacVarInfo));
+
+ Status = RequestMonotonicCounter (RPMC_COUNTER_2, &Counter);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ Counter += 1;
+ ContextIn = GET_CNTX (Global);
+
+ //
+ // Delete current MetaDataHmacVariable first, if any.
+ //
+ if (Global->Unprotected[IndexHmacAdded] != VAR_INDEX_INVALID) {
+ HmacVarDig = VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded]);
+
+ CurrHmacVarInfo.Header.NameSize = HmacVarDig->NameSize;
+ CurrHmacVarInfo.Header.VariableName = VAR_DIG_NAME (HmacVarDig);
+ CurrHmacVarInfo.Header.VendorGuid = VAR_DIG_GUID (HmacVarDig);
+
+ CurrHmacVarInfo.Buffer = VAR_HDR_PTR (HmacVarDig->CacheIndex);
+ CurrHmacVarInfo.StoreIndex = HmacVarDig->StoreIndex;
+ CurrHmacVarInfo.Flags.Auth = HmacVarDig->Flags.Auth;
+ //
+ // Force marking current MetaDataHmacVariable as VAR_IN_DELETED_TRANSITION.
+ //
+ CurrHmacVarInfo.Buffer->State &= VAR_IN_DELETED_TRANSITION;
+ HmacVarDig->State &= VAR_IN_DELETED_TRANSITION;
+ Status = ContextIn->UpdateVariableStore (
+ &CurrHmacVarInfo,
+ OFFSET_OF (VARIABLE_HEADER, State),
+ sizeof (CurrHmacVarInfo.Buffer->State),
+ &CurrHmacVarInfo.Buffer->State
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ } else if (Global->Unprotected[IndexHmacInDel] != VAR_INDEX_INVALID) {
+ HmacVarDig = VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel]);
+ } else {
+ //
+ // No MetaDataHmacVar. Allocate space to cache its value.
+ //
+ HmacVarDig = CreateVariableDigestNode (
+ METADATA_HMAC_VARIABLE_NAME,
+ &METADATA_HMAC_VARIABLE_GUID,
+ METADATA_HMAC_VARIABLE_NAME_SIZE,
+ METADATA_HMAC_SIZE,
+ Global->Flags.Auth,
+ Global
+ );
+ if (HmacVarDig == NULL) {
+ ASSERT (HmacVarDig != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ HmacVarDig->Flags.Protected = FALSE;
+ }
+
+ if (HmacVarDig->CacheIndex == VAR_INDEX_INVALID) {
+ HmacVarDig->CacheIndex = (GET_ADRS (Global)) + (Global->StructSize - GetMetaDataHmacVarSize (Global->Flags.Auth));
+ }
+
+ //
+ // Construct new MetaDataHmacVar.
+ //
+ if (NewHmacVarInfo == NULL) {
+ NewHmacVarInfo = &VarInfo;
+ NewHmacVarInfo->Buffer = GET_BUFR (HmacVarDig->CacheIndex);
+ }
+
+ InitMetadataHmacVariable (NewHmacVarInfo->Buffer, Global->Flags.Auth);
+
+ NewHmacVarInfo->StoreIndex = VAR_INDEX_INVALID; // Skip calculating offset
+ NewHmacVarInfo->Flags.Auth = Global->Flags.Auth;
+ Status = ContextIn->GetVariableInfo (NewHmacVarInfo);
+ ASSERT_EFI_ERROR (Status);
+ HmacValue = NewHmacVarInfo->Header.Data;
+
+ //
+ // Re-calculate HMAC for all valid variables
+ //
+ Context = HmacSha256New ();
+ if (Context == NULL) {
+ ASSERT (Context != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = EFI_ABORTED;
+ if (!HmacSha256SetKey (
+ Context,
+ Global->MetaDataHmacKey,
+ sizeof (Global->MetaDataHmacKey)
+ ))
+ {
+ ASSERT (FALSE);
+ goto Done;
+ }
+
+ //
+ // HMAC (|| hash(Var1) || hash(Var2) || ... || hash(VarN))
+ //
+ VarDig = VAR_DIG_PTR (Global->VariableDigests);
+ while (VarDig != NULL) {
+ if (VarDig->Flags.Valid && VarDig->Flags.Protected) {
+ HmacSha256Update (Context, VAR_DIG_VALUE (VarDig), VarDig->DigestSize);
+ }
+
+ VarDig = VAR_DIG_NEXT (VarDig);
+ }
+
+ //
+ // HMAC (RpmcMonotonicCounter)
+ //
+ if (!HmacSha256Update (Context, &Counter, sizeof (Counter))) {
+ ASSERT (FALSE);
+ goto Done;
+ }
+
+ if (!HmacSha256Final (Context, HmacValue)) {
+ ASSERT (FALSE);
+ goto Done;
+ }
+
+ //
+ // Update HMAC value in cache.
+ //
+ CopyMem (VAR_DIG_VALUE (HmacVarDig), HmacValue, HmacVarDig->DataSize);
+ if ((HmacVarDig->Prev == 0) && (HmacVarDig->Next == 0)) {
+ InsertVariableDigestNode (Global, HmacVarDig, NULL);
+ }
+
+ //
+ // Just one MetaDataHmacVar is needed for normal operation.
+ //
+ Global->Unprotected[IndexHmacAdded] = VAR_DIG_ADR (HmacVarDig);
+ Global->Unprotected[IndexHmacInDel] = VAR_INDEX_INVALID;
+
+ Status = EFI_SUCCESS;
+
+Done:
+ if (Context != NULL) {
+ HmacSha256Free (Context);
+ }
+
+ return Status;
+}
+
+/**
+
+ Check if a given variable is unprotected variable specified in advance
+ and return its index ID.
+
+ @param[in] Global Pointer to global configuration data.
+ @param[in] VarInfo Pointer to variable information data.
+
+ @retval IndexHmacInDel Variable is MetaDataHmacVar in delete-transition state.
+ @retval IndexHmacAdded Variable is MetaDataHmacVar in valid state.
+ @retval IndexErrorFlag Variable is VarErrorLog.
+ @retval Others Variable is not any known unprotected variables.
+
+**/
+UNPROTECTED_VARIABLE_INDEX
+CheckKnownUnprotectedVariable (
+ IN PROTECTED_VARIABLE_GLOBAL *Global,
+ IN PROTECTED_VARIABLE_INFO *VarInfo
+ )
+{
+ UNPROTECTED_VARIABLE_INDEX Index;
+
+ if ((VarInfo == NULL) || ( (VarInfo->StoreIndex == VAR_INDEX_INVALID)
+ && ( (VarInfo->Header.VariableName == NULL)
+ || (VarInfo->Header.VendorGuid == NULL))))
+ {
+ ASSERT (VarInfo != NULL);
+ ASSERT (VarInfo->StoreIndex != VAR_INDEX_INVALID);
+ ASSERT (VarInfo->Header.VariableName != NULL);
+ ASSERT (VarInfo->Header.VendorGuid != NULL);
+ return UnprotectedVarIndexMax;
+ }
+
+ for (Index = 0; Index < UnprotectedVarIndexMax; ++Index) {
+ if ( (Global->Unprotected[Index] != VAR_INDEX_INVALID)
+ && (VarInfo->StoreIndex != VAR_INDEX_INVALID))
+ {
+ if (VarInfo->StoreIndex == VAR_DIG_PTR (Global->Unprotected[Index])->StoreIndex) {
+ break;
+ }
+ } else if (IS_VARIABLE (
+ &VarInfo->Header,
+ mUnprotectedVariables[Index].VariableName,
+ mUnprotectedVariables[Index].VendorGuid
+ ) && (VarInfo->Header.State == mUnprotectedVariables[Index].State))
+ {
+ break;
+ }
+ }
+
+ return Index;
+}
+
+/**
+
+ Compare variable name and Guid
+
+ @param[in] Name1 Name of first variable.
+ @param[in] Name1Size Size of first variable.
+ @param[in] Name2 Name of second variable.
+ @param[in] Name2Size Size of second variable.
+ @param[in] Guid1 Guid for first variable.
+ @param[in] Guid2 Guid for second variable.
+
+ @retval 0 First name is identical to Second name.
+ @return others First name is not identical to Second name.
+
+**/
+INTN
+CompareVariableNameAndGuid (
+ IN CONST CHAR16 *Name1,
+ IN UINTN Name1Size,
+ IN CONST CHAR16 *Name2,
+ IN UINTN Name2Size,
+ IN EFI_GUID *Guid1,
+ IN EFI_GUID *Guid2
+ )
+{
+ INTN Result;
+
+ Result = StrnCmp (
+ Name1,
+ Name2,
+ MIN (Name1Size, Name2Size) / sizeof (CHAR16)
+ );
+ if (Result == 0) {
+ if (Name1Size != Name2Size) {
+ //
+ // Longer name is 'bigger' than shorter one.
+ //
+ Result = (INTN)Name1Size - (INTN)Name2Size;
+ } else {
+ //
+ // The variable name is the same. Compare the GUID.
+ //
+ Result = CompareMem ((VOID *)Guid1, (VOID *)Guid2, sizeof (EFI_GUID));
+ }
+ }
+
+ return Result;
+}
+
+/**
+
+ Compare variable digest.
+
+ @param[in] Variable1 Pointer to first variable digest.
+ @param[in] Variable2 Pointer to second variable digest.
+
+ @retval 0 Variables are identical.
+ @return others Variables are not identical.
+
+**/
+INTN
+CompareVariableDigestInfo (
+ IN VARIABLE_DIGEST *Variable1,
+ IN VARIABLE_DIGEST *Variable2
+ )
+{
+ return CompareVariableNameAndGuid (
+ VAR_DIG_NAME (Variable1),
+ Variable1->NameSize,
+ VAR_DIG_NAME (Variable2),
+ Variable2->NameSize,
+ &Variable1->VendorGuid,
+ &Variable2->VendorGuid
+ );
+}
+
+/**
+
+ Move a node backward in the order controlled by SortMethod.
+
+ @param[in,out] Node Pointer to node to be moved.
+ @param[in] SortMethod Method used to compare node in list.
+
+**/
+VOID
+MoveNodeBackward (
+ IN OUT VARIABLE_DIGEST *Node,
+ IN SORT_METHOD SortMethod
+ )
+{
+ VARIABLE_DIGEST *Curr;
+ VARIABLE_DIGEST *Prev;
+ INTN Result;
+
+ Curr = Node;
+ while (Curr != NULL) {
+ Prev = VAR_DIG_PREV (Curr);
+ if (Prev == NULL) {
+ Result = -1;
+ } else {
+ Result = SortMethod (Prev, Node);
+ }
+
+ //
+ // 'Result > 0' means the 'Prev' is 'bigger' than 'Node'. Continue to check
+ // previous node til a node 'smaller' than 'Node' found.
+ //
+ if (Result > 0) {
+ Curr = Prev;
+ continue;
+ }
+
+ if (Curr != Node) {
+ //
+ // Remove Node first
+ //
+ if (VAR_DIG_PREV (Node) != NULL) {
+ VAR_DIG_PREV (Node)->Next = Node->Next;
+ }
+
+ if (VAR_DIG_NEXT (Node) != NULL) {
+ VAR_DIG_NEXT (Node)->Prev = Node->Prev;
+ }
+
+ //
+ // Insert Node before Curr.
+ //
+ Node->Prev = Curr->Prev;
+ Node->Next = VAR_DIG_ADR (Curr);
+
+ if (Curr->Prev != 0) {
+ VAR_DIG_PREV (Curr)->Next = VAR_DIG_ADR (Node);
+ }
+
+ Curr->Prev = VAR_DIG_ADR (Node);
+ }
+
+ //
+ // If there're two identical variables in storage, one of them must be
+ // "in-delete-transition" state. Mark it as "deleted" anyway.
+ //
+ if (Result == 0) {
+ if (Curr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) {
+ Curr->State &= VAR_DELETED;
+ }
+
+ if (Prev->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) {
+ Prev->State &= VAR_DELETED;
+ }
+ }
+
+ break;
+ }
+}
+
+/**
+
+ Create variable digest node.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] NameSize Size of variable name.
+ @param[in] DataSize Size of variable data.
+ @param[in] AuthVar Authenticated variable flag.
+ @param[in] Global Pointer to global configuration data.
+
+ @retval Ptr Pointer to variable digest
+
+**/
+VARIABLE_DIGEST *
+CreateVariableDigestNode (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT16 NameSize,
+ IN UINT32 DataSize,
+ IN BOOLEAN AuthVar,
+ IN PROTECTED_VARIABLE_GLOBAL *Global
+ )
+{
+ VARIABLE_DIGEST *VarDig;
+ VOID *Buffer;
+ UINTN VarSize;
+
+ VarDig = (VARIABLE_DIGEST *)AllocateZeroPool (
+ sizeof (VARIABLE_DIGEST) + NameSize + METADATA_HMAC_SIZE
+ );
+ if ((VarDig == NULL) || (Global == NULL)) {
+ ASSERT (VarDig != NULL);
+ ASSERT (Global != NULL);
+ return NULL;
+ }
+
+ VarDig->DataSize = DataSize;
+ VarDig->NameSize = NameSize;
+ VarDig->DigestSize = METADATA_HMAC_SIZE;
+ VarDig->State = VAR_ADDED;
+ VarDig->Attributes = VARIABLE_ATTRIBUTE_NV_BS_RT;
+ VarDig->Flags.Auth = AuthVar;
+ VarDig->Flags.Valid = TRUE;
+ VarDig->Flags.Freeable = TRUE;
+ VarDig->Flags.Protected = PcdGetBool (PcdProtectedVariableIntegrity);
+ VarDig->Flags.Encrypted = PcdGetBool (PcdProtectedVariableConfidentiality);
+ VarDig->StoreIndex = VAR_INDEX_INVALID;
+ VarDig->CacheIndex = VAR_INDEX_INVALID;
+
+ if (Global->Flags.CacheReady == TRUE) {
+ VarSize = VARIABLE_HEADER_SIZE (VarDig->Flags.Auth);
+ VarSize += VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize);
+ VarSize += VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize);
+ VarSize = HEADER_ALIGN (VarSize);
+
+ Buffer = AllocateZeroPool (VarSize);
+ if (Buffer != NULL) {
+ VarDig->CacheIndex = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+ }
+ }
+
+ CopyMem (VAR_DIG_NAME (VarDig), VariableName, NameSize);
+ CopyMem (VAR_DIG_GUID (VarDig), VendorGuid, sizeof (EFI_GUID));
+
+ return VarDig;
+}
+
+/**
+
+ Remove variable digest node.
+
+ @param[in,out] Global Pointer to global configuration data.
+ @param[in,out] VarDig Pointer to variable digest value.
+ @param[in] FreeResource Flag to indicate whether to free resource.
+
+**/
+VOID
+RemoveVariableDigestNode (
+ IN OUT PROTECTED_VARIABLE_GLOBAL *Global,
+ IN OUT VARIABLE_DIGEST *VarDig,
+ IN BOOLEAN FreeResource
+ )
+{
+ VARIABLE_DIGEST *Prev;
+ VARIABLE_DIGEST *Next;
+
+ Prev = VAR_DIG_PREV (VarDig);
+ Next = VAR_DIG_NEXT (VarDig);
+
+ if (Global->VariableDigests == VAR_DIG_ADR (VarDig)) {
+ Global->VariableDigests = VAR_DIG_ADR (Next);
+ }
+
+ if (Prev != NULL) {
+ Prev->Next = VAR_DIG_ADR (Next);
+ }
+
+ if (Next != NULL) {
+ Next->Prev = VAR_DIG_ADR (Prev);
+ }
+
+ VarDig->Prev = 0;
+ VarDig->Next = 0;
+ VarDig->Flags.Valid = FALSE;
+
+ if (FreeResource && VarDig->Flags.Freeable) {
+ if ((VarDig->CacheIndex != 0) && (VarDig->CacheIndex != VAR_INDEX_INVALID)) {
+ VarDig->CacheIndex = VAR_INDEX_INVALID;
+ }
+ }
+}
+
+/**
+
+ Insert variable digest node.
+
+ @param[in,out] Global Pointer to global configuration data.
+ @param[in] VarDig Pointer to variable digest value.
+ @param[in] SortMethod Method for sorting.
+
+**/
+VOID
+InsertVariableDigestNode (
+ IN OUT PROTECTED_VARIABLE_GLOBAL *Global,
+ IN VARIABLE_DIGEST *VarDig,
+ IN SORT_METHOD SortMethod
+ )
+{
+ VARIABLE_DIGEST *Curr;
+ VARIABLE_DIGEST *Prev;
+ BOOLEAN DoReplace;
+ INTN Result;
+
+ if (SortMethod == NULL) {
+ SortMethod = CompareVariableDigestInfo;
+ }
+
+ DoReplace = FALSE;
+ Curr = VAR_DIG_PTR (Global->VariableDigests);
+ if (Curr == NULL) {
+ //
+ // First one.
+ //
+ VarDig->Prev = 0;
+ VarDig->Next = 0;
+ Global->VariableDigests = VAR_DIG_ADR (VarDig);
+ return;
+ }
+
+ while (Curr != NULL && Curr != VarDig) {
+ Result = SortMethod (VarDig, Curr);
+
+ if (Result <= 0) {
+ ASSERT (VarDig->StoreIndex != Curr->StoreIndex);
+
+ //
+ // The same variable already in list?
+ //
+ if (Result == 0) {
+ //
+ // Keep only the same new one, unless states are different. In such
+ // situation, the one with no VAR_ADDED will be deleted.
+ //
+ if (VarDig->State >= Curr->State) {
+ DoReplace = TRUE;
+ Curr->Flags.Valid = FALSE; // to-be-deleted
+ } else {
+ DoReplace = FALSE;
+ VarDig->Flags.Valid = FALSE; // to-be-deleted
+ }
+ }
+
+ //
+ // Put VarDig before Curr
+ //
+ VarDig->Next = VAR_DIG_ADR (Curr);
+ VarDig->Prev = Curr->Prev;
+
+ if (VAR_DIG_PREV (Curr) != NULL) {
+ VAR_DIG_PREV (Curr)->Next = VAR_DIG_ADR (VarDig);
+ }
+
+ Curr->Prev = VAR_DIG_ADR (VarDig);
+
+ if (DoReplace) {
+ RemoveVariableDigestNode (Global, Curr, TRUE);
+ }
+
+ break;
+ }
+
+ Prev = Curr;
+ Curr = VAR_DIG_NEXT (Curr);
+ if (Curr == NULL) {
+ Prev->Next = VAR_DIG_ADR (VarDig);
+
+ VarDig->Prev = VAR_DIG_ADR (Prev);
+ VarDig->Next = 0;
+ }
+ }
+
+ //
+ // Update the head node if necessary.
+ //
+ if (VAR_DIG_PTR (VarDig->Prev) == NULL) {
+ Global->VariableDigests = VAR_DIG_ADR (VarDig);
+ }
+}
+
+/**
+
+ Find the specified variable digest
+
+ @param[in] Global Pointer to global configuration data.
+ @param[in] VarInfo Pointer to variable data.
+ @param[in] FindNext Flag to continue looking for variable.
+
+**/
+VARIABLE_DIGEST *
+FindVariableInternal (
+ IN PROTECTED_VARIABLE_GLOBAL *Global,
+ IN PROTECTED_VARIABLE_INFO *VarInfo,
+ IN BOOLEAN FindNext
+ )
+{
+ VARIABLE_DIGEST *VarDig;
+ VARIABLE_DIGEST *Found;
+ VARIABLE_DIGEST *FirstStoreIndexVar;
+ BOOLEAN ByIndex;
+ INTN FwdOrBwd;
+
+ //
+ // If VarInfo->StoreIndex is valid, use it to find the variable. Otherwise,
+ // use the variable name and guid instead, if given. If no clue at all, return
+ // the variable with lowest StoreIndex.
+ //
+ if ( (VarInfo->StoreIndex != VAR_INDEX_INVALID)
+ || (VarInfo->Header.VariableName == NULL)
+ || (VarInfo->Header.VendorGuid == NULL))
+ {
+ ByIndex = TRUE;
+ } else {
+ ByIndex = FALSE;
+ }
+
+ Found = NULL;
+ VarDig = VAR_DIG_PTR (Global->VariableDigests);
+ FirstStoreIndexVar = VarDig;
+ FwdOrBwd = 1;
+
+ //
+ // Discover variable with first/smallest store index
+ //
+ while (VarDig != NULL) {
+ if (VarDig->StoreIndex < FirstStoreIndexVar->StoreIndex) {
+ FirstStoreIndexVar = VAR_DIG_PTR (VarDig);
+ }
+
+ VarDig = VAR_DIG_NEXT (VarDig);
+ }
+
+ //
+ // Input variable is NULL than return first variable
+ // with smallest store index from the variable digest list.
+ //
+ if (((VarInfo->Header.VariableName == NULL) ||
+ (VarInfo->Header.VendorGuid == NULL)) &&
+ (ByIndex == FALSE))
+ {
+ return FirstStoreIndexVar;
+ }
+
+ //
+ // Start with first entry
+ //
+ VarDig = VAR_DIG_PTR (Global->VariableDigests);
+ while (VarDig != NULL) {
+ if (ByIndex) {
+ if (FindNext) {
+ if (VarDig->StoreIndex == VarInfo->StoreIndex) {
+ Found = VarDig = VAR_DIG_NEXT (VarDig);
+ break;
+ }
+ } else if (VarDig->StoreIndex == VarInfo->StoreIndex) {
+ Found = VarDig;
+ break;
+ }
+ } else {
+ //
+ // Match given variable name and vendor guid.
+ //
+ if (IS_VARIABLE (&VarInfo->Header, VAR_DIG_NAME (VarDig), VAR_DIG_GUID (VarDig))) {
+ Found = (FindNext) ? VAR_DIG_NEXT (VarDig) : VarDig;
+ break;
+ }
+ }
+
+ VarDig = (FwdOrBwd > 0) ? VAR_DIG_NEXT (VarDig) : VAR_DIG_PREV (VarDig);
+ if (VarDig == NULL) {
+ }
+ }
+
+ return Found;
+}
+
+/**
+
+ Synchronize the RPMC counters
+
+ @param[in] Global Pointer to global configuration data.
+ @param[in] VarInfo Pointer to variable data.
+ @param[in] FindNext Flag to continue looking for variable.
+
+ @retval EFI_SUCCESS Successfully sync RPMC counters.
+ @return others Failed to sync RPMC counters.
+
+**/
+EFI_STATUS
+SyncRpmcCounter (
+ VOID
+ )
+{
+ UINT32 Counter1;
+ UINT32 Counter2;
+ EFI_STATUS Status;
+
+ //
+ // Sync RPMC1 & RPMC2.
+ //
+ Status = RequestMonotonicCounter (RPMC_COUNTER_1, &Counter1);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ Status = RequestMonotonicCounter (RPMC_COUNTER_2, &Counter2);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ while (Counter1 < Counter2) {
+ Status = IncrementMonotonicCounter (RPMC_COUNTER_1);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ ++Counter1;
+ }
+
+ while (Counter2 < Counter1) {
+ Status = IncrementMonotonicCounter (RPMC_COUNTER_2);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ ++Counter2;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ An alternative version of ProtectedVariableLibGetData to get plain data from
+ given variable, if encrypted.
+
+ @param[in] Global Pointer to global configuration data.
+ @param[in,out] VarInfo Pointer to structure containing variable
+ information. VarInfo->Header.Data must point
+ to the original variable data.
+
+ @retval EFI_SUCCESS Found the specified variable.
+ @retval EFI_INVALID_PARAMETER VarInfo is NULL or both VarInfo->Buffer and
+ VarInfo->Offset are invalid.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+
+**/
+STATIC
+EFI_STATUS
+ProtectedVariableLibGetDataInternal (
+ IN PROTECTED_VARIABLE_GLOBAL *Global,
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_CONTEXT_IN *ContextIn;
+ VOID *Buffer;
+ UINTN BufferSize;
+
+ if ((Global == NULL) || (VarInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ContextIn = GET_CNTX (Global);
+
+ //
+ // Check if the data has been decrypted or not.
+ //
+ VarInfo->CipherData = NULL;
+ VarInfo->CipherDataSize = 0;
+ VarInfo->PlainData = NULL;
+ VarInfo->PlainDataSize = 0;
+ Status = GetCipherDataInfo (VarInfo);
+
+ if ((Status == EFI_UNSUPPORTED) || (Status == EFI_NOT_FOUND)) {
+ VarInfo->Flags.DecryptInPlace = TRUE;
+ VarInfo->PlainDataSize = (UINT32)VarInfo->Header.DataSize;
+ VarInfo->PlainData = VarInfo->Header.Data;
+ VarInfo->CipherDataType = 0;
+ VarInfo->CipherHeaderSize = 0;
+ Status = EFI_SUCCESS;
+ } else if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ //
+ // If the variable data is cipher data, decrypt it inplace if possible.
+ //
+ if ((VarInfo->PlainData == NULL) && (VarInfo->CipherData != NULL)) {
+ VarInfo->Key = Global->RootKey;
+ VarInfo->KeySize = sizeof (Global->RootKey);
+
+ switch (ContextIn->VariableServiceUser) {
+ case FromPeiModule:
+ VarInfo->Flags.DecryptInPlace = FALSE;
+ //
+ // In PEI VariableCache holds Cipher header + Cipher data
+ // Do not override Cipher header data during decrypt operation
+ //
+ VarInfo->PlainData = GET_BUFR (Global->VariableCache + VarInfo->CipherHeaderSize);
+
+ Status = DecryptVariable (VarInfo);
+ if (Status == EFI_UNSUPPORTED) {
+ VarInfo->PlainData = VarInfo->Header.Data;
+ VarInfo->PlainDataSize = (UINT32)VarInfo->Header.DataSize;
+ VarInfo->CipherDataType = 0;
+ VarInfo->CipherHeaderSize = 0;
+
+ Status = EFI_SUCCESS;
+ }
+
+ break;
+
+ case FromSmmModule:
+ VarInfo->Flags.DecryptInPlace = FALSE;
+ VarInfo->PlainData = GET_BUFR (Global->VariableCache);
+
+ Status = DecryptVariable (VarInfo);
+ if (Status == EFI_UNSUPPORTED) {
+ VarInfo->PlainData = VarInfo->Header.Data;
+ VarInfo->PlainDataSize = (UINT32)VarInfo->Header.DataSize;
+ VarInfo->CipherDataType = 0;
+ VarInfo->CipherHeaderSize = 0;
+
+ Status = EFI_SUCCESS;
+ }
+
+ break;
+
+ case FromBootServiceModule:
+ case FromRuntimeModule:
+ //
+ // The SMM passes back only decrypted data. We re-use the original cipher
+ // data buffer to keep the plain data along with the cipher header.
+ //
+ VarInfo->Flags.DecryptInPlace = TRUE;
+ Buffer = (VOID *)((UINTN)VarInfo->CipherData + VarInfo->CipherHeaderSize);
+ BufferSize = VarInfo->PlainDataSize;
+ Status = ContextIn->FindVariableSmm (
+ VarInfo->Header.VariableName,
+ VarInfo->Header.VendorGuid,
+ &VarInfo->Header.Attributes,
+ &BufferSize,
+ Buffer
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Flag the payload as plain data to avoid re-decrypting.
+ //
+ VarInfo->CipherDataType = ENC_TYPE_NULL;
+ VarInfo->PlainDataSize = (UINT32)BufferSize;
+ VarInfo->PlainData = Buffer;
+
+ Status = SetCipherDataInfo (VarInfo);
+ if (Status == EFI_UNSUPPORTED) {
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+ VarInfo->CipherData = NULL;
+ VarInfo->CipherDataSize = 0;
+ }
+
+ return Status;
+}
+
+/**
+
+ An alternative version of ProtectedVariableLibGetData to get plain data, if
+ encrypted, from given variable, for different use cases.
+
+ @param[in,out] VarInfo Pointer to structure containing variable information.
+
+ @retval EFI_SUCCESS Found the specified variable.
+ @retval EFI_INVALID_PARAMETER VarInfo is NULL or both VarInfo->Buffer and
+ VarInfo->Offset are invalid.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByInfo (
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_GLOBAL *Global;
+ VOID **Buffer;
+ UINT32 BufferSize;
+
+ Status = GetProtectedVariableGlobal (&Global);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ //
+ // Save the output data buffer because below call
+ // call will use this struct field internally.
+ //
+ Buffer = VarInfo->PlainData;
+ BufferSize = VarInfo->PlainDataSize;
+
+ Status = ProtectedVariableLibGetDataInternal (Global, VarInfo);
+ if (EFI_ERROR (Status)) {
+ //
+ // Return with caller provided buffer with zero DataSize
+ //
+ VarInfo->PlainData = Buffer;
+ VarInfo->PlainDataSize = 0;
+ return Status;
+ }
+
+ if ((Buffer == NULL) || ((BufferSize) < VarInfo->PlainDataSize)) {
+ //
+ // Return with caller provided buffer with true PlainDataSize
+ //
+ VarInfo->PlainData = Buffer;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Copy Plain data to ouput data buffer
+ //
+ CopyMem (Buffer, VarInfo->PlainData, VarInfo->PlainDataSize);
+ VarInfo->PlainData = Buffer;
+
+ return Status;
+}
+
+/**
+
+ Retrieve plain data, if encrypted, of given variable.
+
+ If variable encryption is employed, this function will initiate a SMM request
+ to get the plain data. Due to security consideration, the decryption can only
+ be done in SMM environment.
+
+ @param[in] Variable Pointer to header of a Variable.
+ @param[in,out] Data Pointer to plain data of the given variable.
+ @param[in,out] DataSize Size of data returned or data buffer needed.
+ @param[in] AuthFlag Auth-variable indicator.
+
+ @retval EFI_SUCCESS Found the specified variable.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL If *DataSize is smaller than needed.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByBuffer (
+ IN VARIABLE_HEADER *Variable,
+ IN OUT VOID *Data,
+ IN OUT UINT32 *DataSize,
+ IN BOOLEAN AuthFlag
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_INFO VarInfo;
+ PROTECTED_VARIABLE_GLOBAL *Global;
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+ VOID *Buffer;
+
+ if ((Variable == NULL) || (DataSize == NULL)) {
+ ASSERT (Variable != NULL);
+ ASSERT (DataSize != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetProtectedVariableGlobal (&Global);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ ZeroMem (&VarInfo, sizeof (VarInfo));
+
+ VarInfo.Buffer = Variable;
+ VarInfo.Flags.Auth = AuthFlag;
+
+ if (VarInfo.Flags.Auth == TRUE) {
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+
+ VarInfo.Header.VariableName = (CHAR16 *)((UINTN)Variable + sizeof (AUTHENTICATED_VARIABLE_HEADER));
+ VarInfo.Header.NameSize = AuthVariable->NameSize;
+ VarInfo.Header.VendorGuid = &AuthVariable->VendorGuid;
+ VarInfo.Header.Attributes = AuthVariable->Attributes;
+ VarInfo.Header.DataSize = AuthVariable->DataSize;
+ } else {
+ VarInfo.Header.VariableName = (CHAR16 *)((UINTN)Variable + sizeof (VARIABLE_HEADER));
+ VarInfo.Header.NameSize = Variable->NameSize;
+ VarInfo.Header.VendorGuid = &Variable->VendorGuid;
+ VarInfo.Header.Attributes = Variable->Attributes;
+ VarInfo.Header.DataSize = Variable->DataSize;
+ }
+
+ Buffer = VARIABLE_NAME (VarInfo.Buffer, VarInfo.Flags.Auth);
+ Buffer = GET_BUFR (GET_ADRS (Buffer) + VarInfo.Header.NameSize);
+ Buffer = GET_BUFR (GET_ADRS (Buffer) + GET_PAD_SIZE (VarInfo.Header.NameSize));
+ VarInfo.Header.Data = Buffer;
+
+ Status = ProtectedVariableLibGetDataInternal (Global, &VarInfo);
+ if (!EFI_ERROR (Status)) {
+ if ((*DataSize) < VarInfo.PlainDataSize) {
+ *DataSize = VarInfo.PlainDataSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *DataSize = VarInfo.PlainDataSize;
+ CopyMem (Data, VarInfo.PlainData, VarInfo.PlainDataSize);
+ }
+
+ return Status;
+}
+
+/**
+ This service retrieves a variable's value using its name and GUID.
+
+ Read the specified variable from the UEFI variable store. If the Data
+ buffer is too small to hold the contents of the variable, the error
+ EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+ size to obtain the data.
+
+ @param VariableName A pointer to a null-terminated string that is the variable's name.
+ @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+ @param Attributes If non-NULL, on return, points to the variable's attributes.
+ @param DataSize On entry, points to the size in bytes of the Data buffer.
+ On return, points to the size of the data returned in Data.
+ @param Data Points to the buffer which will hold the returned variable value.
+ May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable was be found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
+ DataSize is updated with the size required for
+ the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByName (
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_CONTEXT_IN *ContextIn;
+ PROTECTED_VARIABLE_GLOBAL *Global;
+ VARIABLE_DIGEST *VarDig;
+ PROTECTED_VARIABLE_INFO VarInfo;
+ EFI_TIME TimeStamp;
+ VOID *DataBuffer;
+
+ if ((VariableName == NULL) || (VariableGuid == NULL) || (DataSize == NULL)) {
+ ASSERT (VariableName != NULL);
+ ASSERT (VariableGuid != NULL);
+ ASSERT (DataSize != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetProtectedVariableGlobal (&Global);
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ContextIn = GET_CNTX (Global);
+
+ ZeroMem (&VarInfo, sizeof (VarInfo));
+ VarInfo.StoreIndex = VAR_INDEX_INVALID;
+ VarInfo.Header.VariableName = (CHAR16 *)VariableName;
+ VarInfo.Header.NameSize = StrSize (VariableName);
+ VarInfo.Header.VendorGuid = (EFI_GUID *)VariableGuid;
+
+ VarDig = FindVariableInternal (Global, &VarInfo, FALSE);
+ if (VarDig == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Attributes != NULL) {
+ *Attributes = VarDig->Attributes;
+ }
+
+ if ((Data == NULL) || (*DataSize < VarDig->PlainDataSize)) {
+ *DataSize = VarDig->PlainDataSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ VarInfo.Flags.Auth = VarDig->Flags.Auth;
+ VarInfo.Flags.Protected = VarDig->Flags.Protected;
+
+ //
+ // Verify digest before copy the data back, if the variable is not in cache.
+ //
+ if (VarDig->CacheIndex != VAR_INDEX_INVALID) {
+ VarInfo.Header.VariableName = NULL;
+ VarInfo.Header.VendorGuid = NULL;
+ VarInfo.Buffer = GET_BUFR (VarDig->CacheIndex);
+
+ Status = ContextIn->GetVariableInfo (&VarInfo);
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ //
+ // A buffer for at least one variable data (<=PcdMax(Auth)VariableSize)
+ // must be reserved in advance.
+ //
+ ASSERT (
+ Global->VariableCache != 0
+ && Global->VariableCacheSize >= VarDig->DataSize
+ );
+ DataBuffer = GET_BUFR (Global->VariableCache);
+ //
+ // Note name and GUID are already there.
+ //
+ VarInfo.StoreIndex = VarDig->StoreIndex;
+
+ VarInfo.Header.VariableName = NULL; // Prevent name from being retrieved again.
+ VarInfo.Header.NameSize = 0;
+ VarInfo.Header.VendorGuid = NULL; // Prevent guid from being retrieved again.
+ VarInfo.Header.TimeStamp = &TimeStamp;
+ VarInfo.Header.Data = DataBuffer;
+ VarInfo.Header.DataSize = VarDig->DataSize;
+
+ //
+ // Get detailed information about the variable.
+ //
+ Status = ContextIn->GetVariableInfo (&VarInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // The variable must be validated its digest value to avoid TOCTOU, if it's
+ // not been cached yet.
+ //
+ VarInfo.Header.VariableName = VAR_DIG_NAME (VarDig);
+ VarInfo.Header.NameSize = VarDig->NameSize;
+ VarInfo.Header.VendorGuid = &VarDig->VendorGuid;
+ Status = VerifyVariableDigest (Global, &VarInfo, VarDig);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Decrypt the data, if necessary.
+ //
+ Status = ProtectedVariableLibGetDataInternal (Global, &VarInfo);
+ if (!EFI_ERROR (Status)) {
+ if (*DataSize < VarInfo.PlainDataSize) {
+ *DataSize = VarInfo.PlainDataSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *DataSize = VarInfo.PlainDataSize;
+ CopyMem (Data, VarInfo.PlainData, VarInfo.PlainDataSize);
+ }
+
+ return Status;
+}
+
+/**
+
+ This function is used to enumerate the variables managed by current
+ ProtectedVariableLib.
+
+ If the VarInfo->StoreIndex is invalid (VAR_INDEX_INVALID), the first variable
+ with the smallest StoreIndex will be returned. Otherwise, the variable with
+ StoreIndex just after than the VarInfo->StoreIndex will be returned.
+
+ @param[in,out] VarInfo Pointer to structure containing variable information.
+
+ @retval EFI_SUCCESS Found the specified variable.
+ @retval EFI_INVALID_PARAMETER VarInfo is NULL.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+
+**/
+STATIC
+EFI_STATUS
+GetNextVariableInternal (
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_GLOBAL *Global;
+ VARIABLE_DIGEST *Found;
+
+ if (VarInfo == NULL) {
+ ASSERT (VarInfo != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetProtectedVariableGlobal (&Global);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ Found = FindVariableInternal (Global, VarInfo, TRUE);
+ if (Found == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Return all cached data.
+ //
+ VarInfo->Header.VariableName = VAR_DIG_NAME (Found);
+ VarInfo->Header.VendorGuid = VAR_DIG_GUID (Found);
+ VarInfo->Header.NameSize = Found->NameSize;
+ VarInfo->Header.DataSize = Found->DataSize;
+ VarInfo->Header.Attributes = Found->Attributes;
+
+ VarInfo->PlainDataSize = Found->PlainDataSize;
+ VarInfo->StoreIndex = Found->StoreIndex;
+ if (Found->CacheIndex != VAR_INDEX_INVALID) {
+ VarInfo->Buffer = GET_BUFR (Found->CacheIndex);
+ }
+
+ VarInfo->Flags.Auth = Found->Flags.Auth;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Find the request variable.
+
+ @param[in, out] VarInfo Pointer to variable data.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_INVALID_PARAMETER Variable info is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFind (
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_GLOBAL *Global;
+ VARIABLE_DIGEST *Found;
+
+ if (VarInfo == NULL) {
+ ASSERT (VarInfo != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetProtectedVariableGlobal (&Global);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ Found = FindVariableInternal (Global, VarInfo, FALSE);
+ if (Found == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Return all cached data.
+ //
+ VarInfo->Header.VariableName = VAR_DIG_NAME (Found);
+ VarInfo->Header.VendorGuid = VAR_DIG_GUID (Found);
+ VarInfo->Header.NameSize = Found->NameSize;
+ VarInfo->Header.DataSize = Found->DataSize;
+ VarInfo->Header.Attributes = Found->Attributes;
+
+ VarInfo->PlainDataSize = Found->PlainDataSize;
+ VarInfo->StoreIndex = Found->StoreIndex;
+ if (Found->CacheIndex != VAR_INDEX_INVALID) {
+ VarInfo->Buffer = GET_BUFR (Found->CacheIndex);
+ }
+
+ VarInfo->Flags.Auth = Found->Flags.Auth;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the next variable name and GUID.
+
+ This function is called multiple times to retrieve the VariableName
+ and VariableGuid of all variables currently available in the system.
+ On each call, the previous results are passed into the interface,
+ and, on return, the interface returns the data for the next
+ interface. When the entire variable list has been returned,
+ EFI_NOT_FOUND is returned.
+
+ @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ On return, the size of the variable name buffer.
+ @param VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+ @param VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFindNext (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_INFO VarInfo;
+ PROTECTED_VARIABLE_GLOBAL *Global;
+ VARIABLE_DIGEST *VarDig;
+ UINTN Size;
+
+ if ((VariableNameSize == NULL) || (VariableName == NULL) || (VariableGuid == NULL)) {
+ ASSERT (VariableNameSize != NULL);
+ ASSERT (VariableName != NULL);
+ ASSERT (VariableGuid != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetProtectedVariableGlobal (&Global);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SetMem (&VarInfo, sizeof (VarInfo), 0);
+ Size = StrSize (VariableName);
+
+ if (Size <= 2) {
+ VarDig = VAR_DIG_PTR (Global->VariableDigests);
+ } else {
+ VarInfo.Header.VariableName = VariableName;
+ VarInfo.Header.NameSize = Size;
+ VarInfo.Header.VendorGuid = VariableGuid;
+
+ VarInfo.StoreIndex = VAR_INDEX_INVALID;
+
+ VarDig = FindVariableInternal (Global, &VarInfo, TRUE);
+ }
+
+ if (VarDig == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (VarDig->NameSize > *VariableNameSize) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ CopyMem (VariableName, VAR_DIG_NAME (VarDig), VarDig->NameSize);
+ CopyGuid (VariableGuid, &VarDig->VendorGuid);
+ *VariableNameSize = VarInfo.Header.NameSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Return the next variable name and GUID.
+
+ @param[in, out] VarInfo Pointer to variable data.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_INVALID_PARAMETER VarInfo is NULL.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFindNextEx (
+ IN OUT PROTECTED_VARIABLE_INFO *VarInfo
+ )
+{
+ return GetNextVariableInternal (VarInfo);
+}
+
+/**
+
+ Return the max count of a variable.
+
+ @return max count of a variable.
+
+**/
+UINTN
+ProtectedVariableLibGetMaxVariablesCount (
+ VOID
+ )
+{
+ PROTECTED_VARIABLE_GLOBAL *Global;
+ PROTECTED_VARIABLE_INFO VarInfo;
+ VARIABLE_DIGEST *VarDig;
+ EFI_STATUS Status;
+ UINTN Count;
+
+ Status = GetProtectedVariableGlobal (&Global);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return 0;
+ }
+
+ Count = 0;
+ ZeroMem (&VarInfo, sizeof (VarInfo));
+
+ //
+ // Start with first entry
+ //
+ VarDig = VAR_DIG_PTR (Global->VariableDigests);
+ VarInfo.Header.VariableName = VAR_DIG_NAME (VarDig);
+ VarInfo.Header.VendorGuid = VAR_DIG_GUID (VarDig);
+ VarInfo.StoreIndex = VarDig->StoreIndex;
+
+ do {
+ VarInfo.Buffer = NULL;
+ Status = ProtectedVariableLibFindNextEx (&VarInfo);
+ if (EFI_ERROR (Status)) {
+ return Count;
+ }
+
+ Count++;
+ } while (TRUE);
+}
+
+/**
+ The function is called by PerformQuickSort to sort.
+
+ @param[in] Left The pointer to first buffer.
+ @param[in] Right The pointer to second buffer.
+
+ @retval 0 Buffer1 equal to Buffer2.
+ @return < 0 Buffer1 is less than Buffer2.
+ @return > 0 Buffer1 is greater than Buffer2.
+
+**/
+INTN
+EFIAPI
+CompareStoreIndex (
+ IN CONST VOID *Left,
+ IN CONST VOID *Right
+ )
+{
+ EFI_PHYSICAL_ADDRESS StoreIndex1;
+ EFI_PHYSICAL_ADDRESS StoreIndex2;
+
+ StoreIndex1 = (*(EFI_PHYSICAL_ADDRESS *)Left);
+ StoreIndex2 = (*(EFI_PHYSICAL_ADDRESS *)Right);
+
+ if (StoreIndex1 == StoreIndex2) {
+ return (0);
+ }
+
+ if (StoreIndex1 < StoreIndex2) {
+ return (-1);
+ }
+
+ return (1);
+}
+
+/**
+ Refresh variable information changed by variable service.
+
+ @param Buffer Pointer to a pointer of buffer.
+ @param NumElements Pointer to number of elements in list.
+
+
+ @return EFI_SUCCESS Successfully retrieved sorted list.
+ @return others Unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetSortedList (
+ IN OUT EFI_PHYSICAL_ADDRESS **Buffer,
+ IN OUT UINTN *NumElements
+ )
+{
+ EFI_STATUS Status;
+ UINTN Count;
+ UINTN StoreIndexTableSize;
+ EFI_PHYSICAL_ADDRESS *StoreIndexTable;
+ PROTECTED_VARIABLE_INFO VarInfo;
+ PROTECTED_VARIABLE_GLOBAL *Global;
+ VARIABLE_DIGEST *VarDig;
+
+ Status = GetProtectedVariableGlobal (&Global);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ Count = 0;
+ ZeroMem (&VarInfo, sizeof (VarInfo));
+ StoreIndexTableSize = ProtectedVariableLibGetMaxVariablesCount ();
+ StoreIndexTable = AllocateZeroPool (sizeof (EFI_PHYSICAL_ADDRESS) * StoreIndexTableSize);
+
+ //
+ // Start with first entry
+ //
+ VarDig = VAR_DIG_PTR (Global->VariableDigests);
+ VarInfo.Header.VariableName = VAR_DIG_NAME (VarDig);
+ VarInfo.Header.VendorGuid = VAR_DIG_GUID (VarDig);
+ VarInfo.StoreIndex = VarDig->StoreIndex;
+ StoreIndexTable[Count] = VarInfo.StoreIndex;
+ Count++;
+
+ //
+ // Populate the un-sorted table
+ //
+ do {
+ VarInfo.Buffer = NULL;
+ Status = ProtectedVariableLibFindNextEx (&VarInfo);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ StoreIndexTable[Count] = VarInfo.StoreIndex;
+ Count++;
+ } while (TRUE);
+
+ PerformQuickSort (
+ StoreIndexTable,
+ Count,
+ sizeof (EFI_PHYSICAL_ADDRESS),
+ (SORT_COMPARE)CompareStoreIndex
+ );
+
+ *Buffer = StoreIndexTable;
+ *NumElements = Count;
+
+ return EFI_SUCCESS;
+}
diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
new file mode 100644
index 000000000000..94df21eacf25
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
@@ -0,0 +1,163 @@
+/** @file
+ Implemention of ProtectedVariableLib for SMM variable services.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Uefi.h>
+
+#include "Library/UefiBootServicesTableLib.h"
+#include "Library/MemoryAllocationLib.h"
+
+#include "ProtectedVariableInternal.h"
+
+PROTECTED_VARIABLE_CONTEXT_IN mVariableContextIn = {
+ PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION,
+ sizeof (PROTECTED_VARIABLE_CONTEXT_IN),
+ 0,
+ FromSmmModule,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+PROTECTED_VARIABLE_GLOBAL mProtectedVariableGlobal = {
+ PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION,
+ sizeof (PROTECTED_VARIABLE_GLOBAL),
+ { 0 },
+ { 0 },
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ { 0, 0, 0 },
+ 0,
+ 0,
+ { 0, 0, 0, 0, 0, 0}
+};
+
+/**
+ Fix incorrect state of MetaDataHmacVariable before any variable update.
+
+ @param[in] Event The event that occurred
+ @param[in] Context For EFI compatibility. Not used.
+
+**/
+VOID
+EFIAPI
+VariableWriteProtocolCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Fix incorrect state of MetaDataHmacVariable before any variable update.
+ // This has to be done here due to the fact that this operation needs to
+ // update NV storage but the FVB and FTW protocol might not be ready during
+ // ProtectedVariableLibInitialize().
+ //
+ Status = FixupHmacVariable ();
+ ASSERT_EFI_ERROR (Status);
+
+ Status = ProtectedVariableLibWriteInit ();
+ ASSERT_EFI_ERROR (Status);
+
+ gBS->CloseEvent (Event);
+}
+
+/**
+
+ Initialization for protected variable services.
+
+ If this initialization failed upon any error, the whole variable services
+ should not be used. A system reset might be needed to re-construct NV
+ variable storage to be the default state.
+
+ @param[in] ContextIn Pointer to variable service context needed by
+ protected variable.
+
+ @retval EFI_SUCCESS Protected variable services are ready.
+ @retval EFI_INVALID_PARAMETER If ContextIn == NULL or something missing or
+ mismatching in the content in ContextIn.
+ @retval EFI_COMPROMISED_DATA If failed to check integrity of protected variables.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibInitialize (
+ IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_CONTEXT_IN *ProtectedVarContext;
+ PROTECTED_VARIABLE_GLOBAL *OldGlobal;
+ PROTECTED_VARIABLE_GLOBAL *NewGlobal;
+ VOID *VarWriteReg;
+
+ if ( (ContextIn == NULL)
+ || (ContextIn->StructVersion != PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION)
+ || (ContextIn->StructSize != sizeof (PROTECTED_VARIABLE_CONTEXT_IN))
+ || (ContextIn->GetVariableInfo == NULL)
+ || (ContextIn->GetNextVariableInfo == NULL)
+ || (ContextIn->UpdateVariableStore == NULL)
+ || (ContextIn->UpdateVariable == NULL))
+ {
+ ASSERT (ContextIn != NULL);
+ ASSERT (ContextIn->StructVersion == PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION);
+ ASSERT (ContextIn->StructSize == sizeof (PROTECTED_VARIABLE_CONTEXT_IN));
+ ASSERT (ContextIn->GetVariableInfo != NULL);
+ ASSERT (ContextIn->GetNextVariableInfo != NULL);
+ ASSERT (ContextIn->UpdateVariableStore != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GetProtectedVariableGlobal (&NewGlobal);
+ ProtectedVarContext = GET_CNTX (NewGlobal);
+ CopyMem (ProtectedVarContext, ContextIn, sizeof (mVariableContextIn));
+ ProtectedVarContext->VariableServiceUser = FromSmmModule;
+
+ //
+ // Get root key and HMAC key from HOB created by PEI variable driver.
+ //
+ Status = GetProtectedVariableGlobalFromHob (&OldGlobal);
+ ASSERT_EFI_ERROR (Status);
+
+ CopyMem ((VOID *)NewGlobal, (CONST VOID *)OldGlobal, sizeof (*OldGlobal));
+
+ //
+ // The keys must not be available outside SMM.
+ //
+ if (ProtectedVarContext->VariableServiceUser == FromSmmModule) {
+ ZeroMem (OldGlobal->RootKey, sizeof (OldGlobal->RootKey));
+ ZeroMem (OldGlobal->MetaDataHmacKey, sizeof (OldGlobal->MetaDataHmacKey));
+ }
+
+ //
+ // Register variable write protocol notify function used to fix any
+ // inconsistency in MetaDataHmacVariable before the first variable write
+ // operation.
+ //
+ NewGlobal->Flags.WriteInit = FALSE;
+ NewGlobal->Flags.WriteReady = FALSE;
+
+ EfiCreateProtocolNotifyEvent (
+ &gEfiVariableWriteArchProtocolGuid,
+ TPL_CALLBACK,
+ VariableWriteProtocolCallback,
+ NULL,
+ &VarWriteReg
+ );
+
+ return EFI_SUCCESS;
+}
diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
new file mode 100644
index 000000000000..91d71a1e8525
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
@@ -0,0 +1,1331 @@
+/** @file
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi.h>
+#include <PiPei.h>
+
+#include <Guid/VariableFormat.h>
+#include <Ppi/MemoryDiscovered.h>
+
+#include <Library/HobLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#include "ProtectedVariableInternal.h"
+
+/**
+ Function allocates a global buffer.
+
+ This function allocates a buffer with the specified size.
+
+ @param[in] Size Size of buffer to allocate.
+ @param[in] AllocatePage Whether to allocate pages.
+
+ @retval Buffer Pointer to the Buffer allocated.
+ @retval NULL if no Buffer was found.
+
+**/
+VOID *
+AllocateGlobalBuffer (
+ IN UINT32 Size,
+ IN BOOLEAN AllocatePage
+ )
+{
+ VOID *Buffer;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
+ EFI_PEI_HOB_POINTERS Hob;
+
+ Buffer = NULL;
+ if (!AllocatePage) {
+ Buffer = BuildGuidHob (&gEdkiiProtectedVariableGlobalGuid, Size);
+ }
+
+ if (Buffer == NULL) {
+ //
+ // Use the AllocatePages() to get over size limit of general GUID-ed HOB.
+ //
+ Buffer = AllocatePages (EFI_SIZE_TO_PAGES (Size));
+ if (Buffer == NULL) {
+ ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES);
+ return NULL;
+ }
+
+ //
+ // Mark the HOB holding the pages just allocated so that it can be
+ // identified later.
+ //
+ MemoryAllocationHob = NULL;
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
+ while (Hob.Raw != NULL) {
+ MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *)Hob.Raw;
+ if ((UINTN)Buffer == (UINTN)MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress) {
+ CopyGuid (
+ &MemoryAllocationHob->AllocDescriptor.Name,
+ &gEdkiiProtectedVariableGlobalGuid
+ );
+ break;
+ }
+
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+ }
+ }
+
+ return Buffer;
+}
+
+/**
+ Callback use to re-verify all variables and cache them in memory.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] NotifyDescriptor The notification structure this PEIM registered on install.
+ @param[in] Ppi The memory discovered PPI. Not used.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval others There's error in MP initialization.
+**/
+EFI_STATUS
+EFIAPI
+MemoryDiscoveredPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_CONTEXT_IN *ContextIn;
+ PROTECTED_VARIABLE_GLOBAL *Global;
+ VARIABLE_DIGEST *VarDig;
+ PROTECTED_VARIABLE_INFO VarInfo;
+ VOID *Buffer;
+ UINT32 VarSize;
+ INTN Result;
+
+ Status = GetProtectedVariableGlobal (&Global);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ ContextIn = GET_CNTX (Global);
+
+ VarSize = Global->VariableNumber * MAX_VARIABLE_SIZE;
+ Buffer = AllocateGlobalBuffer (VarSize, TRUE);
+
+ //
+ // It's safe to store the pointer in Global->VariableCache, which has been
+ // cleared by above calling of GetProtectedVariableGlobal().
+ //
+ Global->VariableCache = GET_ADRS (Buffer);
+ Global->VariableCacheSize = EFI_SIZE_TO_PAGES (VarSize);
+
+ //
+ // Traverse all valid variables.
+ //
+ VarDig = VAR_DIG_PTR (Global->VariableDigests);
+ while (VarDig != NULL) {
+ if (VarDig->CacheIndex == VAR_INDEX_INVALID) {
+ ASSERT (VarDig->StoreIndex != VAR_INDEX_INVALID);
+
+ VarSize = VARIABLE_HEADER_SIZE (Global->Flags.Auth);
+ VarSize += VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize);
+ VarSize += VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize);
+ VarSize = HEADER_ALIGN (VarSize);
+
+ //
+ // Note the variable might be in unconsecutive space.
+ //
+ ZeroMem (&VarInfo, sizeof (VarInfo));
+ VarInfo.StoreIndex = VarDig->StoreIndex;
+ VarInfo.Buffer = Buffer;
+ VarInfo.Flags.Auth = VarDig->Flags.Auth;
+
+ Status = ContextIn->GetVariableInfo (&VarInfo);
+ ASSERT_EFI_ERROR (Status);
+ //
+ // VerifyVariableDigest() refers to CipherData for raw data.
+ //
+ VarInfo.CipherData = VarInfo.Header.Data;
+ VarInfo.CipherDataSize = (UINT32)VarInfo.Header.DataSize;
+
+ //
+ // Make sure that the cached copy is not compromised.
+ //
+ Status = VerifyVariableDigest (Global, &VarInfo, VarDig);
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED,
+ (PcdGet32 (PcdStatusCodeVariableIntegrity) | (Status & 0xFF))
+ );
+ ASSERT_EFI_ERROR (Status);
+ CpuDeadLoop ();
+ }
+
+ //
+ // Simply use the cache address as CacheIndex of the variable.
+ //
+ VarDig->CacheIndex = GET_ADRS (Buffer);
+ Buffer = (UINT8 *)Buffer + MAX_VARIABLE_SIZE;
+ } else {
+ Result = StrnCmp (
+ VAR_DIG_NAME (VarDig),
+ METADATA_HMAC_VARIABLE_NAME,
+ METADATA_HMAC_VARIABLE_NAME_SIZE
+ );
+ if (Result == 0) {
+ CopyMem (
+ Buffer,
+ GET_BUFR (Global->GlobalSelf + (Global->StructSize - GetMetaDataHmacVarSize (Global->Flags.Auth))),
+ GetMetaDataHmacVarSize (Global->Flags.Auth)
+ );
+
+ //
+ // Simply use the cache address as CacheIndex of the variable.
+ //
+ VarDig->CacheIndex = GET_ADRS (Buffer);
+ Buffer = (UINT8 *)Buffer + MAX_VARIABLE_SIZE;
+ }
+ }
+
+ VarDig = VAR_DIG_NEXT (VarDig);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Callback use to perform variable integrity check.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] NotifyDescriptor The notification structure this PEIM registered on install.
+ @param[in] Ppi The memory discovered PPI. Not used.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval others There's error in MP initialization.
+**/
+EFI_STATUS
+EFIAPI
+VariableStoreDiscoveredPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ EFI_STATUS Status;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ PROTECTED_VARIABLE_CONTEXT_IN *ContextIn;
+
+ GuidHob = GetFirstGuidHob (&gEdkiiProtectedVariableContextGuid);
+ if (GuidHob != NULL) {
+ ContextIn = (PROTECTED_VARIABLE_CONTEXT_IN *)GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ ASSERT (GuidHob == NULL);
+ }
+
+ Status = ContextIn->IsHobVariableStoreAvailable ();
+
+ if (Status == EFI_NOT_READY) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ Status = PerformVariableIntegrityCheck (ContextIn);
+
+ return Status;
+}
+
+EFI_PEI_NOTIFY_DESCRIPTOR mPostMemNotifyList[] = {
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiMemoryDiscoveredPpiGuid,
+ MemoryDiscoveredPpiNotifyCallback
+ }
+};
+
+EFI_PEI_NOTIFY_DESCRIPTOR mVariableStoreNotifyList[] = {
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiVariableStoreDiscoveredPpiGuid,
+ VariableStoreDiscoveredPpiNotifyCallback
+ }
+};
+
+/**
+
+ Get global data structure used to process protected variable.
+
+ @param[out] Global Pointer to global configuration data.
+
+ @retval EFI_SUCCESS Get requested structure successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableGlobal (
+ OUT PROTECTED_VARIABLE_GLOBAL **Global OPTIONAL
+ )
+{
+ return GetProtectedVariableGlobalFromHob (Global);
+}
+
+/**
+
+ Get context data structure used to process protected variable.
+
+ @param[out] ContextIn Pointer to context provided by variable runtime services.
+
+ @retval EFI_SUCCESS Get requested structure successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableContext (
+ PROTECTED_VARIABLE_CONTEXT_IN **ContextIn OPTIONAL
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ GuidHob = GetFirstGuidHob (&gEdkiiProtectedVariableContextGuid);
+ if (GuidHob != NULL) {
+ *ContextIn = (PROTECTED_VARIABLE_CONTEXT_IN *)GET_GUID_HOB_DATA (GuidHob);
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Verify the HMAC value stored in MetaDataHmacVar against all valid and
+ protected variables in storage.
+
+ @param[in,out] Global Pointer to global configuration data.
+
+ @retval EFI_SUCCESS The HMAC value matches.
+ @retval EFI_ABORTED Error in HMAC value calculation.
+ @retval EFI_VOLUME_CORRUPTED Inconsistency found in NV variable storage.
+ @retval EFI_COMPROMISED_DATA The HMAC value doesn't match.
+
+**/
+EFI_STATUS
+VerifyMetaDataHmac (
+ IN OUT PROTECTED_VARIABLE_GLOBAL *Global
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_DIGEST *VariableDig;
+ UINT32 Counter1;
+ UINT32 Counter2;
+ VOID *Hmac1;
+ VOID *Hmac2;
+ UINT8 HmacVal1[METADATA_HMAC_SIZE];
+ UINT8 HmacVal2[METADATA_HMAC_SIZE];
+
+ Hmac1 = NULL;
+ Hmac2 = HmacSha256New ();
+ if (Hmac2 == NULL) {
+ ASSERT (Hmac2 != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (!HmacSha256SetKey (Hmac2, Global->MetaDataHmacKey, sizeof (Global->MetaDataHmacKey))) {
+ ASSERT (FALSE);
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+
+ //
+ // Retrieve the RPMC counter value.
+ //
+ Status = RequestMonotonicCounter (RPMC_COUNTER_1, &Counter1);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ goto Done;
+ }
+
+ Status = RequestMonotonicCounter (RPMC_COUNTER_2, &Counter2);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ goto Done;
+ }
+
+ //
+ // Counter1 must be either equal to Counter2 or just one step ahead of Counter2.
+ //
+ if ((Counter1 > Counter2) && ((Counter1 - Counter2) > 1)) {
+ Status = EFI_COMPROMISED_DATA;
+ goto Done;
+ }
+
+ VariableDig = VAR_DIG_PTR (Global->VariableDigests);
+ while (VariableDig != NULL) {
+ //
+ // Only take valid protected variables into account.
+ //
+ if (VariableDig->Flags.Protected && VariableDig->Flags.Valid) {
+ if (!HmacSha256Update (
+ Hmac2,
+ VAR_DIG_VALUE (VariableDig),
+ VariableDig->DigestSize
+ ))
+ {
+ ASSERT (FALSE);
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ }
+
+ VariableDig = VAR_DIG_NEXT (VariableDig);
+ }
+
+ //
+ // If two MetaDataHmacVariable were found, check which one is valid. We might
+ // need two HMAC values to check against: one for Counter1, one for Counter2.
+ //
+ if ( (Global->Unprotected[IndexHmacAdded] != VAR_INDEX_INVALID)
+ && (Global->Unprotected[IndexHmacInDel] != VAR_INDEX_INVALID)
+ && (Counter1 != Counter2))
+ {
+ //
+ // Might need to check Counter1. There must be something wrong in last boot.
+ //
+ Hmac1 = HmacSha256New ();
+ if ((Hmac1 == NULL) || !HmacSha256Duplicate (Hmac2, Hmac1)) {
+ ASSERT (FALSE);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ if ( !HmacSha256Update (Hmac1, &Counter1, sizeof (Counter1))
+ || !HmacSha256Final (Hmac1, HmacVal1))
+ {
+ ASSERT (FALSE);
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ }
+
+ //
+ // Always check Counter2.
+ //
+ if ( !HmacSha256Update (Hmac2, &Counter2, sizeof (Counter2))
+ || !HmacSha256Final (Hmac2, HmacVal2))
+ {
+ ASSERT (FALSE);
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+
+ //
+ // When writing (update or add) a variable, there must be following steps
+ // performed:
+ //
+ // A - Increment Counter1
+ // B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
+ // C - Calculate new HMAC value against Counter2+1,
+ // and force-add a new MetaDataHmacVar with state of VAR_ADDED
+ // D - Write the new protected variable
+ // E - Increment Counter2
+ // F - Mark old MetaDataHmacVar as VAR_DELETED
+ //
+ Status = EFI_COMPROMISED_DATA;
+ if ( (Global->Unprotected[IndexHmacAdded] != VAR_INDEX_INVALID)
+ && (Global->Unprotected[IndexHmacInDel] == VAR_INDEX_INVALID))
+ {
+ if (CompareMem (
+ VAR_DIG_VALUE (VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])),
+ HmacVal2,
+ METADATA_HMAC_SIZE
+ ) == 0)
+ {
+ //
+ //
+ // + A - Increment Counter1
+ // B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
+ // C - Calculate new HMAC value against Counter2+1,
+ // and force-add a new MetaDataHmacVar with state of VAR_ADDED
+ // D - Write the new protected variable
+ // E - Increment Counter2
+ // F - Mark old MetaDataHmacVar as VAR_DELETED
+ //
+ // or,
+ //
+ // + A - Increment Counter1
+ // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
+ // + C - Calculate new HMAC value against Counter2+1,
+ // and force-add a new MetaDataHmacVar with state of VAR_ADDED
+ // + D - Write the new protected variable
+ // + E - Increment Counter2
+ // + F - Mark old MetaDataHmacVar as VAR_DELETED
+ //
+ Status = EFI_SUCCESS;
+
+ VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid = TRUE;
+ }
+ } else if ( (Global->Unprotected[IndexHmacAdded] == VAR_INDEX_INVALID)
+ && (Global->Unprotected[IndexHmacInDel] != VAR_INDEX_INVALID))
+ {
+ if (CompareMem (
+ VAR_DIG_VALUE (VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])),
+ HmacVal2,
+ METADATA_HMAC_SIZE
+ ) == 0)
+ {
+ //
+ // + A - Increment Counter1
+ // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
+ // C - Calculate new HMAC value against Counter2+1,
+ // and force-add a new MetaDataHmacVar with state of VAR_ADDED
+ // D - Write the new protected variable
+ // E - Increment Counter2
+ // F - Mark old MetaDataHmacVar as VAR_DELETED
+ //
+ Status = EFI_SUCCESS;
+
+ VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid = TRUE;
+ }
+ } else if ( (Global->Unprotected[IndexHmacAdded] != VAR_INDEX_INVALID)
+ && (Global->Unprotected[IndexHmacInDel] != VAR_INDEX_INVALID))
+ {
+ if (Counter1 > Counter2) {
+ if (CompareMem (
+ VAR_DIG_VALUE (VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])),
+ HmacVal2,
+ METADATA_HMAC_SIZE
+ ) == 0)
+ {
+ //
+ // + A - Increment Counter1
+ // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
+ // + C - Calculate new HMAC value against Counter2+1,
+ // and force-add a new MetaDataHmacVar with state VAR_ADDED
+ // D - Write the new protected variable
+ // E - Increment Counter2
+ // F - Mark old MetaDataHmacVar as VAR_DELETED
+ //
+ Status = EFI_SUCCESS;
+
+ VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid = FALSE;
+ VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid = TRUE;
+ } else if (CompareMem (
+ VAR_DIG_VALUE (VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])),
+ HmacVal1,
+ METADATA_HMAC_SIZE
+ ) == 0)
+ {
+ //
+ // + A - Increment Counter1
+ // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
+ // + C - Calculate new HMAC value against Counter2+1,
+ // and force-add a new MetaDataHmacVar with state of VAR_ADDED
+ // + D - Write the new protected variable
+ // E - Increment Counter2
+ // F - Mark old MetaDataHmacVar as VAR_DELETED
+ //
+ Status = EFI_SUCCESS;
+
+ VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid = TRUE;
+ VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid = FALSE;
+ }
+ } else {
+ if (CompareMem (
+ VAR_DIG_VALUE (VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])),
+ HmacVal2,
+ METADATA_HMAC_SIZE
+ ) == 0)
+ {
+ //
+ // + A - Increment Counter1
+ // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
+ // + C - Calculate new HMAC value against Counter2+1,
+ // and force-add a new MetaDataHmacVar with state of VAR_ADDED
+ // + D - Write the new protected variable
+ // + E - Increment Counter2
+ // F - Mark old MetaDataHmacVar as VAR_DELETED
+ //
+ Status = EFI_SUCCESS;
+
+ VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid = TRUE;
+ VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid = FALSE;
+ }
+ }
+ } else {
+ //
+ // There must be logic error or variable written to storage skipped
+ // the protected variable service, if code reaches here.
+ //
+ ASSERT (FALSE);
+ }
+
+Done:
+ if (Hmac1 != NULL) {
+ HmacSha256Free (Hmac1);
+ }
+
+ if (Hmac2 != NULL) {
+ HmacSha256Free (Hmac2);
+ }
+
+ return Status;
+}
+
+/**
+ Collect variable digest information.
+
+ This information is collected to be used to for integrity check.
+
+ @param[in] Global Pointer to global configuration data.
+ @param[in] ContextIn Pointer to variable service context needed by
+ protected variable.
+ @param[in, out] DigestBuffer Base address of digest of each variable.
+ @param[out] DigestBufferSize Digest size of one variable if DigestBuffer is NULL.
+ Size of DigestBuffer if DigestBuffer is NOT NULL.
+ @param[out] VariableNumber Number of valid variables.
+
+ @retval EFI_SUCCESS Successfully retreived variable digest.
+ @retval EFI_INVALID_PARAMETER One ore more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate memory.
+ @retval EFI_BUFFER_TOO_SMALL The DigestBufferSize pass in is too small.
+
+**/
+EFI_STATUS
+CollectVariableDigestInfo (
+ IN PROTECTED_VARIABLE_GLOBAL *Global,
+ IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn,
+ IN OUT VOID *DigestBuffer OPTIONAL,
+ OUT UINT32 *DigestBufferSize OPTIONAL,
+ OUT UINT32 *VariableNumber OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_INFO VarInfo;
+ UINT32 VarNum;
+ UINT32 DigSize;
+ VARIABLE_DIGEST *VarDig;
+ EFI_TIME TimeStamp;
+ UNPROTECTED_VARIABLE_INDEX VarIndex;
+
+ //
+ // This function might be called before Global is initialized. In that case,
+ // Global must be NULL but not ContextIn.
+ //
+ if ((Global == NULL) && (ContextIn == NULL)) {
+ ASSERT (Global != NULL || ContextIn != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Global == NULL) && (DigestBuffer != NULL)) {
+ ASSERT (Global != NULL && DigestBuffer != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ( (DigestBuffer != NULL)
+ && ((DigestBufferSize == NULL) || (*DigestBufferSize == 0)))
+ {
+ ASSERT (
+ DigestBuffer != NULL
+ && DigestBufferSize != NULL && *DigestBufferSize > 0
+ );
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Global != NULL) && (ContextIn == NULL)) {
+ ContextIn = GET_CNTX (Global);
+ }
+
+ DigSize = 0;
+ VarNum = 0;
+ VarDig = NULL;
+
+ ZeroMem (&VarInfo, sizeof (VarInfo));
+ VarInfo.StoreIndex = VAR_INDEX_INVALID; // To get the first variable.
+
+ if ((Global != NULL) &&
+ (Global->VariableCache != 0) &&
+ (Global->VariableCacheSize > 0))
+ {
+ //
+ // Use the variable cache to hold a copy of one variable.
+ //
+ VarInfo.Buffer = GET_BUFR (Global->VariableCache);
+ } else {
+ //
+ // Allocate a buffer to hold a copy of one variable
+ //
+ VarInfo.Buffer = AllocatePages (EFI_SIZE_TO_PAGES (MAX_VARIABLE_SIZE));
+ if (VarInfo.Buffer == NULL) {
+ ASSERT (VarInfo.Buffer != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ if ((DigestBuffer != NULL) && (*DigestBufferSize > 0)) {
+ VarDig = DigestBuffer;
+ }
+
+ while (TRUE) {
+ if (VarDig != NULL) {
+ if (DigSize >= (*DigestBufferSize)) {
+ //
+ // Out of buffer.
+ //
+ break;
+ }
+
+ VarInfo.Header.VendorGuid = &VarDig->VendorGuid;
+ VarInfo.Header.VariableName = VAR_DIG_NAME (VarDig);
+ VarInfo.Header.NameSize = (UINTN)DigestBuffer + (UINTN)*DigestBufferSize
+ - (UINTN)VarInfo.Header.VariableName;
+ VarInfo.Header.TimeStamp = &TimeStamp;
+ VarInfo.Header.Data = NULL;
+ } else {
+ ZeroMem ((VOID *)&VarInfo.Header, sizeof (VarInfo.Header));
+ }
+
+ Status = ContextIn->GetNextVariableInfo (&VarInfo);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Skip deleted variables.
+ //
+ if ( (VarInfo.Header.State != VAR_ADDED)
+ && (VarInfo.Header.State != (VAR_ADDED & VAR_IN_DELETED_TRANSITION)))
+ {
+ continue;
+ }
+
+ if (Global != NULL) {
+ Global->Flags.Auth &= VarInfo.Flags.Auth;
+ }
+
+ VarNum += 1;
+ DigSize += (UINT32)(sizeof (VARIABLE_DIGEST)
+ + VarInfo.Header.NameSize
+ + METADATA_HMAC_SIZE);
+ if ((DigestBuffer != NULL) && (DigSize > *DigestBufferSize)) {
+ ASSERT (DigSize <= *DigestBufferSize);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (VarDig != NULL) {
+ VarDig->Prev = 0;
+ VarDig->Next = 0;
+ VarDig->State = VarInfo.Header.State;
+ VarDig->Attributes = VarInfo.Header.Attributes;
+ VarDig->DataSize = (UINT32)VarInfo.Header.DataSize;
+ VarDig->NameSize = (UINT16)VarInfo.Header.NameSize;
+ VarDig->DigestSize = METADATA_HMAC_SIZE;
+ VarDig->StoreIndex = VarInfo.StoreIndex;
+
+ if ((VarInfo.Buffer != NULL) && ((UINTN)VarInfo.Buffer != Global->VariableCache)) {
+ VarDig->CacheIndex = GET_ADRS (VarInfo.Buffer);
+ } else {
+ VarDig->CacheIndex = VAR_INDEX_INVALID;
+ }
+
+ VarDig->Flags.Auth = VarInfo.Flags.Auth;
+ VarDig->Flags.Valid = TRUE;
+
+ VarIndex = CheckKnownUnprotectedVariable (Global, &VarInfo);
+ if (VarIndex >= UnprotectedVarIndexMax) {
+ //
+ // Check information relating to encryption, if enabled.
+ //
+ VarDig->Flags.Encrypted = FALSE;
+ if ((VarInfo.Header.Data != NULL) && (VarInfo.Header.DataSize > 0)) {
+ VarInfo.CipherData = NULL;
+ VarInfo.CipherDataSize = 0;
+ VarInfo.PlainData = NULL;
+ VarInfo.PlainDataSize = 0;
+ Status = GetCipherDataInfo (&VarInfo);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Discovered encrypted variable mark variable to be
+ // encrypted on the next SetVariable() operation
+ //
+ VarDig->Flags.Encrypted = PcdGetBool (PcdProtectedVariableConfidentiality);
+ } else {
+ VarInfo.PlainData = VarInfo.Header.Data;
+ VarInfo.PlainDataSize = (UINT32)VarInfo.Header.DataSize;
+ VarInfo.CipherDataType = 0;
+ VarInfo.CipherHeaderSize = 0;
+ if (Status == EFI_NOT_FOUND) {
+ //
+ // Found variable that is not encrypted mark variable to be
+ // encrypted on the next SetVariable() operation
+ //
+ VarDig->Flags.Encrypted = PcdGetBool (PcdProtectedVariableConfidentiality);
+ }
+ }
+ }
+
+ //
+ // Variable is protected
+ //
+ VarDig->Flags.Protected = PcdGetBool (PcdProtectedVariableIntegrity);
+ VarDig->PlainDataSize = VarInfo.PlainDataSize;
+
+ //
+ // Calculate digest only for protected variable.
+ //
+ Status = GetVariableDigest (Global, &VarInfo, VAR_DIG_VALUE (VarDig));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Keep the VarDig in an ordered list.
+ //
+ InsertVariableDigestNode (Global, VarDig, CompareVariableDigestInfo);
+ } else {
+ VarDig->Flags.Protected = FALSE;
+ VarDig->Flags.Encrypted = FALSE;
+ VarDig->PlainDataSize = VarDig->DataSize;
+
+ //
+ // Make use of VARIABLE_DIGEST->DigestValue to cache HMAC value from
+ // MetaDataHmacVar, which doesn't need a digest value (only protected
+ // variables need it for integrity check).
+ //
+ if ((VarIndex == IndexHmacInDel) || (VarIndex == IndexHmacAdded)) {
+ if (VarDig->State == VAR_ADDED) {
+ VarIndex = IndexHmacAdded;
+ } else {
+ VarIndex = IndexHmacInDel;
+ }
+ }
+
+ Global->Unprotected[VarIndex] = VAR_DIG_ADR (VarDig);
+
+ if ((VarInfo.Header.Data != NULL) && (VarDig->DataSize <= VarDig->DigestSize)) {
+ CopyMem (VAR_DIG_VALUE (VarDig), VarInfo.Header.Data, VarDig->DataSize);
+ }
+
+ //
+ // Don't add the VarDig for MetaDataHmacVar into the linked list now.
+ // Do it after the HMAC has been validated.
+ //
+ if ((VarIndex != IndexHmacInDel) || (VarIndex != IndexHmacAdded)) {
+ InsertVariableDigestNode (Global, VarDig, CompareVariableDigestInfo);
+ }
+ }
+
+ VarDig = (VARIABLE_DIGEST *)((UINTN)VarDig + VAR_DIG_END (VarDig));
+ }
+ }
+
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ return Status;
+ }
+
+ if (DigestBufferSize != NULL) {
+ *DigestBufferSize = DigSize;
+ }
+
+ if (VariableNumber != NULL) {
+ *VariableNumber = VarNum;
+ }
+
+ if ((Global == NULL) && (VarInfo.Buffer != NULL)) {
+ //
+ // Free Buffer
+ //
+ FreePages (VarInfo.Buffer, EFI_SIZE_TO_PAGES (MAX_VARIABLE_SIZE));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Perform for protected variable integrity check.
+
+ If this initialization failed upon any error, the whole variable services
+ should not be used. A system reset might be needed to re-construct NV
+ variable storage to be the default state.
+
+ @param[in] ContextIn Pointer to variable service context needed by
+ protected variable.
+
+ @retval EFI_SUCCESS Protected variable services are ready.
+ @retval EFI_INVALID_PARAMETER If ContextIn == NULL or something missing or
+ mismatching in the content in ContextIn.
+ @retval EFI_COMPROMISED_DATA If failed to check integrity of protected variables.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+PerformVariableIntegrityCheck (
+ IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn
+ )
+{
+ EFI_STATUS Status;
+ UINT32 HobDataSize;
+ UINT32 VarNumber;
+ VOID *Buffer;
+ PROTECTED_VARIABLE_GLOBAL *Global;
+ VARIABLE_DIGEST *DigBuffer;
+ UINT32 DigBufferSize;
+ UINT32 HmacMetaDataSize;
+ UINTN Index;
+ BOOLEAN PreviousKey;
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ if ((ContextIn == NULL) || (ContextIn->GetNextVariableInfo == NULL)) {
+ ASSERT (ContextIn != NULL);
+ ASSERT (ContextIn->GetNextVariableInfo != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ContextIn->StructSize = (ContextIn->StructSize == 0) ? sizeof (*ContextIn)
+ : ContextIn->StructSize;
+
+ //
+ // Enumerate all variables first to collect info for resource allocation.
+ //
+ DigBufferSize = 0;
+ Status = CollectVariableDigestInfo (
+ NULL,
+ ContextIn,
+ NULL,
+ &DigBufferSize,
+ &VarNumber
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Allocate buffer for Global. Memory layout:
+ //
+ // Global
+ // Digest context
+ // Variable Digest List
+ // HmacMetaData
+ //
+ // To save precious NEM space of processor, variable cache will not be
+ // allocated at this point until physical memory is ready for use.
+ //
+ HmacMetaDataSize = (UINT32)GetMetaDataHmacVarSize (TRUE);
+ HobDataSize = sizeof (PROTECTED_VARIABLE_GLOBAL)
+ + (UINT32)DIGEST_CONTEXT_SIZE
+ + DigBufferSize
+ + HmacMetaDataSize;
+ Buffer = AllocateGlobalBuffer (HobDataSize, FALSE);
+ if (Buffer == NULL) {
+ ASSERT (Buffer != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Global = (PROTECTED_VARIABLE_GLOBAL *)((UINTN)Buffer);
+ Global->DigestContext = GET_ADRS (Global + 1);
+
+ if (DigBufferSize > 0) {
+ DigBuffer = (VARIABLE_DIGEST *)(UINTN)(Global->DigestContext + DIGEST_CONTEXT_SIZE);
+ ZeroMem (DigBuffer, DigBufferSize);
+ } else {
+ DigBuffer = NULL;
+ }
+
+ //
+ // Keep a copy of ContextIn in HOB for later uses.
+ //
+ Global->GlobalSelf = GET_ADRS (Global);
+ Global->ContextIn = GET_ADRS (ContextIn);
+
+ Global->StructVersion = PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION;
+ Global->StructSize = HobDataSize;
+
+ Global->VariableNumber = VarNumber;
+ Global->VariableDigests = 0;
+
+ Global->Flags.Auth = TRUE;
+ Global->Flags.WriteInit = FALSE;
+ Global->Flags.WriteReady = FALSE;
+
+ GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+ if (GuidHob == NULL) {
+ GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+ if (GuidHob != NULL) {
+ Global->Flags.Auth = FALSE;
+ }
+ }
+
+ Global->Flags.RecoveryMode = (GuidHob != NULL);
+
+ //
+ // Before physical memory is ready, we cannot cache all variables in the very
+ // limited NEM space. But we still need to reserve buffer to hold data of
+ // one variable as well as context for integrity check (HMAC calculation).
+ //
+ Global->VariableCacheSize = MAX_VARIABLE_SIZE;
+ Buffer = AllocatePages (EFI_SIZE_TO_PAGES (Global->VariableCacheSize));
+ if (Buffer == NULL) {
+ ASSERT (Buffer != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Global->VariableCache = GET_ADRS (Buffer);
+ Global->LastAccessedVariable = VAR_INDEX_INVALID;
+
+ for (Index = 0; Index < UnprotectedVarIndexMax; ++Index) {
+ Global->Unprotected[Index] = VAR_INDEX_INVALID;
+ }
+
+ //
+ // Re-enumerate all NV variables and build digest list.
+ //
+ Status = CollectVariableDigestInfo (
+ Global,
+ ContextIn,
+ DigBuffer,
+ &DigBufferSize,
+ &VarNumber
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ ASSERT (Global->VariableNumber == VarNumber);
+
+ //
+ // Fix-up number of valid protected variables (i.e. exclude unprotected ones)
+ //
+ for (Index = 0; VarNumber != 0 && Index < UnprotectedVarIndexMax; ++Index) {
+ if (Global->Unprotected[Index] != VAR_INDEX_INVALID) {
+ --VarNumber;
+ }
+ }
+
+ //
+ // Get root key and generate HMAC key.
+ //
+ PreviousKey = FALSE;
+ Status = GetVariableKey ((VOID *)Global->RootKey, sizeof (Global->RootKey));
+ if (EFI_ERROR (Status)) {
+ ASSERT (FALSE);
+ Status = EFI_COMPROMISED_DATA;
+ }
+
+ //
+ // Derive the MetaDataHmacKey from root key
+ //
+ if (!GenerateMetaDataHmacKey (
+ Global->RootKey,
+ sizeof (Global->RootKey),
+ Global->MetaDataHmacKey,
+ sizeof (Global->MetaDataHmacKey)
+ ))
+ {
+ ASSERT (FALSE);
+ Status = EFI_COMPROMISED_DATA;
+ }
+
+ //
+ // Check the integrity of all NV variables, if any.
+ //
+ if (( (Global->Unprotected[IndexHmacAdded] != VAR_INDEX_INVALID)
+ || (Global->Unprotected[IndexHmacInDel] != VAR_INDEX_INVALID)))
+ {
+ //
+ // Validate the HMAC stored in variable MetaDataHmacVar.
+ //
+ Status = VerifyMetaDataHmac (Global);
+ if (EFI_ERROR (Status)) {
+ //
+ // Try again with the previous root key if the latest key failed the HMAC validation.
+ //
+ Status = GetVariableKey ((VOID *)Global->RootKey, sizeof (Global->RootKey));
+ if (!EFI_ERROR (Status)) {
+ //
+ // Derive the MetaDataHmacKey from previous root key
+ //
+ if (GenerateMetaDataHmacKey (
+ Global->RootKey,
+ sizeof (Global->RootKey),
+ Global->MetaDataHmacKey,
+ sizeof (Global->MetaDataHmacKey)
+ ) == TRUE)
+ {
+ //
+ // Validate the HMAC stored in variable MetaDataHmacVar.
+ //
+ Status = VerifyMetaDataHmac (Global);
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_COMPROMISED_DATA;
+ }
+ } else {
+ Status = EFI_COMPROMISED_DATA;
+ }
+ }
+ }
+ } else if (Global->Flags.RecoveryMode) {
+ //
+ // Generate the first version of MetaDataHmacVar.
+ //
+ Status = SyncRpmcCounter ();
+ if (!EFI_ERROR (Status)) {
+ Status = RefreshVariableMetadataHmac (Global, NULL, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // MetaDataHmacVar is always calculated against Counter2+1. Updating
+ // RPMCs to match it.
+ //
+ (VOID)IncrementMonotonicCounter (RPMC_COUNTER_1);
+ (VOID)IncrementMonotonicCounter (RPMC_COUNTER_2);
+ }
+ }
+ } else if ((VarNumber > 0) && !Global->Flags.RecoveryMode) {
+ //
+ // There's no MetaDataHmacVar found for protected variables. Suppose
+ // the variable storage is compromised.
+ //
+ Status = EFI_COMPROMISED_DATA;
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // The integrity of variables have been compromised. The platform has to do
+ // something to recover the variable store. But the boot should not go on
+ // anyway this time.
+ //
+ DEBUG ((DEBUG_ERROR, "%a: %d Integrity check Status = %r\n", __FUNCTION__, __LINE__, Status));
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED,
+ (PcdGet32 (PcdStatusCodeVariableIntegrity) | EFI_SW_PEI_PC_RECOVERY_BEGIN)
+ );
+ #if defined (EDKII_UNIT_TEST_FRAMEWORK_ENABLED) // Avoid test malfunctioning.
+ return Status;
+ #else
+ ASSERT_EFI_ERROR (Status);
+ CpuDeadLoop ();
+ #endif
+ }
+
+ //
+ // Everything's OK.
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ PcdGet32 (PcdStatusCodeVariableIntegrity)
+ );
+
+ if (GET_BUFR (Global->VariableCacheSize) != NULL) {
+ //
+ // Free Buffer
+ //
+ FreePages (Buffer, EFI_SIZE_TO_PAGES (Global->VariableCacheSize));
+ }
+
+ //
+ // Keep the valid MetaDataHmacVar in the list.
+ //
+ for (Index = 0; Index < IndexPlatformVar; ++Index) {
+ if ( (Global->Unprotected[Index] != VAR_INDEX_INVALID)
+ && VAR_DIG_PTR (Global->Unprotected[Index])->Flags.Valid)
+ {
+ InsertVariableDigestNode (
+ Global,
+ VAR_DIG_PTR (Global->Unprotected[Index]),
+ NULL
+ );
+ }
+ }
+
+ //
+ // Restore the key to the latest one.
+ //
+ if (PreviousKey) {
+ Status = GetVariableKey ((VOID *)Global->RootKey, sizeof (Global->RootKey));
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Derive the MetaDataHmacKey from root key
+ //
+ if (!GenerateMetaDataHmacKey (
+ Global->RootKey,
+ sizeof (Global->RootKey),
+ Global->MetaDataHmacKey,
+ sizeof (Global->MetaDataHmacKey)
+ ))
+ {
+ ASSERT (FALSE);
+ }
+ }
+
+ //
+ // Make sure that the RPMC counter is in-sync.
+ //
+ Status = SyncRpmcCounter ();
+
+ //
+ // Setup a hook to migrate data in Global once physical memory is ready.
+ //
+ Status = PeiServicesNotifyPpi (mPostMemNotifyList);
+
+ return Status;
+}
+
+/**
+
+ Initialization for protected variable services.
+
+ If the variable store is available than perform integrity check.
+ Otherwise, defer integrity check until variable store is available.
+
+
+ @param[in] ContextIn Pointer to variable service context needed by
+ protected variable.
+
+ @retval EFI_SUCCESS Protected variable services are ready.
+ @retval EFI_INVALID_PARAMETER If ContextIn == NULL or something missing or
+ mismatching in the content in ContextIn.
+ @retval EFI_COMPROMISED_DATA If failed to check integrity of protected variables.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibInitialize (
+ IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn
+ )
+{
+ EFI_STATUS Status;
+ VOID *ContextInHob;
+ PROTECTED_VARIABLE_INFO VarInfo;
+
+ if ((ContextIn == NULL) || (ContextIn->GetNextVariableInfo == NULL)) {
+ ASSERT (ContextIn != NULL);
+ ASSERT (ContextIn->GetNextVariableInfo != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Keep a copy of ContextIn in HOB for later uses.
+ //
+ ContextIn->StructSize = (ContextIn->StructSize == 0) ? sizeof (*ContextIn)
+ : ContextIn->StructSize;
+ ContextInHob = BuildGuidHob (&gEdkiiProtectedVariableContextGuid, ContextIn->StructSize);
+ CopyMem (ContextInHob, ContextIn, ContextIn->StructSize);
+
+ //
+ // Discover if Variable Store Info Hob has been published by platform driver.
+ // It contains information regards to HOB or NV Variable Store availability
+ //
+ ZeroMem ((VOID *)&VarInfo.Header, sizeof (VarInfo.Header));
+ VarInfo.StoreIndex = VAR_INDEX_INVALID;
+ VarInfo.Buffer = AllocatePages (EFI_SIZE_TO_PAGES (MAX_VARIABLE_SIZE));
+ if (VarInfo.Buffer == NULL) {
+ ASSERT (VarInfo.Buffer != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FreePages (VarInfo.Buffer, EFI_SIZE_TO_PAGES ((MAX_VARIABLE_SIZE)));
+
+ Status = ContextIn->GetNextVariableInfo (&VarInfo);
+ if (EFI_ERROR (Status)) {
+ //
+ // Register for platform driver callback when Variable Store is available.
+ //
+ DEBUG ((DEBUG_INFO, "Variable Store is not available. Register for a integrity check callback\n"));
+ Status = PeiServicesNotifyPpi (mVariableStoreNotifyList);
+ return Status;
+ }
+
+ //
+ // HOB Variable store is not available
+ // Assume NV Variable store is available instead
+ // Perform integrity check on NV Variable Store
+ //
+ DEBUG ((DEBUG_INFO, "NV Variable Store is available. Perform integrity check\n"));
+ Status = PerformVariableIntegrityCheck (ContextInHob);
+ return Status;
+}
+
+/**
+
+ Prepare for variable update.
+
+ (Not suppported in PEI phase.)
+
+ @retval EFI_UNSUPPORTED Updating variable is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteInit (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Update a variable with protection provided by this library.
+
+ Not supported in PEI phase.
+
+ @param[in,out] CurrVariable Variable to be updated. It's NULL if
+ adding a new variable.
+ @param[in] CurrVariableInDel In-delete-transition copy of updating variable.
+ @param[in,out] NewVariable Buffer of new variable data.
+ Buffer of "MetaDataHmacVar" and new
+ variable (encrypted).
+ @param[in,out] NewVariableSize Size of NewVariable.
+ Size of (encrypted) NewVariable and
+ "MetaDataHmacVar".
+
+ @retval EFI_UNSUPPORTED Not support updating variable in PEI phase.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibUpdate (
+ IN OUT VARIABLE_HEADER *CurrVariable,
+ IN VARIABLE_HEADER *CurrVariableInDel,
+ IN OUT VARIABLE_HEADER *NewVariable,
+ IN OUT UINTN *NewVariableSize
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Finalize a variable updating after it's written to NV variable storage
+ successfully.
+
+ @param[in] NewVariable Buffer of new variables and MetaDataHmacVar.
+ @param[in] VariableSize Size of buffer pointed by NewVariable.
+ @param[in] StoreIndex StoreIndex to NV variable storage from where the new
+ variable and MetaDataHmacVar have been written.
+
+ @retval EFI_UNSUPPORTED Not support updating variable in PEI phase.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteFinal (
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN VariableSize,
+ IN UINT64 StoreIndex
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
new file mode 100644
index 000000000000..8e964f4cd28d
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
@@ -0,0 +1,209 @@
+/** @file
+ Implemention of ProtectedVariableLib for SMM variable services.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Uefi.h>
+
+#include "Guid/SmmVariableCommon.h"
+
+#include "Library/MmServicesTableLib.h"
+#include "Library/MemoryAllocationLib.h"
+
+#include "ProtectedVariableInternal.h"
+
+PROTECTED_VARIABLE_CONTEXT_IN mVariableContextIn = {
+ PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION,
+ sizeof (PROTECTED_VARIABLE_CONTEXT_IN),
+ 0,
+ FromSmmModule,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+PROTECTED_VARIABLE_GLOBAL mProtectedVariableGlobal = {
+ PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION,
+ sizeof (PROTECTED_VARIABLE_GLOBAL),
+ { 0 },
+ { 0 },
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ { 0, 0, 0 },
+ 0,
+ 0,
+ { 0, 0, 0, 0}
+};
+
+/**
+
+ Callback function to call variable write.
+
+ @param[in] Protocol Not Used.
+ @param[in] Interface Not Used.
+ @param[in] Handle Not Used.
+
+ @retval EFI_SUCCESS Protected variable write successful.
+ @retval others Protected variable write failed.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableWriteProtocolCallback (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+
+ Status = ProtectedVariableLibWriteInit ();
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Initialization for protected variable services.
+
+ If this initialization failed upon any error, the whole variable services
+ should not be used. A system reset might be needed to re-construct NV
+ variable storage to be the default state.
+
+ @param[in] ContextIn Pointer to variable service context needed by
+ protected variable.
+
+ @retval EFI_SUCCESS Protected variable services are ready.
+ @retval EFI_INVALID_PARAMETER If ContextIn == NULL or something missing or
+ mismatching in the content in ContextIn.
+ @retval EFI_COMPROMISED_DATA If failed to check integrity of protected variables.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
+ @retval EFI_UNSUPPORTED Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibInitialize (
+ IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_CONTEXT_IN *ProtectedVarContext;
+ PROTECTED_VARIABLE_GLOBAL *OldGlobal;
+ PROTECTED_VARIABLE_GLOBAL *NewGlobal;
+ VARIABLE_DIGEST *VarDig;
+ VARIABLE_DIGEST *NewVarDig;
+ EFI_PHYSICAL_ADDRESS NewCacheIndex;
+ UINTN VarSize;
+ UNPROTECTED_VARIABLE_INDEX Index;
+
+ if ( (ContextIn == NULL)
+ || (ContextIn->StructVersion != PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION)
+ || (ContextIn->StructSize != sizeof (PROTECTED_VARIABLE_CONTEXT_IN))
+ || (ContextIn->GetVariableInfo == NULL)
+ || (ContextIn->GetNextVariableInfo == NULL)
+ || (ContextIn->UpdateVariableStore == NULL)
+ || (ContextIn->UpdateVariable == NULL))
+ {
+ ASSERT (ContextIn != NULL);
+ ASSERT (ContextIn->StructVersion == PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION);
+ ASSERT (ContextIn->StructSize == sizeof (PROTECTED_VARIABLE_CONTEXT_IN));
+ ASSERT (ContextIn->GetVariableInfo != NULL);
+ ASSERT (ContextIn->GetNextVariableInfo != NULL);
+ ASSERT (ContextIn->UpdateVariableStore != NULL);
+ ASSERT (ContextIn->UpdateVariable != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GetProtectedVariableGlobal (&NewGlobal);
+ ProtectedVarContext = GET_CNTX (NewGlobal);
+ CopyMem (ProtectedVarContext, ContextIn, sizeof (mVariableContextIn));
+ ProtectedVarContext->VariableServiceUser = FromSmmModule;
+
+ //
+ // Get root key and HMAC key from HOB created by PEI variable driver.
+ //
+ Status = GetProtectedVariableGlobalFromHob (&OldGlobal);
+ ASSERT_EFI_ERROR (Status);
+
+ CopyMem ((VOID *)NewGlobal, (CONST VOID *)OldGlobal, sizeof (*OldGlobal));
+
+ //
+ // The keys must not be available outside SMM.
+ //
+ if (ProtectedVarContext->VariableServiceUser == FromSmmModule) {
+ ZeroMem (OldGlobal->RootKey, sizeof (OldGlobal->RootKey));
+ ZeroMem (OldGlobal->MetaDataHmacKey, sizeof (OldGlobal->MetaDataHmacKey));
+ }
+
+ NewGlobal->Flags.WriteInit = FALSE;
+ NewGlobal->Flags.WriteReady = FALSE;
+ NewGlobal->LastAccessedVariable = 0;
+ NewGlobal->VariableCache = GET_ADRS (AllocateZeroPool (MAX_VARIABLE_SIZE));
+ NewGlobal->DigestContext = GET_ADRS (AllocateZeroPool (DIGEST_CONTEXT_SIZE));
+ if (NewGlobal->DigestContext == 0) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Copy over variable from HOB to SMM memory
+ //
+ NewGlobal->VariableDigests = 0;
+ VarDig = VAR_DIG_PTR (OldGlobal->VariableDigests);
+ while (VarDig != NULL) {
+ //
+ // Allocate new Var Digest in SMM memory
+ //
+ NewVarDig = (VARIABLE_DIGEST *)AllocateZeroPool (
+ sizeof (VARIABLE_DIGEST) + VarDig->NameSize + METADATA_HMAC_SIZE
+ );
+ if (NewVarDig == NULL) {
+ ASSERT (NewVarDig != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (NewVarDig, VarDig, sizeof (VARIABLE_DIGEST));
+ NewVarDig->Prev = 0;
+ NewVarDig->Next = 0;
+
+ CopyMem (VAR_DIG_NAME (NewVarDig), VAR_DIG_NAME (VarDig), VarDig->NameSize);
+ CopyMem (VAR_DIG_VALUE (NewVarDig), VAR_DIG_VALUE (VarDig), VarDig->DigestSize);
+
+ VarSize = VARIABLE_HEADER_SIZE (NewGlobal->Flags.Auth);
+ VarSize += VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize);
+ VarSize += VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize);
+ VarSize = HEADER_ALIGN (VarSize);
+
+ NewCacheIndex = GET_ADRS (AllocateZeroPool (VarSize));
+ if (GET_BUFR (NewCacheIndex) == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (GET_BUFR (NewCacheIndex), GET_BUFR (VarDig->CacheIndex), VarSize);
+ NewVarDig->CacheIndex = NewCacheIndex;
+ NewVarDig->Flags.Freeable = TRUE;
+
+ for (Index = 0; Index < UnprotectedVarIndexMax; ++Index) {
+ if (OldGlobal->Unprotected[Index] == VAR_DIG_ADR (VarDig)) {
+ NewGlobal->Unprotected[Index] = VAR_DIG_ADR (NewVarDig);
+ }
+ }
+
+ InsertVariableDigestNode (NewGlobal, NewVarDig, NULL);
+
+ VarDig = VAR_DIG_NEXT (VarDig);
+ }
+
+ return Status;
+}
diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c
new file mode 100644
index 000000000000..92ba7cb12763
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c
@@ -0,0 +1,975 @@
+/** @file
+ Implemention of ProtectedVariableLib for SMM variable services.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Uefi.h>
+
+#include "Guid/SmmVariableCommon.h"
+
+#include "Library/MmServicesTableLib.h"
+#include "Library/MemoryAllocationLib.h"
+#include <Library/HobLib.h>
+
+#include "ProtectedVariableInternal.h"
+
+/**
+
+ Get context and/or global data structure used to process protected variable.
+
+ @param[out] Global Pointer to global configuration data.
+
+ @retval EFI_SUCCESS Get requested structure successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableGlobal (
+ OUT PROTECTED_VARIABLE_GLOBAL **Global OPTIONAL
+ )
+{
+ if (Global != NULL) {
+ mProtectedVariableGlobal.ContextIn = GET_ADRS (&mVariableContextIn);
+ *Global = &mProtectedVariableGlobal;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Encrypt given variable data and generate new HMAC value against it.
+
+ @param[in] Global Pointer to global configuration data.
+ @param[in,out] NewVarInfo Pointer to buffer of new variable data.
+ @param[in,out] NewVarDig Pointer to buffer of new variable digest.
+
+ @retval EFI_SUCCESS No error occurred during the encryption and HMC calculation.
+ @retval EFI_ABORTED Failed to do HMC calculation.
+ @return EFI_OUT_OF_RESOURCES Not enough resource to calculate HMC value.
+ @return EFI_NOT_FOUND The MetaDataHmacVar was not found in storage.
+
+**/
+STATIC
+EFI_STATUS
+UpdateVariableInternal (
+ IN PROTECTED_VARIABLE_GLOBAL *Global,
+ IN OUT PROTECTED_VARIABLE_INFO *NewVarInfo,
+ IN OUT VARIABLE_DIGEST *NewVarDig
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_INFO CachedVarInfo;
+ VOID *Buffer;
+ UINTN VarSize;
+
+ if ((NewVarInfo == NULL) || (NewVarDig == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If Add or update variable, encrypt new data first.
+ //
+ if (NewVarInfo->Buffer != NULL) {
+ Status = EFI_UNSUPPORTED;
+
+ if (NewVarDig->Flags.Encrypted) {
+ NewVarInfo->PlainData = NULL;
+ NewVarInfo->PlainDataSize = 0;
+ NewVarInfo->CipherData = NULL;
+ NewVarInfo->CipherDataSize = 0;
+ NewVarInfo->Key = Global->RootKey;
+ NewVarInfo->KeySize = sizeof (Global->RootKey);
+ NewVarInfo->Header.Attributes &= (~EFI_VARIABLE_APPEND_WRITE);
+ Status = EncryptVariable (NewVarInfo);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update new data size in variable header.
+ //
+ SET_VARIABLE_DATA_SIZE (NewVarInfo, NewVarInfo->CipherDataSize);
+ } else if (Status != EFI_UNSUPPORTED) {
+ ASSERT (FALSE);
+ return Status;
+ }
+ }
+
+ if (Status == EFI_UNSUPPORTED) {
+ NewVarInfo->CipherData = NewVarInfo->Header.Data;
+ NewVarInfo->CipherDataSize = (UINT32)NewVarInfo->Header.DataSize;
+ NewVarInfo->PlainData = NULL;
+ NewVarInfo->PlainDataSize = 0;
+ }
+ } else {
+ NewVarInfo->CipherData = NULL;
+ NewVarInfo->CipherDataSize = 0;
+ NewVarInfo->PlainData = NULL;
+ NewVarInfo->PlainDataSize = 0;
+ }
+
+ if (NewVarDig->CacheIndex != 0) {
+ //
+ // Update the cached copy.
+ //
+ ZeroMem ((VOID *)&CachedVarInfo, sizeof (CachedVarInfo));
+ CachedVarInfo.Buffer = GET_BUFR (NewVarDig->CacheIndex);
+ CachedVarInfo.StoreIndex = VAR_INDEX_INVALID;
+ CachedVarInfo.Flags.Auth = NewVarInfo->Flags.Auth;
+
+ Status = GET_CNTX (Global)->GetVariableInfo (&CachedVarInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ if ((CachedVarInfo.Header.DataSize != 0) && (NewVarInfo->CipherDataSize > CachedVarInfo.Header.DataSize)) {
+ //
+ // allocate new VarInfo buffer that is of greater CipherDataSize
+ //
+ VarSize = VARIABLE_HEADER_SIZE (NewVarDig->Flags.Auth);
+ VarSize += NewVarInfo->Header.NameSize + GET_PAD_SIZE (NewVarInfo->Header.NameSize);
+ VarSize += NewVarInfo->CipherDataSize + GET_PAD_SIZE (NewVarInfo->CipherDataSize);
+ VarSize = HEADER_ALIGN (VarSize);
+ Buffer = AllocateZeroPool (VarSize);
+ if (Buffer != NULL) {
+ VarSize = VARIABLE_HEADER_SIZE (NewVarDig->Flags.Auth);
+ VarSize += CachedVarInfo.Header.NameSize + GET_PAD_SIZE (CachedVarInfo.Header.NameSize);
+ VarSize += CachedVarInfo.Header.DataSize + GET_PAD_SIZE (CachedVarInfo.DataSize);
+ VarSize = HEADER_ALIGN (VarSize);
+
+ CopyMem (
+ Buffer,
+ CachedVarInfo.Buffer,
+ VarSize
+ );
+
+ FreePool (CachedVarInfo.Buffer);
+
+ //
+ // Update the cached copy.
+ //
+ ZeroMem ((VOID *)&CachedVarInfo, sizeof (CachedVarInfo));
+ CachedVarInfo.Buffer = Buffer;
+ CachedVarInfo.StoreIndex = VAR_INDEX_INVALID;
+ CachedVarInfo.Flags.Auth = NewVarInfo->Flags.Auth;
+ Status = GET_CNTX (Global)->GetVariableInfo (&CachedVarInfo);
+ ASSERT_EFI_ERROR (Status);
+ NewVarDig->CacheIndex = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+ }
+ }
+
+ CopyMem (
+ CachedVarInfo.Header.Data,
+ NewVarInfo->CipherData,
+ NewVarInfo->CipherDataSize
+ );
+ SET_VARIABLE_DATA_SIZE (&CachedVarInfo, NewVarInfo->CipherDataSize);
+
+ NewVarDig->State = VAR_ADDED;
+ NewVarDig->DataSize = NewVarInfo->CipherDataSize;
+
+ if (NewVarInfo->PlainDataSize > 0) {
+ NewVarDig->PlainDataSize = NewVarInfo->PlainDataSize;
+ } else {
+ NewVarDig->PlainDataSize = NewVarDig->DataSize;
+ }
+
+ //
+ // (Re-)Calculate the hash of the variable.
+ //
+ if (NewVarDig->Flags.Protected) {
+ GetVariableDigest (Global, NewVarInfo, VAR_DIG_VALUE (NewVarDig));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Fix state of MetaDataHmacVar on NV variable storage, if there's failure at
+ last boot during updating variable.
+
+ This must be done before the first writing of variable in current boot,
+ including storage reclaim.
+
+ @retval EFI_UNSUPPORTED Updating NV variable storage is not supported.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to complete the operation.
+ @retval EFI_SUCCESS Variable store was successfully updated.
+
+**/
+EFI_STATUS
+FixupHmacVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_INFO HmacVarInfo;
+ PROTECTED_VARIABLE_GLOBAL *Global;
+ PROTECTED_VARIABLE_CONTEXT_IN *ContextIn;
+ VARIABLE_DIGEST *VarDig;
+ UINTN Index;
+
+ Status = GetProtectedVariableGlobal (&Global);
+ ASSERT_EFI_ERROR (Status);
+
+ if (Global->Flags.WriteReady) {
+ return EFI_SUCCESS;
+ }
+
+ ContextIn = GET_CNTX (Global);
+
+ //
+ // Delete invalid MetaDataHmacVar.
+ //
+ for (Index = 0; Index <= IndexHmacAdded; ++Index) {
+ if (Global->Unprotected[Index] == VAR_INDEX_INVALID) {
+ continue;
+ }
+
+ VarDig = VAR_DIG_PTR (Global->Unprotected[Index]);
+ if (VarDig->Flags.Valid) {
+ continue;
+ }
+
+ ZeroMem ((VOID *)&HmacVarInfo, sizeof (HmacVarInfo));
+ HmacVarInfo.StoreIndex = VarDig->StoreIndex;
+ HmacVarInfo.Flags.Auth = VarDig->Flags.Auth;
+
+ Status = ContextIn->GetVariableInfo (&HmacVarInfo);
+ if (!EFI_ERROR (Status) && (HmacVarInfo.Buffer != NULL)) {
+ HmacVarInfo.Buffer->State &= VAR_DELETED;
+ Status = ContextIn->UpdateVariableStore (
+ &HmacVarInfo,
+ OFFSET_OF (VARIABLE_HEADER, State),
+ sizeof (HmacVarInfo.Buffer->State),
+ &HmacVarInfo.Buffer->State
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ }
+
+ //
+ // Release the resource and update related states.
+ //
+ VarDig->State &= VAR_DELETED;
+ RemoveVariableDigestNode (Global, VarDig, FALSE);
+ Global->Unprotected[Index] = VAR_INDEX_INVALID;
+ }
+
+ //
+ // There should be no MetaDataHmacVar if in variable storage recovery mode.
+ //
+ if (Global->Flags.RecoveryMode) {
+ ASSERT (Global->Unprotected[IndexHmacAdded] == VAR_INDEX_INVALID);
+ ASSERT (Global->Unprotected[IndexHmacInDel] == VAR_INDEX_INVALID);
+ }
+
+ Global->Flags.WriteReady = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Prepare for variable update.
+
+ This is needed only once during current boot to mitigate replay attack. Its
+ major job is to advance RPMC (Replay Protected Monotonic Counter).
+
+ @retval EFI_SUCCESS Variable is ready to update hereafter.
+ @retval EFI_UNSUPPORTED Updating variable is not supported.
+ @retval EFI_DEVICE_ERROR Error in advancing RPMC.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteInit (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_GLOBAL *Global;
+ PROTECTED_VARIABLE_CONTEXT_IN *ContextIn;
+ PROTECTED_VARIABLE_INFO VarInfo;
+
+ (VOID)GetProtectedVariableGlobal (&Global);
+ ContextIn = GET_CNTX (Global);
+
+ //
+ // HmacVarInfo should be here
+ //
+ if (Global->Flags.RecoveryMode) {
+ //
+ // Flush default variables to variable storage if in variable recovery mode.
+ //
+ Status = ContextIn->UpdateVariableStore (NULL, 0, (UINT32)-1, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ } else {
+ //
+ // RPMC1 is going to be one step ahead of RPMC2 here, in order to
+ // refresh the MetaDataHmacVar in each boot before writing any other
+ // variables.
+ //
+ Status = IncrementMonotonicCounter (RPMC_COUNTER_1);
+ ASSERT_EFI_ERROR (Status);
+
+ ContextIn = GET_CNTX (Global);
+
+ //
+ // Fix any wrong MetaDataHmacVar information before adding new one.
+ //
+ Status = FixupHmacVariable ();
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ if (!Global->Flags.WriteReady) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Refresh MetaDataHmacVar with RPMC2 by 1 in each boot before any variable
+ // update, by deleting (attr == 0 && datasize == 0) the old one.
+ //
+ ZeroMem (&VarInfo, sizeof (PROTECTED_VARIABLE_INFO)); // Zero attr & datasize
+
+ VarInfo.Flags.Auth = Global->Flags.Auth;
+ VarInfo.Header.VariableName = METADATA_HMAC_VARIABLE_NAME;
+ VarInfo.Header.NameSize = METADATA_HMAC_VARIABLE_NAME_SIZE;
+ VarInfo.Header.VendorGuid = &METADATA_HMAC_VARIABLE_GUID;
+
+ //
+ // Pretend to delete MetaDataHmacVar.
+ //
+ Status = ContextIn->UpdateVariable (&VarInfo.Header);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ }
+
+ mProtectedVariableGlobal.Flags.WriteInit = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Update a variable with protection provided by this library.
+
+ If variable encryption is employed, the new variable data will be encrypted
+ before being written to NV variable storage.
+
+ A special variable, called "MetaDataHmacVar", will always be updated along
+ with variable being updated to reflect the changes (HMAC value) of all
+ protected valid variables. The only exceptions, currently, is variable
+ variable "VarErrorLog".
+
+ The buffer passed by NewVariable must be double of maximum variable size,
+ which allows to pass the "MetaDataHmacVar" back to caller along with encrypted
+ new variable data, if any. This can make sure the new variable data and
+ "MetaDataHmacVar" can be written at almost the same time to reduce the chance
+ of compromising the integrity.
+
+ If *NewVariableSize is zero, it means to delete variable passed by CurrVariable
+ and/or CurrVariableInDel. "MetaDataHmacVar" will be updated as well in such
+ case because of less variables in storage. NewVariable should be always passed
+ in to convey new "MetaDataHmacVar" back.
+
+ @param[in,out] CurrVariable Variable to be updated. It's NULL if
+ adding a new variable.
+ @param[in] CurrVariableInDel In-delete-transition copy of updating variable.
+ @param[in,out] NewVariable Buffer of new variable data.
+ Buffer of "MetaDataHmacVar" and new
+ variable (encrypted).
+ @param[in,out] NewVariableSize Size of NewVariable.
+ Size of (encrypted) NewVariable and
+ "MetaDataHmacVar".
+
+ @retval EFI_SUCCESS The variable is updated with protection successfully.
+ @retval EFI_INVALID_PARAMETER NewVariable is NULL.
+ @retval EFI_NOT_FOUND Information missing to finish the operation.
+ @retval EFI_ABORTED Failed to encrypt variable or calculate HMAC.
+ @retval EFI_NOT_READY The RPMC device is not yet initialized.
+ @retval EFI_DEVICE_ERROR The RPMC device has error in updating.
+ @retval EFI_ACCESS_DENIED The given variable is not allowed to update.
+ Currently this only happens on updating
+ "MetaDataHmacVar" from code outside of this
+ library.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibUpdate (
+ IN OUT VARIABLE_HEADER *CurrVariable,
+ IN VARIABLE_HEADER *CurrVariableInDel,
+ IN OUT VARIABLE_HEADER *NewVariable,
+ IN OUT UINTN *NewVariableSize
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_CONTEXT_IN *ContextIn;
+ PROTECTED_VARIABLE_GLOBAL *Global;
+ PROTECTED_VARIABLE_INFO VarInfo;
+ VARIABLE_DIGEST *VarDig;
+ VARIABLE_DIGEST *CurrVarDig;
+ VARIABLE_DIGEST *NewVarDig;
+ PROTECTED_VARIABLE_INFO NewVarInfo;
+ PROTECTED_VARIABLE_INFO NewHmacVarInfo;
+ UINTN VarSize;
+ UINT64 UnprotectedVarIndex;
+
+ //
+ // Advance RPMC
+ //
+ Status = IncrementMonotonicCounter (RPMC_COUNTER_1);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Buffer for new variable is always needed, even this function is called to
+ // delete an existing one, because we need to pass the MetaDataHmacVar back
+ // which will be updated upon each variable addition or deletion.
+ //
+ if ((NewVariable == NULL) || (NewVariableSize == NULL)) {
+ ASSERT (NewVariable != NULL);
+ ASSERT (NewVariableSize != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetProtectedVariableGlobal (&Global);
+ ASSERT_EFI_ERROR (Status);
+ ContextIn = GET_CNTX (Global);
+
+ if (!Global->Flags.WriteReady && !Global->Flags.WriteInit) {
+ return EFI_NOT_READY;
+ }
+
+ VarSize = 0;
+ CurrVarDig = NULL;
+ NewVarDig = NULL;
+ UnprotectedVarIndex = VAR_INDEX_INVALID;
+
+ //
+ // Check existing copy of the same variable.
+ //
+ if (CurrVariable != NULL) {
+ //
+ // Find local cached copy, if possible.
+ //
+ ZeroMem (&VarInfo, sizeof (VarInfo));
+ VarInfo.Buffer = CurrVariable;
+ VarInfo.StoreIndex = VAR_INDEX_INVALID;
+ VarInfo.Flags.Auth = Global->Flags.Auth;
+
+ Status = ContextIn->GetVariableInfo (&VarInfo); // Retrieve the name/guid
+ ASSERT_EFI_ERROR (Status);
+
+ UnprotectedVarIndex = CheckKnownUnprotectedVariable (Global, &VarInfo);
+ if (UnprotectedVarIndex < UnprotectedVarIndexMax) {
+ CurrVarDig = VAR_DIG_PTR (Global->Unprotected[UnprotectedVarIndex]);
+ } else {
+ CurrVarDig = FindVariableInternal (Global, &VarInfo, FALSE);
+ }
+
+ ASSERT (CurrVarDig != NULL);
+ CurrVarDig->State &= VAR_DELETED;
+ }
+
+ //
+ // The old copy of the variable might haven't been deleted completely.
+ //
+ if (CurrVariableInDel != NULL) {
+ //
+ // Find local cached copy, if possible.
+ //
+ ZeroMem (&VarInfo, sizeof (VarInfo));
+ VarInfo.Buffer = CurrVariableInDel;
+ VarInfo.StoreIndex = VAR_INDEX_INVALID;
+ VarInfo.Flags.Auth = Global->Flags.Auth;
+
+ Status = ContextIn->GetVariableInfo (&VarInfo); // Retrieve the name/guid
+ ASSERT_EFI_ERROR (Status);
+
+ if (UnprotectedVarIndex == VAR_INDEX_INVALID) {
+ UnprotectedVarIndex = CheckKnownUnprotectedVariable (Global, &VarInfo);
+ }
+
+ if (UnprotectedVarIndex < UnprotectedVarIndexMax) {
+ VarDig = VAR_DIG_PTR (Global->Unprotected[UnprotectedVarIndex]);
+ } else {
+ VarDig = FindVariableInternal (Global, &VarInfo, FALSE);
+ }
+
+ if ((VarDig != NULL) && (VAR_DIG_ADR (VarDig) != VAR_INDEX_INVALID)) {
+ VarDig->State &= VAR_DELETED;
+
+ //
+ // Just need one node for the same variable. So remove the one
+ // in-del-transition.
+ //
+ if ((CurrVarDig != NULL) && (VarDig != CurrVarDig)) {
+ RemoveVariableDigestNode (Global, VarDig, TRUE);
+ } else {
+ CurrVarDig = VarDig; // Reuse the one in-del-transition.
+ }
+ }
+ }
+
+ //
+ // New data of the variable or new variable to be added.
+ //
+ if (NewVariable != NULL) {
+ //
+ // Completely new variable?
+ //
+ if (UnprotectedVarIndex == VAR_INDEX_INVALID) {
+ ZeroMem (&VarInfo, sizeof (VarInfo));
+ VarInfo.Buffer = NewVariable;
+ VarInfo.StoreIndex = VAR_INDEX_INVALID;
+ VarInfo.Flags.Auth = Global->Flags.Auth;
+
+ Status = ContextIn->GetVariableInfo (&VarInfo); // Retrieve the name/guid
+ ASSERT_EFI_ERROR (Status);
+
+ UnprotectedVarIndex = CheckKnownUnprotectedVariable (Global, &VarInfo);
+ }
+ }
+
+ //
+ // Reserve space for MetaDataHmacVar (before the new variable so
+ // that it can be written first).
+ //
+ ZeroMem (&NewVarInfo, sizeof (NewVarInfo));
+ ZeroMem (&NewHmacVarInfo, sizeof (NewHmacVarInfo));
+
+ //
+ // Put the MetaDataHmacVar at the beginning of buffer.
+ //
+ NewHmacVarInfo.Buffer = NewVariable;
+
+ if (*NewVariableSize == 0) {
+ //
+ // Delete variable (but not MetaDataHmacVar)
+ //
+ if ( (UnprotectedVarIndex != IndexHmacAdded)
+ && (UnprotectedVarIndex != IndexHmacInDel))
+ {
+ RemoveVariableDigestNode (Global, CurrVarDig, TRUE);
+ }
+
+ NewVarInfo.Buffer = NULL;
+ } else if (UnprotectedVarIndex >= IndexPlatformVar) {
+ //
+ // Add/update variable. Move new variable data to be after MetaDataHmacVar.
+ //
+ // TRICK: New MetaDataHmacVar will be put at the beginning of buffer
+ // for new variable so that they can be written into non-volatile
+ // variable storage in one call. This can avoid writing one variable
+ // (NewHmacVarInfo) in the middle of writing another variable
+ // (NewVarInfo), which will need two calls and introduce extra
+ // complexities (from temp variable buffer reservation to variable
+ // space reclaim, etc.) in current implementation of variable
+ // services. The caller must make sure there's enough space in
+ // variable buffer (i.e. at least 2 * MaxVariableSize).
+ //
+ NewVarInfo.Buffer = (VARIABLE_HEADER *)((UINTN)NewVariable
+ + GetMetaDataHmacVarSize (Global->Flags.Auth));
+ CopyMem ((VOID *)NewVarInfo.Buffer, (VOID *)NewVariable, *NewVariableSize);
+
+ NewVarInfo.StoreIndex = VAR_INDEX_INVALID; // Skip offset calculation (it's new one)
+ NewVarInfo.Flags.Auth = Global->Flags.Auth;
+
+ Status = ContextIn->GetVariableInfo (&NewVarInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ if (CurrVarDig != NULL) {
+ //
+ // Update existing variable. Re-use the node.
+ //
+ NewVarDig = CurrVarDig;
+ } else {
+ //
+ // Add new variable.
+ //
+ NewVarDig = CreateVariableDigestNode (
+ NewVarInfo.Header.VariableName,
+ NewVarInfo.Header.VendorGuid,
+ (UINT16)NewVarInfo.Header.NameSize,
+ (UINT32)NewVarInfo.Header.DataSize,
+ NewVarInfo.Flags.Auth,
+ Global
+ );
+ if (NewVarDig == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewVarDig->Attributes = NewVarInfo.Header.Attributes;
+ if (UnprotectedVarIndex < UnprotectedVarIndexMax) {
+ NewVarDig->Flags.Protected = FALSE;
+ NewVarDig->Flags.Encrypted = FALSE;
+ Global->Unprotected[UnprotectedVarIndex] = VAR_DIG_ADR (NewVarDig);
+ }
+
+ //
+ // copy new variable to CacheIndex
+ //
+ VarSize = VARIABLE_HEADER_SIZE (NewVarInfo.Flags.Auth);
+ VarSize += NewVarInfo.Header.NameSize + GET_PAD_SIZE (NewVarInfo.Header.NameSize);
+ VarSize += NewVarInfo.Header.DataSize + GET_PAD_SIZE (NewVarInfo.Header.DataSize);
+ VarSize = HEADER_ALIGN (VarSize);
+ CopyMem (GET_BUFR (NewVarDig->CacheIndex), GET_BUFR (NewVarInfo.Buffer), VarSize);
+ InsertVariableDigestNode (Global, NewVarDig, NULL);
+ }
+ }
+
+ if ( (UnprotectedVarIndex == IndexHmacAdded)
+ || (UnprotectedVarIndex == IndexHmacInDel))
+ {
+ //
+ // MetaDataHmacVar should be managed only by this library. It's not
+ // supposed to be updated by external users of variable service. The only
+ // exception is that deleting it (not really delete but refresh the HMAC
+ // value against RPMC+1) is allowed before WriteInit, as a way to always
+ // increment RPMC once in current boot before any variable updates.
+ //
+ if ((NewVarInfo.Buffer != NULL) || Global->Flags.WriteInit) {
+ return EFI_ACCESS_DENIED;
+ }
+ } else {
+ //
+ // Do encryption, if enabled.
+ //
+ if ((NewVarDig != NULL) && (NewVarInfo.Buffer != NULL)) {
+ Status = UpdateVariableInternal (Global, &NewVarInfo, NewVarDig);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ }
+ }
+
+ //
+ // Refresh MetaDataHmacVar.
+ //
+ Status = RefreshVariableMetadataHmac (Global, NULL, &NewHmacVarInfo);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ //
+ // Return size for both MetaDataHmacVar and added/updated one.
+ //
+ VarSize = VARIABLE_SIZE (&NewHmacVarInfo);
+ *NewVariableSize = HEADER_ALIGN (VarSize);
+ if (NewVarInfo.Buffer != NULL) {
+ VarSize = VARIABLE_SIZE (&NewVarInfo);
+ VarSize = HEADER_ALIGN (VarSize);
+
+ if (VarSize > GET_CNTX (Global)->MaxVariableSize) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ *NewVariableSize += VarSize;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Finalize a variable updating after it's written to NV variable storage
+ successfully.
+
+ This usually includes works like increasing RPMC, synchronizing local cache,
+ updating new position of "MetaDataHmacVar", deleting old copy of "MetaDataHmacVar"
+ completely, etc.
+
+ @param[in] NewVariable Buffer of new variables and MetaDataHmacVar.
+ @param[in] VariableSize Size of buffer pointed by NewVariable.
+ @param[in] StoreIndex StoreIndex to NV variable storage from where the new
+ variable and MetaDataHmacVar have been written.
+
+ @retval EFI_SUCCESS No problem in winding up the variable write operation.
+ @retval Others Failed to updating state of old copy of updated
+ variable, or failed to increase RPMC, etc.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteFinal (
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN VariableSize,
+ IN UINT64 StoreIndex
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_INFO VarInfo;
+ PROTECTED_VARIABLE_CONTEXT_IN *ContextIn;
+ PROTECTED_VARIABLE_GLOBAL *Global;
+ UNPROTECTED_VARIABLE_INDEX Index;
+ VARIABLE_DIGEST *VarDig;
+ VOID *Buffer;
+ UINTN VarSize;
+ UINTN NewVarSize;
+
+ Status = GetProtectedVariableGlobal (&Global);
+ ASSERT_EFI_ERROR (Status);
+ ContextIn = GET_CNTX (Global);
+
+ ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
+ VarInfo.Buffer = NewVariable;
+ VarInfo.StoreIndex = VAR_INDEX_INVALID;
+ VarInfo.Flags.Auth = Global->Flags.Auth;
+
+ Status = ContextIn->GetVariableInfo (&VarInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ Index = CheckKnownUnprotectedVariable (Global, &VarInfo);
+ if (Index < UnprotectedVarIndexMax) {
+ VarDig = VAR_DIG_PTR (Global->Unprotected[Index]);
+ } else {
+ VarDig = FindVariableInternal (Global, &VarInfo, FALSE);
+ }
+
+ if (Index == IndexHmacAdded) {
+ //
+ // Advance the RPMC to let it match new MetaDataHmacVar.
+ //
+ Status = IncrementMonotonicCounter (RPMC_COUNTER_2);
+ ASSERT_EFI_ERROR (Status);
+
+ if ((VarDig->StoreIndex != VAR_INDEX_INVALID) && (VarDig->State != VAR_ADDED)) {
+ ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
+ VarInfo.StoreIndex = VarDig->StoreIndex; // Still point to old copy
+ VarInfo.Flags.Auth = Global->Flags.Auth;
+
+ //
+ // Delete variable completely.
+ //
+ Status = ContextIn->GetVariableInfo (&VarInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ if ( (VarInfo.Buffer->State == VAR_ADDED)
+ || (VarInfo.Buffer->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)))
+ {
+ VarInfo.Buffer->State &= VAR_DELETED;
+ Status = ContextIn->UpdateVariableStore (
+ &VarInfo,
+ OFFSET_OF (VARIABLE_HEADER, State),
+ sizeof (VarInfo.Buffer->State),
+ &VarInfo.Buffer->State
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ }
+ }
+ }
+
+ VarDig->StoreIndex = StoreIndex;
+ VarDig->State = VAR_ADDED;
+
+ ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
+ VarInfo.Buffer = NULL;
+ VarInfo.StoreIndex = VarDig->StoreIndex;
+ VarInfo.Flags.Auth = Global->Flags.Auth;
+ Status = ContextIn->GetVariableInfo (&VarInfo);
+
+ //
+ // Check if cache pool need re-allocation due to variable size increase
+ //
+ VarSize = VARIABLE_HEADER_SIZE (VarDig->Flags.Auth);
+ VarSize += VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize);
+ VarSize += VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize);
+ VarSize = HEADER_ALIGN (VarSize);
+
+ NewVarSize = VARIABLE_HEADER_SIZE (VarInfo.Flags.Auth);
+ NewVarSize += VarInfo.Header.NameSize + GET_PAD_SIZE (VarInfo.Header.NameSize);
+ NewVarSize += VarInfo.Header.DataSize + GET_PAD_SIZE (VarInfo.Header.DataSize);
+ NewVarSize = HEADER_ALIGN (NewVarSize);
+
+ if (VarSize < NewVarSize) {
+ if (VarDig->Flags.Freeable == TRUE) {
+ FreePool (GET_BUFR (VarDig->CacheIndex));
+ }
+
+ Buffer = AllocatePool (NewVarSize);
+ if (Buffer != NULL) {
+ VarDig->CacheIndex = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+ } else {
+ ASSERT (FALSE);
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Update cached copy.
+ //
+ CopyMem (GET_BUFR (VarDig->CacheIndex), NewVariable, NewVarSize);
+
+ //
+ // Check if there is consecutive variable as part of the write or
+ // is it just the MetaDataHmacVar variable
+ //
+ if (NewVarSize < VariableSize) {
+ //
+ // Advance to consecutive Variable
+ //
+ NewVariable = GET_BUFR (GET_ADRS (NewVariable) + NewVarSize);
+
+ //
+ // Update the StoreIndex of consecutive Variable
+ //
+ ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
+ VarInfo.Buffer = NULL;
+ VarInfo.StoreIndex = VarDig->StoreIndex;
+ VarInfo.Flags.Auth = Global->Flags.Auth;
+ Status = ContextIn->GetNextVariableInfo (&VarInfo);
+ StoreIndex = VarInfo.StoreIndex;
+
+ //
+ // The new StoreIndex does not exist in the variable digest.
+ // It is yet to be updated.
+ // Therefore, find variable by Name & Guid instead.
+ //
+ VarInfo.StoreIndex = VAR_INDEX_INVALID;
+ VarDig = FindVariableInternal (Global, &VarInfo, FALSE);
+
+ //
+ // Check if cache pool need re-allocation due to variable size increase
+ //
+ VarSize = VARIABLE_HEADER_SIZE (VarDig->Flags.Auth);
+ VarSize += VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize);
+ VarSize += VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize);
+ VarSize = HEADER_ALIGN (VarSize);
+
+ NewVarSize = VARIABLE_HEADER_SIZE (VarInfo.Flags.Auth);
+ NewVarSize += VarInfo.Header.NameSize + GET_PAD_SIZE (VarInfo.Header.NameSize);
+ NewVarSize += VarInfo.Header.DataSize + GET_PAD_SIZE (VarInfo.Header.DataSize);
+ NewVarSize = HEADER_ALIGN (NewVarSize);
+
+ if (VarSize < NewVarSize) {
+ if (VarDig->Flags.Freeable == TRUE) {
+ FreePool (GET_BUFR (VarDig->CacheIndex));
+ }
+
+ Buffer = AllocatePool (NewVarSize);
+ if (Buffer != NULL) {
+ VarDig->CacheIndex = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+ } else {
+ ASSERT (FALSE);
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Update cached copy.
+ //
+ CopyMem (GET_BUFR (VarDig->CacheIndex), NewVariable, NewVarSize);
+ VarDig->StoreIndex = StoreIndex;
+ }
+
+ return Status;
+}
+
+/**
+ Refresh variable information changed by variable service.
+
+ @param[in] Variable Pointer to buffer of the updated variable.
+ @param[in] VariableSize Size of variable pointed by Variable.
+ @param[in] StoreIndex New index of the variable in store.
+ @param[in] RefreshData Flag to indicate if the variable has been updated.
+
+ @return EFI_SUCCESS No error occurred in updating.
+ @return EFI_NOT_FOUND The given variable was not found in
+ ProtectedVariableLib.
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibRefresh (
+ IN VARIABLE_HEADER *Variable,
+ IN UINTN VariableSize,
+ IN UINT64 StoreIndex,
+ IN BOOLEAN RefreshData
+ )
+{
+ EFI_STATUS Status;
+ PROTECTED_VARIABLE_INFO VarInfo;
+ PROTECTED_VARIABLE_GLOBAL *Global;
+ VARIABLE_DIGEST *VarDig;
+
+ (VOID)GetProtectedVariableGlobal (&Global);
+
+ ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
+ VarInfo.Buffer = Variable;
+ VarInfo.StoreIndex = VAR_INDEX_INVALID;
+ VarInfo.Flags.Auth = Global->Flags.Auth;
+
+ Status = GET_CNTX (Global)->GetVariableInfo (&VarInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ VarDig = FindVariableInternal (Global, &VarInfo, FALSE);
+ if (VarDig == NULL) {
+ ASSERT (VarDig != NULL);
+ return EFI_NOT_FOUND;
+ }
+
+ if (StoreIndex != VAR_INDEX_INVALID) {
+ VarDig->StoreIndex = StoreIndex;
+ }
+
+ if (RefreshData) {
+ if (VarDig->CacheIndex == VAR_INDEX_INVALID) {
+ VarDig->CacheIndex = (EFI_PHYSICAL_ADDRESS)(UINTN)
+ AllocatePool (MAX_VARIABLE_SIZE);
+ }
+
+ CopyMem (GET_BUFR (VarDig->CacheIndex), Variable, VariableSize);
+ }
+
+ //
+ // Information should stay the same other than following ones.
+ //
+ VarDig->State = VarInfo.Header.State;
+ VarDig->DataSize = (UINT32)VarInfo.Header.DataSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Determine if the variable is the HMAC variable
+
+ @param VariableName Pointer to variable name.
+
+ @return TRUE Variable is HMAC variable
+ @return FALSE Variable is not HMAC variable
+
+**/
+BOOLEAN
+ProtectedVariableLibIsHmac (
+ IN CHAR16 *VariableName
+ )
+{
+ INTN Result;
+
+ Result = StrnCmp (
+ METADATA_HMAC_VARIABLE_NAME,
+ VariableName,
+ METADATA_HMAC_VARIABLE_NAME_SIZE
+ );
+
+ if (Result == 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
new file mode 100644
index 000000000000..4591d1cd59e5
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
@@ -0,0 +1,233 @@
+/** @file
+ Implemention of ProtectedVariableLib for BootService/Runtime use cases.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Uefi.h>
+
+#include "Library/MemoryAllocationLib.h"
+#include "Library/UefiBootServicesTableLib.h"
+#include "Library/UefiRuntimeLib.h"
+#include "ProtectedVariableInternal.h"
+
+EFI_EVENT mVaChangeEvent = NULL;
+
+PROTECTED_VARIABLE_CONTEXT_IN mRtVariableContextIn = {
+ PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION,
+ sizeof (PROTECTED_VARIABLE_CONTEXT_IN),
+ 0,
+ FromRuntimeModule,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+PROTECTED_VARIABLE_GLOBAL mRtProtectedVariableGlobal = {
+ PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION,
+ sizeof (PROTECTED_VARIABLE_GLOBAL),
+ { 0 },
+ { 0 },
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ { 0, 0, 0 },
+ 0,
+ 0,
+ { 0, 0, 0, 0, 0, 0}
+};
+
+/**
+
+ Get global data structure used to process protected variable.
+
+ @param[out] Global Pointer to global configuration data.
+
+ @retval EFI_SUCCESS Get requested structure successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableGlobal (
+ OUT PROTECTED_VARIABLE_GLOBAL **Global OPTIONAL
+ )
+{
+ if (Global != NULL) {
+ mRtProtectedVariableGlobal.ContextIn = GET_ADRS (&mRtVariableContextIn);
+ *Global = &mRtProtectedVariableGlobal;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+ It convers pointer to new virtual address.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+VirtualAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ if (mRtVariableContextIn.FindVariableSmm != NULL) {
+ EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn.FindVariableSmm);
+ }
+
+ if (mRtVariableContextIn.GetVariableInfo != NULL) {
+ EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn.GetVariableInfo);
+ }
+
+ if (mRtVariableContextIn.GetNextVariableInfo != NULL) {
+ EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn.GetNextVariableInfo);
+ }
+
+ if (mRtVariableContextIn.UpdateVariableStore != NULL) {
+ EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn.UpdateVariableStore);
+ }
+
+ EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn);
+ if (mRtProtectedVariableGlobal.VariableCache != 0) {
+ EfiConvertPointer (0x0, (VOID **)&mRtProtectedVariableGlobal.VariableCache);
+ }
+
+ EfiConvertPointer (0x0, (VOID **)&mRtProtectedVariableGlobal);
+}
+
+/**
+
+ Initialization for protected variable services.
+
+ If this initialization failed upon any error, the whole variable services
+ should not be used. A system reset might be needed to re-construct NV
+ variable storage to be the default state.
+
+ @param[in] ContextIn Pointer to variable service context needed by
+ protected variable.
+
+ @retval EFI_SUCCESS Protected variable services are ready.
+ @retval EFI_INVALID_PARAMETER If ContextIn == NULL or something missing or
+ mismatching in the content in ContextIn.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibInitialize (
+ IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn
+ )
+{
+ if ( (ContextIn == NULL)
+ || (ContextIn->StructVersion != PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION)
+ || (ContextIn->FindVariableSmm == NULL)
+ || (ContextIn->GetVariableInfo == NULL))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (&mRtVariableContextIn, ContextIn, sizeof (mRtVariableContextIn));
+
+ //
+ // Register the event to convert the pointer for runtime.
+ //
+ gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ VirtualAddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mVaChangeEvent
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Prepare for variable update.
+
+ Not supported in DXE phase.
+
+ @retval EFI_UNSUPPORTED Updating variable is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteInit (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Update a variable with protection provided by this library.
+
+ Not supported in DXE phase.
+
+ @param[in,out] CurrVariable Variable to be updated. It's NULL if
+ adding a new variable.
+ @param[in] CurrVariableInDel In-delete-transition copy of updating variable.
+ @param[in,out] NewVariable Buffer of new variable data or
+ Buffer of "MetaDataHmacVar" and new variable (encrypted).
+ @param[in,out] NewVariableSize Size of NewVariable or
+ Size of (encrypted) NewVariable and "MetaDataHmacVar".
+
+ @retval EFI_UNSUPPORTED Not support updating variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibUpdate (
+ IN OUT VARIABLE_HEADER *CurrVariable,
+ IN VARIABLE_HEADER *CurrVariableInDel,
+ IN OUT VARIABLE_HEADER *NewVariable,
+ IN OUT UINTN *NewVariableSize
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Finalize a variable updating after it's written to NV variable storage
+ successfully.
+
+ (Not supported for BootService/Runtime use cases.)
+
+ @param[in] NewVariable Buffer of new variables and MetaDataHmacVar.
+ @param[in] VariableSize Size of buffer pointed by NewVariable.
+ @param[in] StoreIndex StoreIndex to NV variable storage from where the new
+ variable and MetaDataHmacVar have been written.
+
+ @retval EFI_UNSUPPORTED Not supported for BootService/Runtime use cases.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteFinal (
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN VariableSize,
+ IN UINT64 StoreIndex
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 18/28] MdeModulePkg: Reference Null ProtectedVariableLib
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (16 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 17/28] SecurityPkg: Add Protected Variable Services Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-04-29 18:04 ` [Patch v2 19/28] SecurityPkg: Add references to new *.inf files Judah Vang
` (11 subsequent siblings)
29 siblings, 0 replies; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Make reference to new Null ProtectVariableLib.
The null ProtectedVariableLib is used by default.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
MdeModulePkg/MdeModulePkg.dsc | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index b1d83461865e..6d9847c0cd34 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -2,7 +2,7 @@
# EFI/PI Reference Module Package for All Architectures
#
# (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
-# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2007 - 2022, Intel Corporation. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -103,6 +103,7 @@ [LibraryClasses]
DisplayUpdateProgressLib|MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.inf
VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
MmUnblockMemoryLib|MdePkg/Library/MmUnblockMemoryLib/MmUnblockMemoryLibNull.inf
+ ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
[LibraryClasses.EBC.PEIM]
IoLib|MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.inf
@@ -316,6 +317,7 @@ [Components]
MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf
MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+ MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 19/28] SecurityPkg: Add references to new *.inf files
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (17 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 18/28] MdeModulePkg: Reference Null ProtectedVariableLib Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-04-29 18:04 ` [Patch v2 20/28] ArmVirtPkg: Add reference to ProtectedVariableNull Judah Vang
` (10 subsequent siblings)
29 siblings, 0 replies; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add references to the different *ProtectedVariableLib.inf.
Also add references to VariableKeyLibNull.inf,
EncryptionVariableLibNull.inf, ProtectedVariableNull.inf.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
SecurityPkg/SecurityPkg.dsc | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc
index 73a93c2285b1..6d8318c6e4bf 100644
--- a/SecurityPkg/SecurityPkg.dsc
+++ b/SecurityPkg/SecurityPkg.dsc
@@ -1,7 +1,7 @@
## @file
# Security Module Package for All Architectures.
#
-# Copyright (c) 2009 - 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2009 - 2022, Intel Corporation. All rights reserved.<BR>
# (C) Copyright 2015-2020 Hewlett Packard Enterprise Development LP<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -66,8 +66,11 @@ [LibraryClasses]
TcgStorageCoreLib|SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCoreLib.inf
TcgStorageOpalLib|SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf
ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf
+
+ # These should be Null by default
VariableKeyLib|SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.inf
RpmcLib|SecurityPkg/Library/RpmcLibNull/RpmcLibNull.inf
+ EncryptionVariableLib|SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
TcgEventLogRecordLib|SecurityPkg/Library/TcgEventLogRecordLib/TcgEventLogRecordLib.inf
MmUnblockMemoryLib|MdePkg/Library/MmUnblockMemoryLib/MmUnblockMemoryLibNull.inf
SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf
@@ -251,8 +254,16 @@ [Components]
#
# Variable Confidentiality & Integrity
#
+ SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
+ SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
+ SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
+ SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf
+ SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
+ SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
+
SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.inf
SecurityPkg/Library/RpmcLibNull/RpmcLibNull.inf
+ SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
#
# Other
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 20/28] ArmVirtPkg: Add reference to ProtectedVariableNull
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (18 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 19/28] SecurityPkg: Add references to new *.inf files Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-03 7:29 ` Ard Biesheuvel
2022-04-29 18:04 ` [Patch v2 21/28] UefiPayloadPkg: Add ProtectedVariable reference Judah Vang
` (9 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Ard Biesheuvel, Leif Lindholm, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Need reference to ProtectVariableNullLib otherwise build fails.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
ArmVirtPkg/ArmVirtQemu.dsc | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
index aa0ce61630f7..cdebd94a9fce 100644
--- a/ArmVirtPkg/ArmVirtQemu.dsc
+++ b/ArmVirtPkg/ArmVirtQemu.dsc
@@ -1,7 +1,7 @@
#
# Copyright (c) 2011-2015, ARM Limited. All rights reserved.
# Copyright (c) 2014, Linaro Limited. All rights reserved.
-# Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.
+# Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -81,6 +81,7 @@ [LibraryClasses.common]
PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
PciHostBridgeLib|OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf
PciHostBridgeUtilityLib|OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf
+ ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
!if $(TPM2_ENABLE) == TRUE
Tpm2CommandLib|SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 21/28] UefiPayloadPkg: Add ProtectedVariable reference
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (19 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 20/28] ArmVirtPkg: Add reference to ProtectedVariableNull Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-04-29 21:03 ` Guo Dong
2022-04-29 18:04 ` [Patch v2 22/28] EmulatorPkg: " Judah Vang
` (8 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel
Cc: Jian J Wang, Guo Dong, Ray Ni, Maurice Ma, Benjamin You,
Sean Rhodes, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add reference for ProtectedVariableLib so build is successful.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Guo Dong <guo.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Maurice Ma <maurice.ma@intel.com>
Cc: Benjamin You <benjamin.you@intel.com>
Cc: Sean Rhodes <sean@starlabs.systems>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
UefiPayloadPkg/UefiPayloadPkg.dsc | 2 ++
1 file changed, 2 insertions(+)
diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc
index 17b30589e77c..fe835eed1bc7 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dsc
+++ b/UefiPayloadPkg/UefiPayloadPkg.dsc
@@ -263,9 +263,11 @@ [LibraryClasses]
AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
!if $(VARIABLE_SUPPORT) == "EMU"
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+ ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
!elseif $(VARIABLE_SUPPORT) == "SPI"
PlatformSecureLib|SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf
TpmMeasurementLib|SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf
+ ProtectedVariableLib|SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
S3BootScriptLib|MdePkg/Library/BaseS3BootScriptLibNull/BaseS3BootScriptLibNull.inf
MmUnblockMemoryLib|MdePkg/Library/MmUnblockMemoryLib/MmUnblockMemoryLibNull.inf
!endif
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 22/28] EmulatorPkg: Add ProtectedVariable reference
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (20 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 21/28] UefiPayloadPkg: Add ProtectedVariable reference Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-04-29 18:04 ` [Patch v2 23/28] OvmfPkg: " Judah Vang
` (7 subsequent siblings)
29 siblings, 0 replies; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Andrew Fish, Ray Ni, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add reference to null ProtectedVariableLib.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Andrew Fish <afish@apple.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
EmulatorPkg/EmulatorPkg.dsc | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/EmulatorPkg/EmulatorPkg.dsc b/EmulatorPkg/EmulatorPkg.dsc
index 554c13ddb500..4a6d50390db7 100644
--- a/EmulatorPkg/EmulatorPkg.dsc
+++ b/EmulatorPkg/EmulatorPkg.dsc
@@ -4,7 +4,7 @@
# The Emulation Platform can be used to debug individual modules, prior to creating
# a real platform. This also provides an example for how an DSC is created.
#
-# Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
# Portions copyright (c) 2010 - 2011, Apple Inc. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.
#
@@ -119,6 +119,7 @@ [LibraryClasses]
LockBoxLib|MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf
CpuExceptionHandlerLib|MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+ ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf
VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 23/28] OvmfPkg: Add ProtectedVariable reference
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (21 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 22/28] EmulatorPkg: " Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-04-29 18:04 ` [Patch v2 24/28] OvmfPkg: Add ProtectedVariableLib reference Judah Vang
` (6 subsequent siblings)
29 siblings, 0 replies; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel
Cc: Jian J Wang, Ard Biesheuvel, Jiewen Yao, Jordan Justen,
Gerd Hoffmann, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add reference to null ProtectedVariableLib.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
OvmfPkg/OvmfPkgIa32.dsc | 1 +
OvmfPkg/OvmfPkgIa32X64.dsc | 1 +
OvmfPkg/OvmfPkgX64.dsc | 1 +
OvmfPkg/OvmfXen.dsc | 3 ++-
4 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index f02b371f7427..358ad991a2dc 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -178,6 +178,7 @@ [LibraryClasses]
LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
+ ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
!endif
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index cb68e612bd35..7e46d53061b1 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -182,6 +182,7 @@ [LibraryClasses]
LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
+ ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
!endif
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 45ffa2dbe35f..32ebe045c03d 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -189,6 +189,7 @@ [LibraryClasses]
LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
+ ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index a1626d06dfc3..532a3e1b2027 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -1,7 +1,7 @@
## @file
# EFI/Framework Open Virtual Machine Firmware (OVMF) platform
#
-# Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
# Copyright (c) 2019, Citrix Systems, Inc.
# Copyright (c) Microsoft Corporation.
@@ -218,6 +218,7 @@ [LibraryClasses]
Tcg2PhysicalPresenceLib|OvmfPkg/Library/Tcg2PhysicalPresenceLibNull/DxeTcg2PhysicalPresenceLib.inf
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+ ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
RealTimeClockLib|OvmfPkg/Library/XenRealTimeClockLib/XenRealTimeClockLib.inf
TimeBaseLib|EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf
!ifdef $(DEBUG_ON_HYPERVISOR_CONSOLE)
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 24/28] OvmfPkg: Add ProtectedVariableLib reference
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (22 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 23/28] OvmfPkg: " Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-04-29 18:04 ` [Patch v2 25/28] " Judah Vang
` (5 subsequent siblings)
29 siblings, 0 replies; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel
Cc: Jian J Wang, Jiewen Yao, Min Xu, Brijesh Singh, Erdem Aktas,
James Bottomley, Tom Lendacky, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add reference to null ProtectedVariableLib.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
OvmfPkg/AmdSev/AmdSevX64.dsc | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index f0700035c116..b0072f5fb0d3 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -3,7 +3,7 @@
# virtual machine remote attestation and secret injection
#
# Copyright (c) 2020 James Bottomley, IBM Corporation.
-# Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -176,6 +176,7 @@ [LibraryClasses]
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
BlobVerifierLib|OvmfPkg/AmdSev/BlobVerifierLibSevHashes/BlobVerifierLibSevHashes.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
+ ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
!if $(SOURCE_DEBUG_ENABLE) == TRUE
PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 25/28] OvmfPkg: Add ProtectedVariableLib reference
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (23 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 24/28] OvmfPkg: Add ProtectedVariableLib reference Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-04-29 18:04 ` [Patch v2 26/28] " Judah Vang
` (4 subsequent siblings)
29 siblings, 0 replies; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Rebecca Cran, Peter Grehan, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add reference to null ProtectedVariableLib.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Rebecca Cran <rebecca@bsdio.com>
Cc: Peter Grehan <grehan@freebsd.org>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
OvmfPkg/Bhyve/BhyveX64.dsc | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/OvmfPkg/Bhyve/BhyveX64.dsc b/OvmfPkg/Bhyve/BhyveX64.dsc
index a8fa4d38ab60..5b36dc2358bb 100644
--- a/OvmfPkg/Bhyve/BhyveX64.dsc
+++ b/OvmfPkg/Bhyve/BhyveX64.dsc
@@ -1,6 +1,6 @@
#
# Copyright (c) 2020, Rebecca Cran <rebecca@bsdio.com>
-# Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
# Copyright (c) 2014, Pluribus Networks, Inc.
#
@@ -171,6 +171,7 @@ [LibraryClasses]
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
+ ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 26/28] OvmfPkg: Add ProtectedVariableLib reference
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (24 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 25/28] " Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-04-29 18:04 ` [Patch v2 27/28] OvmfPkg: Add ProtectedVariable reference Judah Vang
` (3 subsequent siblings)
29 siblings, 0 replies; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Gerd Hoffmann, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add reference to null ProtectedVariableLib.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
OvmfPkg/Microvm/MicrovmX64.dsc | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/OvmfPkg/Microvm/MicrovmX64.dsc b/OvmfPkg/Microvm/MicrovmX64.dsc
index 20c3c9c4d862..723be8ad345c 100644
--- a/OvmfPkg/Microvm/MicrovmX64.dsc
+++ b/OvmfPkg/Microvm/MicrovmX64.dsc
@@ -1,7 +1,7 @@
## @file
# EFI/Framework Open Virtual Machine Firmware (OVMF) platform
#
-# Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
# Copyright (c) Microsoft Corporation.
#
@@ -183,6 +183,7 @@ [LibraryClasses]
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
+ ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
!if $(SOURCE_DEBUG_ENABLE) == TRUE
PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 27/28] OvmfPkg: Add ProtectedVariable reference
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (25 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 26/28] " Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-03 7:30 ` [edk2-devel] " Ard Biesheuvel
2022-04-29 18:04 ` [Patch v2 28/28] CryptoPkg: Enable cypto HMAC KDF library Judah Vang
` (2 subsequent siblings)
29 siblings, 1 reply; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Sebastien Boeuf, Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add reference to null ProtectedVariableLib.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Sebastien Boeuf <sebastien.boeuf@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
OvmfPkg/CloudHv/CloudHvX64.dsc | 1 +
1 file changed, 1 insertion(+)
diff --git a/OvmfPkg/CloudHv/CloudHvX64.dsc b/OvmfPkg/CloudHv/CloudHvX64.dsc
index d1c85f60c768..3ec7e860c613 100644
--- a/OvmfPkg/CloudHv/CloudHvX64.dsc
+++ b/OvmfPkg/CloudHv/CloudHvX64.dsc
@@ -180,6 +180,7 @@ [LibraryClasses]
VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
+ ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
!endif
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [Patch v2 28/28] CryptoPkg: Enable cypto HMAC KDF library
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (26 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 27/28] OvmfPkg: Add ProtectedVariable reference Judah Vang
@ 2022-04-29 18:04 ` Judah Vang
2022-05-17 2:48 ` [edk2-devel] [Patch v2 00/28] UEFI variable protection Michael Kubacki
[not found] ` <16EFC4965F71DFB8.20068@groups.io>
29 siblings, 0 replies; 49+ messages in thread
From: Judah Vang @ 2022-04-29 18:04 UTC (permalink / raw)
To: devel; +Cc: Jiewen Yao, Jian J Wang, Xiaoyu Lu, Guomin Jiang,
Nishant C Mistry
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
RPMC confidentiality feature requires HMAC-SHA256 support during
SMM phase. This allows the protected variable's data to be
encrypted in the SPI flash.
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Xiaoyu Lu <xiaoyux.lu@intel.com>
Cc: Guomin Jiang <guomin.jiang@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf b/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
index ae75bc87b5e5..28ad0bf0816d 100644
--- a/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
+++ b/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
@@ -43,7 +43,7 @@ [Sources]
Hash/CryptCShake256.c
Hash/CryptParallelHash.c
Hmac/CryptHmacSha256.c
- Kdf/CryptHkdfNull.c
+ Kdf/CryptHkdf.c
Cipher/CryptAes.c
Pk/CryptRsaBasic.c
Pk/CryptRsaExtNull.c
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* Re: [Patch v2 21/28] UefiPayloadPkg: Add ProtectedVariable reference
2022-04-29 18:04 ` [Patch v2 21/28] UefiPayloadPkg: Add ProtectedVariable reference Judah Vang
@ 2022-04-29 21:03 ` Guo Dong
0 siblings, 0 replies; 49+ messages in thread
From: Guo Dong @ 2022-04-29 21:03 UTC (permalink / raw)
To: Vang, Judah, devel@edk2.groups.io
Cc: Wang, Jian J, Ni, Ray, Maurice Ma, You, Benjamin, Rhodes, Sean,
Mistry, Nishant C
Reviewed-by: Guo Dong <guo.dong@intel.com>
-----Original Message-----
From: Vang, Judah <judah.vang@intel.com>
Sent: Friday, April 29, 2022 11:04 AM
To: devel@edk2.groups.io
Cc: Wang, Jian J <jian.j.wang@intel.com>; Dong, Guo <guo.dong@intel.com>; Ni, Ray <ray.ni@intel.com>; Maurice Ma <maurice.ma@intel.com>; You, Benjamin <benjamin.you@intel.com>; Rhodes, Sean <sean@starlabs.systems>; Mistry, Nishant C <nishant.c.mistry@intel.com>
Subject: [Patch v2 21/28] UefiPayloadPkg: Add ProtectedVariable reference
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
Add reference for ProtectedVariableLib so build is successful.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Guo Dong <guo.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Maurice Ma <maurice.ma@intel.com>
Cc: Benjamin You <benjamin.you@intel.com>
Cc: Sean Rhodes <sean@starlabs.systems>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
UefiPayloadPkg/UefiPayloadPkg.dsc | 2 ++
1 file changed, 2 insertions(+)
diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc
index 17b30589e77c..fe835eed1bc7 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dsc
+++ b/UefiPayloadPkg/UefiPayloadPkg.dsc
@@ -263,9 +263,11 @@ [LibraryClasses]
AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
!if $(VARIABLE_SUPPORT) == "EMU"
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+ ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
!elseif $(VARIABLE_SUPPORT) == "SPI"
PlatformSecureLib|SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf
TpmMeasurementLib|SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf
+ ProtectedVariableLib|SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
S3BootScriptLib|MdePkg/Library/BaseS3BootScriptLibNull/BaseS3BootScriptLibNull.inf
MmUnblockMemoryLib|MdePkg/Library/MmUnblockMemoryLib/MmUnblockMemoryLibNull.inf
!endif
--
2.35.1.windows.2
^ permalink raw reply related [flat|nested] 49+ messages in thread
* Re: [Patch v2 20/28] ArmVirtPkg: Add reference to ProtectedVariableNull
2022-04-29 18:04 ` [Patch v2 20/28] ArmVirtPkg: Add reference to ProtectedVariableNull Judah Vang
@ 2022-05-03 7:29 ` Ard Biesheuvel
0 siblings, 0 replies; 49+ messages in thread
From: Ard Biesheuvel @ 2022-05-03 7:29 UTC (permalink / raw)
To: Judah Vang
Cc: edk2-devel-groups-io, Jian J Wang, Ard Biesheuvel, Leif Lindholm,
Nishant C Mistry
On Fri, 29 Apr 2022 at 20:05, Judah Vang <judah.vang@intel.com> wrote:
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> Need reference to ProtectVariableNullLib otherwise build fails.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> ArmVirtPkg/ArmVirtQemu.dsc | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
> index aa0ce61630f7..cdebd94a9fce 100644
> --- a/ArmVirtPkg/ArmVirtQemu.dsc
> +++ b/ArmVirtPkg/ArmVirtQemu.dsc
> @@ -1,7 +1,7 @@
> #
> # Copyright (c) 2011-2015, ARM Limited. All rights reserved.
> # Copyright (c) 2014, Linaro Limited. All rights reserved.
> -# Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.
> +# Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.
> #
> # SPDX-License-Identifier: BSD-2-Clause-Patent
> #
> @@ -81,6 +81,7 @@ [LibraryClasses.common]
> PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
> PciHostBridgeLib|OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf
> PciHostBridgeUtilityLib|OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf
> + ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
>
> !if $(TPM2_ENABLE) == TRUE
> Tpm2CommandLib|SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf
> --
> 2.35.1.windows.2
>
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [edk2-devel] [Patch v2 27/28] OvmfPkg: Add ProtectedVariable reference
2022-04-29 18:04 ` [Patch v2 27/28] OvmfPkg: Add ProtectedVariable reference Judah Vang
@ 2022-05-03 7:30 ` Ard Biesheuvel
0 siblings, 0 replies; 49+ messages in thread
From: Ard Biesheuvel @ 2022-05-03 7:30 UTC (permalink / raw)
To: edk2-devel-groups-io, Judah Vang
Cc: Jian J Wang, Sebastien Boeuf, Nishant C Mistry
On Fri, 29 Apr 2022 at 20:05, Judah Vang <judah.vang@intel.com> wrote:
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> Add reference to null ProtectedVariableLib.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Sebastien Boeuf <sebastien.boeuf@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> OvmfPkg/CloudHv/CloudHvX64.dsc | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/OvmfPkg/CloudHv/CloudHvX64.dsc b/OvmfPkg/CloudHv/CloudHvX64.dsc
> index d1c85f60c768..3ec7e860c613 100644
> --- a/OvmfPkg/CloudHv/CloudHvX64.dsc
> +++ b/OvmfPkg/CloudHv/CloudHvX64.dsc
> @@ -180,6 +180,7 @@ [LibraryClasses]
> VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
> LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
> MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
> + ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
> !if $(SMM_REQUIRE) == FALSE
> LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
> !endif
> --
> 2.35.1.windows.2
>
>
>
>
>
>
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [Patch v2 06/28] MdeModulePkg: Add new include files
2022-04-29 18:04 ` [Patch v2 06/28] MdeModulePkg: Add new include files Judah Vang
@ 2022-05-12 9:31 ` Wang, Jian J
0 siblings, 0 replies; 49+ messages in thread
From: Wang, Jian J @ 2022-05-12 9:31 UTC (permalink / raw)
To: Vang, Judah, devel@edk2.groups.io; +Cc: Gao, Liming, Mistry, Nishant C
Hi Judah,
Please check my comments inlined below.
Regards,
Jian
> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Saturday, April 30, 2022 2:04 AM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [Patch v2 06/28] MdeModulePkg: Add new include files
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> Add EncryptionVariableLib.h for providing encryption and
> decryption services for protected variables.
> Add ProtectedVariableLib.h for providing integrity or
> variables.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> MdeModulePkg/Include/Library/EncryptionVariableLib.h | 165 +++++
> MdeModulePkg/Include/Library/ProtectedVariableLib.h | 700
> ++++++++++++++++++++
> 2 files changed, 865 insertions(+)
>
> diff --git a/MdeModulePkg/Include/Library/EncryptionVariableLib.h
> b/MdeModulePkg/Include/Library/EncryptionVariableLib.h
> new file mode 100644
> index 000000000000..c7740e659dcf
> --- /dev/null
> +++ b/MdeModulePkg/Include/Library/EncryptionVariableLib.h
> @@ -0,0 +1,165 @@
> +/** @file
> + Provides services to encrypt/decrypt variables.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef ENCRYPTION_VARIABLE_LIB_H_
> +#define ENCRYPTION_VARIABLE_LIB_H_
> +
> +#include <IndustryStandard/Tpm20.h>
> +
> +#include <Guid/VariableFormat.h>
> +
> +#include <Library/AuthVariableLib.h>
> +
> +#define ENC_TYPE_NULL 0
> +#define ENC_TYPE_AES TPM_ALG_AES
> +
> +typedef struct _VARIABLE_ENCRYPTION_FLAGS {
> + BOOLEAN Auth; // Variable is authenticated or not
> + BOOLEAN DecryptInPlace; // Do decryption in place
> + BOOLEAN Protected; // Variable is protected or not
> +} VARIABLE_ENCRYPTION_FLAGS;
> +
> +typedef struct _VARIABLE_ENCRYPTION_INFO {
> + AUTH_VARIABLE_INFO Header; // Authenticated varabile header
> + VARIABLE_HEADER *Buffer; // Pointer to variable buffer
> + UINT64 StoreIndex; // Variable store index
> + VOID *PlainData; // Pointer to plain data
> + UINT32 PlainDataSize; // Size of plain data
> + VOID *CipherData; // Pointer to cipher data
> + UINT32 CipherDataSize; // Size of cipher data
> + UINT32 CipherHeaderSize; // Size of cipher header
> + UINT32 CipherDataType; // Type of cipher data
> + VOID *Key; // Pointer to encrypt/decrypt key
> + UINT32 KeySize; // Size of key
> + VARIABLE_ENCRYPTION_FLAGS Flags; // Encryption flags
> +} VARIABLE_ENCRYPTION_INFO;
> +
> +/**
> + Encrypt variable data.
> +
> + @param[in, out] VarInfo Pointer to structure containing detailed
> information about a variable.
> +
> + @retval EFI_SUCCESS Function successfully executed.
> + @retval EFI_INVALID_PARAMETER If ProtectedVarLibContextIn == NULL or
> ProtectedVarLibContextOut == NULL.
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
> + @retval EFI_UNSUPPORTED Unsupported to process authenticated
> variable.
[JianJW] authenticated -> encrypted
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +EncryptVariable (
> + IN OUT VARIABLE_ENCRYPTION_INFO *VarInfo
> + );
> +
> +/**
> + Decrypt variable data.
> +
> + If VarEncInfo->CipherData is not NULL, it must holds the cipher data to be
> + decrypted. Otherwise, assume the cipher data from variable data buffer, i.e.
> + VarEncInfo->Header.Data.
> +
> + If VarEncInfo->Flags.DecryptInPlace is TRUE, the decrypted data will be put
> + back in the same buffer as cipher buffer got above, after encryption header,
> + which helps to identify later if the data in buffer is decrypted or not. This
> + can avoid repeat decryption when accessing the same variable more than
> once.
> +
> + If VarEncInfo->Flags.DecryptInPlace is FALSE, VarEncInfo->PlainData must be
> + passed in with a valid buffer with VarEncInfo->PlainDataSize set correctly
> + with its size.
> +
> + Note the VarEncInfo->PlainData is always pointing to the buffer address with
> + decrypted data without encryption header, and VarEncInfo->PlainDataSize is
> + always the size of original variable data, if this function returned
> + successfully.
> +
> + @param[in, out] VarInfo Pointer to structure containing detailed
> + information about a variable.
> +
> + @retval EFI_SUCCESS Variable was decrypted successfully.
> + @retval EFI_INVALID_PARAMETER Variable information in VarEncInfo is
> invalid.
> + @retval EFI_BUFFER_TOO_SMALL VarEncInfo->PlainData is not NULL but
> + VarEncInfo->PlainDataSize is too small.
> + @retval EFI_ABORTED Uknown error occurred during decrypting.
[JianJW] Uknown -> Unknown
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
> + @retval EFI_COMPROMISED_DATA The cipher header is not valid.
> + @retval EFI_UNSUPPORTED Unsupported to encrypt variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DecryptVariable (
> + IN OUT VARIABLE_ENCRYPTION_INFO *VarInfo
> + );
> +
> +/**
> + Get cipher information about a variable, including plaindata size,
> + cipher algorithm type, etc.
> +
> + For data passed in with VarEncInfo,
> +
> + VarEncInfo->Header.Data
> + - The variable data in normal variable structure.
> + VarEncInfo->Header.DataSize
> + - The size of variable data.
> +
> + For data passed out with VarEncInfo (valid only if EFI_SUCCESS is returned),
> +
> + VarEncInfo->CipherDataType
> + - ENC_TYPE_NULL, if the variable is not encrypted or has been decrypted;
> + - ENC_TYPE_AES, if the variable is encrypted.
> + VarEncInfo->CipherHeaderSize
> + - Size of cipher header put before encrypted or decrypted data.
> + VarEncInfo->PlainData
> + - NULL, if the variable is encrypted; Or
> + - pointer to original variable data, if the variable has been decrypted.
> + VarEncInfo->PlainDataSize
> + - The size of original variable data
> + VarEncInfo->CipherData
> + - NULL, if the variable is decrypted; Or
> + - pointer to start of encrypted variable data, including encryption header;
> + VarEncInfo->CipherDataSize
> + - The size of encrypted variable data, including encryption header.
> +
> + @param[in, out] VarInfo Pointer to structure containing detailed
> + information about a variable.
> +
> + @retval EFI_SUCCESS The information was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER Variable information in VarEncInfo is
> invalid.
> + @retval EFI_NOT_FOUND No cipher information recognized.
> + @retval EFI_UNSUPPORTED Unsupported interface.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetCipherDataInfo (
> + IN OUT VARIABLE_ENCRYPTION_INFO *VarInfo
> + );
> +
> +/**
> + Force set cipher information for a variable, like plaindata size,
> + cipher algorithm type, cipher data etc.
> +
> + The destination buffer must be passed via VarEncInfo->Header.Data.
> +
> + This method is only used to update and/or change plain data information.
> +
> + @param[in, out] VarInfo Pointer to structure containing detailed
> + information about a variable.
> +
> + @retval EFI_SUCCESS The information was updated successfully.
> + @retval EFI_INVALID_PARAMETER Variable information in VarEncInfo is
> invalid.
> + @retval EFI_UNSUPPORTED If this method is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetCipherDataInfo (
> + IN OUT VARIABLE_ENCRYPTION_INFO *VarInfo
> + );
> +
> +#endif //_ENCRYPTION_VARIABLE_LIB_H_
> diff --git a/MdeModulePkg/Include/Library/ProtectedVariableLib.h
> b/MdeModulePkg/Include/Library/ProtectedVariableLib.h
> new file mode 100644
> index 000000000000..2f57b4ebbc70
> --- /dev/null
> +++ b/MdeModulePkg/Include/Library/ProtectedVariableLib.h
> @@ -0,0 +1,700 @@
> +/** @file
> + Defines interfaces of protected variable services for non-volatile variable
> + storage.
> +
> +Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PROTECTED_VARIABLE_LIB_H_
> +#define PROTECTED_VARIABLE_LIB_H_
> +
> +#include <PiPei.h>
> +#include <PiDxe.h>
> +
> +#include <Guid/VariableFormat.h>
> +
> +#include <Protocol/VarCheck.h>
> +#include <Protocol/FirmwareVolumeBlock.h>
> +
> +#include <Library/UefiLib.h>
> +#include <Library/EncryptionVariableLib.h>
> +
> +#pragma pack(1)
> +
> +typedef struct _VARIABLE_DIGEST_FLAGS {
> + BOOLEAN Auth; // Authenticated variable format
> + BOOLEAN Valid; // Valid variable data in current variable
> + BOOLEAN Protected; // Protected variable (used in calculating
> HMAC)
> + BOOLEAN Encrypted; // Encrypted variable
> + BOOLEAN Freeable; // Memory reserved for current node can
> be freed
> + BOOLEAN CacheIndexAhead; // Indicates if CacheIndex is Ahead
> relative to Global structure
> + BOOLEAN Reserved[2]; // Reserved fields
> +} VARIABLE_DIGEST_FLAGS;
> +
> +typedef struct _VARIABLE_DIGEST {
> + ///
> + /// Pointer to digest of next variable in a pre-defined rule of order for
> + /// integration verification. In other words, the final HMAC of all
> + /// protected variables is calculated by concatenating digest of each
> + /// variable in the order of this singly linked list.
> + ///
> + EFI_PHYSICAL_ADDRESS Prev;
> + EFI_PHYSICAL_ADDRESS Next;
> + ///
> + /// Index to variable in physical store, used to locate the variable directly
> + /// inside the store (Implementation dependent).
> + ///
> + EFI_PHYSICAL_ADDRESS StoreIndex;
> + ///
> + /// Index to variable in memory cache, used to locate the variable directly
> + /// inside the cache (Implementation dependent).
> + ///
> + EFI_PHYSICAL_ADDRESS CacheIndex;
> +
> + ///
> + /// Pointer to Cache offset within Global Structure
> + ///
> + UINT32 CacheOffset;
> +
> + ///
> + /// Frequently accessed information relating to the variable.
> + ///
> + UINT16 DigestSize; // Size of digest value
> + UINT16 NameSize; // Size of variable name
> + UINT32 DataSize; // Size of variable data
> + UINT32 PlainDataSize; // Size of plain data of current variable (if
> encrypted)
> + UINT32 State; // State of current variable
> + UINT32 Attributes; // Attributes of current variable
> +
> + EFI_GUID VendorGuid; // GUID
> + VARIABLE_DIGEST_FLAGS Flags; // Variable digest flags
> + //
> + // Data with variable length are put at the end of this structure.
> + //
> + // CHAR16 VariableName[NameSize/2];
> + // UINT8 DigestValue[DigestSize];
> +} VARIABLE_DIGEST;
> +
> +#pragma pack()
> +
> +#define VAR_DIG_NAMEOFF(VarDig) (sizeof (VARIABLE_DIGEST))
> +#define VAR_DIG_DIGOFF(VarDig) (VAR_DIG_NAMEOFF (VarDig) + (VarDig)-
> >NameSize)
> +
> +#define VAR_DIG_END(VarDig) (VAR_DIG_DIGOFF (VarDig) + (VarDig)-
> >DigestSize)
> +
> +#define VAR_DIG_VALUE(VarDig) (VOID *)((UINTN)(VarDig) +
> VAR_DIG_DIGOFF (VarDig))
> +#define VAR_DIG_NAME(VarDig) (CHAR16 *)((UINTN)(VarDig) +
> VAR_DIG_NAMEOFF (VarDig))
> +#define VAR_DIG_GUID(VarDig) &(VAR_DIG_PTR (VarDig)->VendorGuid)
> +
> +#define VAR_DIG_PTR(Addr) ((VARIABLE_DIGEST *)(UINTN)(Addr))
> +#define VAR_DIG_ADR(Ptr) ((EFI_PHYSICAL_ADDRESS)(UINTN)(Ptr))
> +#define VAR_DIG_NEXT(VarDig) (VAR_DIG_PTR ((VarDig)->Next))
> +#define VAR_DIG_PREV(VarDig) (VAR_DIG_PTR ((VarDig)->Prev))
> +
> +#define VAR_INDEX_INVALID ((UINT64)(-1))
> +
> +#define VAR_HDR_PTR(Addr) ((VARIABLE_HEADER *)(UINTN)(Addr))
> +
> +typedef VARIABLE_ENCRYPTION_INFO PROTECTED_VARIABLE_INFO;
> +
> +/**
> +
> + This function writes data to the NV variable storage at given position.
> +
> + Note: Per current variable service architecture, only SMM is allowed to
> + (directly) change NV variable storage.
> +
> + @param VariableInfo Pointer to structure holding details of a variable.
> + @param Offset Offset to the given variable to write from.
> + @param Size Size of data to be written.
> + @param Buffer Pointer to the buffer from which data is written.
> +
> + @retval EFI_INVALID_PARAMETER Invalid parameters passed in.
> + @retval EFI_UNSUPPORTED Updating NV variable storage is not
> supported.
> + @retval EFI_OUT_OF_RESOURCES Not enough resource to complete the
> operation.
> + @retval EFI_SUCCESS Variable store successfully updated.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *PROTECTED_VAR_LIB_UPDATE_VARIABLE_STORE)(
> + IN PROTECTED_VARIABLE_INFO *VariableInfo,
> + IN UINTN Offset,
> + IN UINT32 Size,
> + IN UINT8 *Buffer
> + );
> +
> +/**
> + Update the variable region with Variable information.
> +
> + @param[in] AuthVariableInfo Pointer AUTH_VARIABLE_INFO structure for
> + input of the variable.
[JianJW] "Pointer" -> "Pointer to"
> +
> + @retval EFI_SUCCESS The update operation is success.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_WRITE_PROTECTED Variable is write-protected.
> + @retval EFI_OUT_OF_RESOURCES There is not enough resource.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *PROTECTED_VAR_LIB_UPDATE_VARIABLE)(
> + IN AUTH_VARIABLE_INFO *AuthVariableInfo
> + );
> +
> +/**
> +
> + Retrieve details about a variable and return them in VariableInfo->Header.
> +
> + If VariableInfo->Address is given, this function will calculate its offset
> + relative to given variable storage via VariableStore; Otherwise, it will try
> + other internal variable storages or cached copies. It's assumed that, for all
> + copies of NV variable storage, all variables are stored in the same relative
> + position. If VariableInfo->Address is found in the range of any storage copies,
> + its offset relative to that storage should be the same in other copies.
> +
> + If VariableInfo->Offset is given (non-zero) but not VariableInfo->Address,
> + this function will return the variable memory address inside VariableStore,
> + if given, via VariableInfo->Address; Otherwise, the address of other storage
> + copies will be returned, if any.
> +
> + For a new variable whose offset has not been determined, a value of -1 as
> + VariableInfo->Offset should be passed to skip the offset calculation.
> +
> + @param VariableInfo Pointer to variable information.
> +
> + @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo-
> >Address
> + and VariableInfo->Offset are NULL (0).
> + @retval EFI_NOT_FOUND If given Address or Offset is out of range of
> + any given or internal storage copies.
> + @retval EFI_SUCCESS Variable details are retrieved successfully.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *PROTECTED_VAR_LIB_GET_VAR_INFO)(
> + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
> + );
> +
> +/**
> +
> + Retrieve details of the variable next to given variable within VariableStore.
> +
> + If VarInfo->Address is NULL, the first one in VariableStore is returned.
> +
> + VariableStart and/or VariableEnd can be given optionally for the situation
> + in which the valid storage space is smaller than the VariableStore->Size.
> + This usually happens when PEI variable services make a compact variable
> + cache to save memory, which cannot make use VariableStore->Size to
> determine
> + the correct variable storage range.
> +
> + @param VariableStore Pointer to a variable storage. It's optional.
> + @param VariableStart Start point of valid range in VariableStore.
> + @param VariableEnd End point of valid range in VariableStore.
> + @param VariableInfo Pointer to variable information.
> +
> + @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL.
> + @retval EFI_NOT_FOUND If the end of VariableStore is reached.
> + @retval EFI_SUCCESS The next variable is retrieved successfully.
[JianJW] The list of @param and @retval don't match the function prototype
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *PROTECTED_VAR_LIB_GET_NEXT_VAR_INFO)(
> + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
> + );
> +
> +typedef
> +EFI_STATUS
> +(EFIAPI *DIGEST_METHOD_CALLBACK)(
> + IN VARIABLE_HEADER *Variable,
> + IN OUT VARIABLE_DIGEST *Digest
> + );
[JianJW] Missing function header comment
> +
> +/**
> +
> + Initialize a memory copy of NV variable storage.
> +
> + To save memory consumption (especially in PEI phase), it's allowed to cache
> + only valid variables. In such case, an index table recording offset of each
> + valid variables could be employed. The index table makes sure the cached
> copy
> + to be synchronized with the original copy in NV variable storage. To avoid
> + TOCTOU issue, once the variables are cached in memory and verified, NV
> + variable storage should not be used to read variable information. The cached
> + copy should be used instead.
> +
> + If StoreCacheBase is not given, this function should return the required
> + cache size and valid variable number, if VariableNumber is not NULL. Then
> + the caller can prepare correct cache buffer and index table buffer before
> + next calling.
> +
> + @param[in] CacheBase Base address of NV variable storage cache.
> + @param[in] CacheSize Size of CacheBuffer.
> + @param[out] CacheSize Size of required cache buffer.
> + @param[out] DigBuffer Base address of digest of each variable.
> + @param[in, out] DigBufferSize Digest size of one variable if DigestBuffer is
> NULL.
> + Size of DigestBuffer if DigestBuffer is NOT NULL.
> + @param[out] DigSize Required size of DigestBuffer if DigestBuffer is
> NULL.
> + @param[out] DigMethod Method used to generate digest for each
> variable.
> + @param[out] VarNumber Number of valid variables.
> + @param[out] AuthFlag Auth-variable indicator.
> +
> + @retval EFI_INVALID_PARAMETER CacheSize is NULL; Or,
> + StoreCacheBase is 0 but *CacheSize it not.
> + @retval EFI_VOLUME_CORRUPTED If original NV variable storage is
> corrupted.
> + @retval EFI_BUFFER_TOO_SMALL If *CacheSize is smaller than required
> memory.
> + @retval EFI_SUCCESS The cached variable storage is initialized.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *PROTECTED_VAR_LIB_INIT_VAR_STORE)(
> + OUT VOID *CacheBase OPTIONAL,
> + IN OUT UINT32 *CacheSize OPTIONAL,
> + OUT VOID *DigBuffer OPTIONAL,
> + IN OUT UINT32 *DigBufferSize OPTIONAL,
> + IN UINT32 DigSize OPTIONAL,
> + IN DIGEST_METHOD_CALLBACK DigMethod OPTIONAL,
> + OUT UINT32 *VarNumber OPTIONAL,
> + OUT BOOLEAN *AuthFlag OPTIONAL
> + );
[JianJW] This function and above one are not used at all. Please remove it.
> +
> +/**
> +
> + Initiate a variable retrieval in SMM environment from non-SMM environment.
> +
> + This is usually required in BS/RT environment when local cached copy is in
> + encrypted form. Variable decryption can only be done in SMM environment.
> +
> + @param[in] VariableName Name of Variable to be found.
> + @param[in] VendorGuid Variable vendor GUID.
> + @param[out] Attributes Attribute value of the variable found.
> + @param[in, out] DataSize Size of Data found. If size is less than the
> + data, this value contains the required size.
> + @param[out] Data Data pointer.
> +
> + @retval EFI_SUCCESS Found the specified variable.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_NOT_FOUND The specified variable could not be found.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *PROTECTED_VAR_LIB_FIND_VAR_SMM)(
> + IN CHAR16 *VariableName,
> + IN EFI_GUID *VendorGuid,
> + OUT UINT32 *Attributes OPTIONAL,
> + IN OUT UINTN *DataSize,
> + OUT VOID *Data OPTIONAL
> + );
[JianJW] The parameters are not aligned.
> +
> +/**
> + Check if a variable is user variable or not.
> +
> + @param[in] Variable Pointer to variable header.
> +
> + @retval TRUE User variable.
> + @retval FALSE System variable.
> +
> +**/
> +typedef
> +BOOLEAN
> +(EFIAPI *PROTECTED_VAR_LIB_IS_USER_VAR)(
> + IN VARIABLE_HEADER *Variable
> + );
[JianJW] This function type is not used at all. Please remove it.
> +
> +/**
> + Check if a HOB variable store is available or not.
> +
> + @retval EFI_NOT_READY HOB variable store info not available.
> + @retval EFI_NOT_FOUND HOB variable store is NOT available.
> + @retval EFI_SUCCESS HOB variable store is available.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *PROTECTED_VAR_LIB_HOB_STORE_AVAILABLE)(
> + VOID
> + );
> +
> +typedef enum {
> + FromPeiModule,
> + FromBootServiceModule,
> + FromRuntimeModule,
> + FromSmmModule
> +} VARIABLE_SERVICE_USER;
> +
> +#pragma pack(1)
> +
> +#define PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION 0x02
> +
> +typedef struct _PROTECTED_VARIABLE_CONTEXT_IN {
> + UINT32 StructVersion;
> + UINT32 StructSize;
> + UINT32 MaxVariableSize;
> +
> + VARIABLE_SERVICE_USER VariableServiceUser;
> +
> + PROTECTED_VAR_LIB_FIND_VAR_SMM FindVariableSmm;
> + PROTECTED_VAR_LIB_GET_VAR_INFO GetVariableInfo;
> + PROTECTED_VAR_LIB_GET_NEXT_VAR_INFO GetNextVariableInfo;
> + PROTECTED_VAR_LIB_UPDATE_VARIABLE_STORE UpdateVariableStore;
> + PROTECTED_VAR_LIB_UPDATE_VARIABLE UpdateVariable;
> + PROTECTED_VAR_LIB_HOB_STORE_AVAILABLE
> IsHobVariableStoreAvailable;
> +} PROTECTED_VARIABLE_CONTEXT_IN;
> +
> +#pragma pack()
> +
> +/**
> +
> + Initialization for protected variable services.
> +
> + If this initialization failed upon any error, the whole variable services
> + should not be used. A system reset might be needed to re-construct NV
> + variable storage to be the default state.
> +
> + @param[in] ContextIn Pointer to variable service context needed by
> + protected variable.
> +
> + @retval EFI_SUCCESS Protected variable services are ready.
> + @retval EFI_INVALID_PARAMETER If ContextIn == NULL or something
> missing or
> + mismatching in the content in ContextIn.
> + @retval EFI_COMPROMISED_DATA If failed to check integrity of protected
> variables.
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibInitialize (
> + IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn
> + );
> +
> +/**
> +
> + An alternative version of ProtectedVariableLibGetData to get plain data, if
> + encrypted, from given variable, for different use cases.
> +
> + @param[in,out] VarInfo Pointer to structure containing variable
> information.
> +
> + @retval EFI_SUCCESS Found the specified variable.
> + @retval EFI_INVALID_PARAMETER VarInfo is NULL or both VarInfo-
> >Address and
> + VarInfo->Offset are invalid.
> + @retval EFI_NOT_FOUND The specified variable could not be found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetByInfo (
> + IN OUT PROTECTED_VARIABLE_INFO *VarInfo
> + );
> +
> +/**
> + This service retrieves a variable's value using its name and GUID.
> +
> + Read the specified variable from the UEFI variable store. If the Data
> + buffer is too small to hold the contents of the variable, the error
> + EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
> + size to obtain the data.
> +
> + @param VariableName A pointer to a null-terminated string that is the
> variable's name.
> + @param VariableGuid A pointer to an EFI_GUID that is the variable's
> GUID. The combination of
> + VariableGuid and VariableName must be unique.
> + @param Attributes If non-NULL, on return, points to the variable's
> attributes.
> + @param DataSize On entry, points to the size in bytes of the Data
> buffer.
> + On return, points to the size of the data returned in Data.
> + @param Data Points to the buffer which will hold the returned
> variable value.
> + May be NULL with a zero DataSize in order to determine the
> size of the buffer needed.
> +
> + @retval EFI_SUCCESS The variable was read successfully.
> + @retval EFI_NOT_FOUND The variable was be found.
> + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting
> data.
> + DataSize is updated with the size required for
> + the specified variable.
> + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> Data is NULL.
> + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetByName (
> + IN CONST CHAR16 *VariableName,
> + IN CONST EFI_GUID *VariableGuid,
> + OUT UINT32 *Attributes,
> + IN OUT UINTN *DataSize,
> + OUT VOID *Data OPTIONAL
> + );
[JianJW] The data type of parameters are not aligned.
> +
> +/**
> +
> + Retrieve plain data, if encrypted, of given variable.
> +
> + If variable encryption is employed, this function will initiate a SMM request
> + to get the plain data. Due to security consideration, the decryption can only
> + be done in SMM environment.
> +
> + @param[in] Variable Pointer to header of a Variable.
> + @param[out] Data Pointer to plain data of the given variable.
> + @param[in, out] DataSize Size of data returned or data buffer needed.
> + @param[in] AuthFlag Auth-variable indicator.
> +
> + @retval EFI_SUCCESS Found the specified variable.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_NOT_FOUND The specified variable could not be found.
> + @retval EFI_BUFFER_TOO_SMALL If *DataSize is smaller than needed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetByBuffer (
> + IN VARIABLE_HEADER *Variable,
> + IN OUT VOID *Data,
> + IN OUT UINT32 *DataSize,
> + IN BOOLEAN AuthFlag
> + );
> +
> +/**
> +
> + Prepare for variable update.
> +
> + This is needed only once during current boot to mitigate replay attack. Its
> + major job is to advance RPMC (Replay Protected Monotonic Counter).
> +
> + @retval EFI_SUCCESS Variable is ready to update hereafter.
> + @retval EFI_UNSUPPORTED Updating variable is not supported.
> + @retval EFI_DEVICE_ERROR Error in advancing RPMC.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibWriteInit (
> + VOID
> + );
> +
> +/**
> +
> + Update a variable with protection provided by this library.
> +
> + If variable encryption is employed, the new variable data will be encrypted
> + before being written to NV variable storage.
> +
> + A special variable, called "MetaDataHmacVar", will always be updated along
> + with variable being updated to reflect the changes (HMAC value) of all
> + protected valid variables. The only exceptions, currently, are variable
> + "MetaDataHmacVar" itself and variable "VarErrorLog".
> +
> + The buffer passed by NewVariable must be double of maximum variable size,
> + which allows to pass the "MetaDataHmacVar" back to caller along with
> encrypted
> + new variable data, if any. This can make sure the new variable data and
> + "MetaDataHmacVar" can be written at almost the same time to reduce the
> chance
> + of compromising the integrity.
> +
> + If *NewVariableSize is zero, it means to delete variable passed by CurrVariable
> + and/or CurrVariableInDel. "MetaDataHmacVar" will be updated as well in such
> + case because of less variables in storage. NewVariable should be always
> passed
> + in to convey new "MetaDataHmacVar" back.
> +
> + @param[in,out] CurrVariable Variable to be updated. It's NULL if
> + adding a new variable.
> + @param[in,out] CurrVariableInDel In-delete-transition copy of updating
> variable.
> + @param[in] NewVariable Buffer of new variable data.
> + @param[out] NewVariable Buffer of "MetaDataHmacVar" and new
> + variable (encrypted).
> + @param[in] NewVariableSize Size of NewVariable.
> + @param[out] NewVariableSize Size of (encrypted) NewVariable and
> + "MetaDataHmacVar".
> +
> + @retval EFI_SUCCESS The variable is updated with protection
> successfully.
> + @retval EFI_INVALID_PARAMETER NewVariable is NULL.
> + @retval EFI_NOT_FOUND Information missing to finish the operation.
> + @retval EFI_ABORTED Failed to encrypt variable or calculate HMAC.
> + @retval EFI_NOT_READY The RPMC device is not yet initialized.
> + @retval EFI_DEVICE_ERROR The RPMC device has error in updating.
> + @retval EFI_ACCESS_DENIED The given variable is not allowed to update.
> + Currently this only happens on updating
> + "MetaDataHmacVar" from code outside of this
> + library.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibUpdate (
> + IN OUT VARIABLE_HEADER *CurrVariable OPTIONAL,
> + IN OUT VARIABLE_HEADER *CurrVariableInDel OPTIONAL,
> + IN OUT VARIABLE_HEADER *NewVariable,
> + IN OUT UINTN *NewVariableSize
> + );
> +
> +/**
> +
> + Finalize a variable updating after it's written to NV variable storage
> + successfully.
> +
> + This usually includes works like increasing RPMC, synchronizing local cache,
> + updating new position of "MetaDataHmacVar", deleting old copy of
> "MetaDataHmacVar"
> + completely, etc.
> +
> + @param[in] NewVariable Buffer of new variables and
> MetaDataHmacVar.
> + @param[in] VariableSize Size of buffer pointed by NewVariable.
> + @param[in] Offset Offset to NV variable storage from where the
> new
[JianJW] The "Offset" doesn't match the parameter name (StoreIndex) used in below
> + variable and MetaDataHmacVar have been written.
> +
> + @retval EFI_SUCCESS No problem in winding up the variable write
> operation.
> + @retval Others Failed to updating state of old copy of updated
> + variable, or failed to increase RPMC, etc.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibWriteFinal (
> + IN VARIABLE_HEADER *NewVariable,
> + IN UINTN VariableSize,
> + IN UINT64 StoreIndex
> + );
> +
> +/**
> + Return the request variable name and GUID as per StoreIndex.
> +
> + This function is called multiple times to retrieve the VariableName
> + and VariableGuid of all variables currently available in the system.
> + On each call, the previous results are passed into the interface,
> + and, on return, the interface returns the data for the next
> + interface. When the entire variable list has been returned,
> + EFI_NOT_FOUND is returned.
> +
> + @param This A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +
> + @param VariableNameSize On entry, points to the size of the buffer pointed
> to by VariableName.
> + On return, the size of the variable name buffer.
> + @param VariableName On entry, a pointer to a null-terminated string that
> is the variable's name.
> + On return, points to the next variable's null-terminated name
> string.
> + @param VariableGuid On entry, a pointer to an EFI_GUID that is the
> variable's GUID.
> + On return, a pointer to the next variable's GUID.
[JianJW] The @param list doesn't match the real parameters declared below.
> +
> + @retval EFI_SUCCESS The variable was read successfully.
> + @retval EFI_NOT_FOUND The variable could not be found.
> + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the
> resulting
> + data. VariableNameSize is updated with the size
> + required for the specified variable.
> + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> + VariableNameSize is NULL.
> + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibFind (
> + IN OUT PROTECTED_VARIABLE_INFO *VarInfo
> + );
> +
> +/**
> + Return the next variable name and GUID.
> +
> + This function is called multiple times to retrieve the VariableName
> + and VariableGuid of all variables currently available in the system.
> + On each call, the previous results are passed into the interface,
> + and, on return, the interface returns the data for the next
> + interface. When the entire variable list has been returned,
> + EFI_NOT_FOUND is returned.
> +
> + @param VariableNameSize On entry, points to the size of the buffer pointed
> to by VariableName.
> + On return, the size of the variable name buffer.
> + @param VariableName On entry, a pointer to a null-terminated string that
> is the variable's name.
> + On return, points to the next variable's null-terminated name
> string.
> + @param VariableGuid On entry, a pointer to an EFI_GUID that is the
> variable's GUID.
> + On return, a pointer to the next variable's GUID.
> +
> + @retval EFI_SUCCESS The variable was read successfully.
> + @retval EFI_NOT_FOUND The variable could not be found.
> + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the
> resulting
> + data. VariableNameSize is updated with the size
> + required for the specified variable.
> + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> + VariableNameSize is NULL.
> + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibFindNext (
> + IN OUT UINTN *VariableNameSize,
> + IN OUT CHAR16 *VariableName,
> + IN OUT EFI_GUID *VariableGuid
> + );
> +
> +/**
> + Find variable via information in data structure PROTECTED_VARIABLE_INFO.
> +
> + If VarInfo->StoreIndex is given and valid, always used it to search variable
> + in store. Otherwise, search the variable via variable name and guid pointed
> + by VarInfo->Header.VariableName and VarInfo->Header.VendorGuid.
> +
> + @param VarInfo Pointer to data containing variable information.
> +
> + @return EFI_SUCCESS Found the variable.
> + @return EFI_INVALID_PARAMETER No valid variable information is given.
> + @return EFI_NOT_FOUND The given variable was not found or no more
> + variables available.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibFindNextEx (
> + IN OUT PROTECTED_VARIABLE_INFO *VarInfo
> + );
> +
> +/**
> + Refresh variable information changed by variable service.
> +
> + @param Variable Pointer to buffer of the updated variable.
> + @param VariableSize Size of variable pointed by Variable.
> + @param StoreIndex New index of the variable in store.
> + @param RefreshData Flag to indicate if the variable has been updated.
> +
> + @return EFI_SUCCESS No error occurred in updating.
> + @return EFI_NOT_FOUND The given variable was not found in
> + ProtectedVariableLib.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibRefresh (
> + IN VARIABLE_HEADER *Variable,
> + IN UINTN VariableSize,
> + IN UINT64 StoreIndex,
> + IN BOOLEAN RefreshData
> + );
> +
> +/**
> + Refresh variable information changed by variable service.
[JianJW] This function description looks unmatching the function name.
> +
> + @param Buffer Pointer to a pointer of buffer.
> + @param NumElements Pointer to number of elements in list.
> +
> +
> + @return EFI_SUCCESS Successfully retrieved sorted list.
> + @return others Unsuccessful.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetSortedList (
> + IN OUT EFI_PHYSICAL_ADDRESS **Buffer,
> + IN OUT UINTN *NumElements
> + );
> +
> +/**
> +
> + Determine if the variable is the HMAC variable
> +
> + @param VariableName Pointer to variable name.
> +
> + @return TRUE Variable is HMAC variable
> + @return FALSE Variable is not HMAC variable
> +
> +**/
> +BOOLEAN
> +ProtectedVariableLibIsHmac (
> + IN CHAR16 *VariableName
> + );
> +
> +#endif
> --
> 2.35.1.windows.2
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [Patch v2 05/28] MdeModulePkg: Add new ProtectedVariable GUIDs
2022-04-29 18:04 ` [Patch v2 05/28] MdeModulePkg: Add new ProtectedVariable GUIDs Judah Vang
@ 2022-05-12 9:32 ` Wang, Jian J
0 siblings, 0 replies; 49+ messages in thread
From: Wang, Jian J @ 2022-05-12 9:32 UTC (permalink / raw)
To: Vang, Judah, devel@edk2.groups.io; +Cc: Gao, Liming, Mistry, Nishant C
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
Regards,
Jian
> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Saturday, April 30, 2022 2:04 AM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [Patch v2 05/28] MdeModulePkg: Add new ProtectedVariable GUIDs
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> New ProtectVariable GUIDs for passing variable information
> from PEI phase to SMM phase.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> MdeModulePkg/Include/Guid/ProtectedVariable.h | 22
> ++++++++++++++++++++
> 1 file changed, 22 insertions(+)
>
> diff --git a/MdeModulePkg/Include/Guid/ProtectedVariable.h
> b/MdeModulePkg/Include/Guid/ProtectedVariable.h
> new file mode 100644
> index 000000000000..0c6e19e0456b
> --- /dev/null
> +++ b/MdeModulePkg/Include/Guid/ProtectedVariable.h
> @@ -0,0 +1,22 @@
> +/** @file
> + The GUID definitions specific for protected variable services.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PROTECTED_VARIABLE_H_
> +#define PROTECTED_VARIABLE_H_
> +
> +#define EDKII_PROTECTED_VARIABLE_GLOBAL_GUID \
> + { 0x8ebf379a, 0xf18e, 0x4728, { 0xa4, 0x10, 0x0, 0xcf, 0x9a, 0x65, 0xbe,
> 0x91 } }
> +
> +#define EDKII_METADATA_HMAC_VARIABLE_GUID \
> + { 0xb54cda50, 0xec54, 0x4b20, { 0x85, 0xb4, 0x57, 0xbf, 0x52, 0x98, 0x68,
> 0x3d } }
> +
> +extern EFI_GUID gEdkiiProtectedVariableGlobalGuid;
> +extern EFI_GUID gEdkiiMetaDataHmacVariableGuid;
> +extern EFI_GUID gEdkiiProtectedVariableContextGuid;
> +
> +#endif // __PROTECTED_VARIABLE_H__
> --
> 2.35.1.windows.2
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [Patch v2 04/28] MdeModulePkg: Add reference to new Ppi Guid
2022-04-29 18:04 ` [Patch v2 04/28] MdeModulePkg: Add reference to new Ppi Guid Judah Vang
@ 2022-05-12 9:32 ` Wang, Jian J
0 siblings, 0 replies; 49+ messages in thread
From: Wang, Jian J @ 2022-05-12 9:32 UTC (permalink / raw)
To: Vang, Judah, devel@edk2.groups.io; +Cc: Gao, Liming, Mistry, Nishant C
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
Regards,
Jian
> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Saturday, April 30, 2022 2:04 AM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [Patch v2 04/28] MdeModulePkg: Add reference to new Ppi Guid
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> Add reference to gEfiPeiVariableStoreDiscoveredPpiGuid which
> contains information whether variable store is available.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> MdePkg/Include/Ppi/ReadOnlyVariable2.h | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/MdePkg/Include/Ppi/ReadOnlyVariable2.h
> b/MdePkg/Include/Ppi/ReadOnlyVariable2.h
> index 926c0bc82a43..c5a8470565bb 100644
> --- a/MdePkg/Include/Ppi/ReadOnlyVariable2.h
> +++ b/MdePkg/Include/Ppi/ReadOnlyVariable2.h
> @@ -2,7 +2,7 @@
> This file declares Read-only Variable Service2 PPI.
> This ppi permits read-only access to the UEFI variable store during the PEI
> phase.
>
> -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> @par Revision Reference:
> @@ -106,4 +106,6 @@ struct _EFI_PEI_READ_ONLY_VARIABLE2_PPI {
>
> extern EFI_GUID gEfiPeiReadOnlyVariable2PpiGuid;
>
> +extern EFI_GUID gEfiPeiVariableStoreDiscoveredPpiGuid;
> +
> #endif
> --
> 2.35.1.windows.2
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [Patch v2 01/28] MdeModulePkg: Add new GUID for Variable Store Info
2022-04-29 18:04 ` [Patch v2 01/28] MdeModulePkg: Add new GUID for Variable Store Info Judah Vang
@ 2022-05-12 9:32 ` Wang, Jian J
0 siblings, 0 replies; 49+ messages in thread
From: Wang, Jian J @ 2022-05-12 9:32 UTC (permalink / raw)
To: Vang, Judah, devel@edk2.groups.io; +Cc: Gao, Liming, Mistry, Nishant C
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
Regards,
Jian
> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Saturday, April 30, 2022 2:04 AM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [Patch v2 01/28] MdeModulePkg: Add new GUID for Variable Store Info
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> Discover if Variable Store Info HOB has been published
> by platform driver. It contains information in regards
> to HOB or NV Variable Store availability
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> MdeModulePkg/MdeModulePkg.dec | 13 ++++++++++++-
> 1 file changed, 12 insertions(+), 1 deletion(-)
>
> diff --git a/MdeModulePkg/MdeModulePkg.dec
> b/MdeModulePkg/MdeModulePkg.dec
> index cf79292ec877..f39827e4eacd 100644
> --- a/MdeModulePkg/MdeModulePkg.dec
> +++ b/MdeModulePkg/MdeModulePkg.dec
> @@ -4,7 +4,7 @@
> # and libraries instances, which are used for those modules.
> #
> # Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
> -# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2007 - 2022, Intel Corporation. All rights reserved.<BR>
> # Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
> # (C) Copyright 2016 - 2019 Hewlett Packard Enterprise Development LP<BR>
> # Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> @@ -93,6 +93,14 @@ [LibraryClasses]
> #
> TpmMeasurementLib|Include/Library/TpmMeasurementLib.h
>
> + ## @libraryclass Provides interfaces to encrypt/decrypt variable.
> + #
> + EncryptionVariableLib|Include/Library/EncryptionVariableLib.h
> +
> + ## @libraryclass Provides interfaces to encrypt/decrypt variable.
> + #
> + ProtectedVariableLib|Include/Library/ProtectedVariableLib.h
> +
> ## @libraryclass Provides authenticated variable services.
> #
> AuthVariableLib|Include/Library/AuthVariableLib.h
> @@ -505,6 +513,9 @@ [Ppis]
> gEdkiiPeiCapsuleOnDiskPpiGuid = { 0x71a9ea61, 0x5a35, 0x4a5d, { 0xac,
> 0xef, 0x9c, 0xf8, 0x6d, 0x6d, 0x67, 0xe0 } }
> gEdkiiPeiBootInCapsuleOnDiskModePpiGuid = { 0xb08a11e4, 0xe2b7, 0x4b75,
> { 0xb5, 0x15, 0xaf, 0x61, 0x6, 0x68, 0xbf, 0xd1 } }
>
> + ## Include/Ppi/ReadOnlyVariable2.h
> + gEfiPeiVariableStoreDiscoveredPpiGuid = { 0xa2fc038d, 0xfdf5, 0x4501,
> { 0xaf, 0x8e, 0x69, 0xb0, 0x20, 0xec, 0xe6, 0x63 } }
> +
> [Protocols]
> ## Load File protocol provides capability to load and unload EFI image into
> memory and execute it.
> # Include/Protocol/LoadPe32Image.h
> --
> 2.35.1.windows.2
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [Patch v2 03/28] MdeModulePkg: Update AUTH_VARIABLE_INFO struct
2022-04-29 18:04 ` [Patch v2 03/28] MdeModulePkg: Update AUTH_VARIABLE_INFO struct Judah Vang
@ 2022-05-12 9:33 ` Wang, Jian J
0 siblings, 0 replies; 49+ messages in thread
From: Wang, Jian J @ 2022-05-12 9:33 UTC (permalink / raw)
To: Vang, Judah, devel@edk2.groups.io; +Cc: Gao, Liming, Mistry, Nishant C
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
Regards,
Jian
> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Saturday, April 30, 2022 2:04 AM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [Patch v2 03/28] MdeModulePkg: Update AUTH_VARIABLE_INFO struct
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> Added NameSize and State to AUTH_VARIABLE_INFO struct.
> The size of the name and state is needed when creating
> the variable digest.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> MdeModulePkg/Include/Library/AuthVariableLib.h | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/MdeModulePkg/Include/Library/AuthVariableLib.h
> b/MdeModulePkg/Include/Library/AuthVariableLib.h
> index 37aceba699e6..32391bbf2b61 100644
> --- a/MdeModulePkg/Include/Library/AuthVariableLib.h
> +++ b/MdeModulePkg/Include/Library/AuthVariableLib.h
> @@ -1,7 +1,7 @@
> /** @file
> Provides services to initialize and process authenticated variables.
>
> -Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> **/
> @@ -25,9 +25,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)))
>
> typedef struct {
> + UINTN NameSize;
> CHAR16 *VariableName;
> EFI_GUID *VendorGuid;
> UINT32 Attributes;
> + UINT8 State;
> UINTN DataSize;
> VOID *Data;
> UINT32 PubKeyIndex;
> --
> 2.35.1.windows.2
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [Patch v2 02/28] SecurityPkg: Add new GUIDs for
2022-04-29 18:04 ` [Patch v2 02/28] SecurityPkg: Add new GUIDs for Judah Vang
@ 2022-05-12 9:33 ` Wang, Jian J
0 siblings, 0 replies; 49+ messages in thread
From: Wang, Jian J @ 2022-05-12 9:33 UTC (permalink / raw)
To: Vang, Judah, devel@edk2.groups.io; +Cc: Yao, Jiewen, Mistry, Nishant C
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
Regards,
Jian
> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Saturday, April 30, 2022 2:04 AM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [Patch v2 02/28] SecurityPkg: Add new GUIDs for
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> The gEdkiiProtectedVariableGlobalGuid HOB contains the global
> configuration data structure which is verified in PEI Phase.
> The gEdkiiMetaDataHmacVariableGuid is used for saving the
> meta data HMAC variable.
> The gEdkiiProtectedVariableContextGuid contains the Protected
> Variable context saved in PEI phase to be used later.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> SecurityPkg/SecurityPkg.dec | 43 +++++++++++++++++++-
> 1 file changed, 42 insertions(+), 1 deletion(-)
>
> diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec
> index 9f7a032d60d5..ea88908ea7d2 100644
> --- a/SecurityPkg/SecurityPkg.dec
> +++ b/SecurityPkg/SecurityPkg.dec
> @@ -5,7 +5,7 @@
> # It also provides the definitions(including PPIs/PROTOCOLs/GUIDs and library
> classes)
> # and libraries instances, which are used for those features.
> #
> -# Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2009 - 2022, Intel Corporation. All rights reserved.<BR>
> # (C) Copyright 2015 Hewlett Packard Enterprise Development LP <BR>
> # Copyright (c) Microsoft Corporation.<BR>
> # SPDX-License-Identifier: BSD-2-Clause-Patent
> @@ -217,6 +217,18 @@ [Guids]
> ## GUID used to specify section with default dbt content
> gDefaultdbtFileGuid = { 0x36c513ee, 0xa338, 0x4976, { 0xa0, 0xfb,
> 0x6d, 0xdb, 0xa3, 0xda, 0xfe, 0x87 } }
>
> + ## Include/Guid/ProtectedVariable.h
> + # {8EBF379A-F18E-4728-A410-00CF9A65BE91}
> + gEdkiiProtectedVariableGlobalGuid = { 0x8ebf379a, 0xf18e, 0x4728, { 0xa4,
> 0x10, 0x0, 0xcf, 0x9a, 0x65, 0xbe, 0x91 } }
> +
> + ## Include/Guid/ProtectedVariable.h
> + # {e3e890ad-5b67-466e-904f-94ca7e9376bb}
> + gEdkiiMetaDataHmacVariableGuid = {0xe3e890ad, 0x5b67, 0x466e, {0x90,
> 0x4f, 0x94, 0xca, 0x7e, 0x93, 0x76, 0xbb}}
> +
> + ## Include/Guid/ProtectedVariable.h
> + # {a11a3652-875b-495a-b097-200917580b98}
> + gEdkiiProtectedVariableContextGuid = {0xa11a3652, 0x875b, 0x495a, {0xb0,
> 0x97, 0x20, 0x09, 0x17, 0x58, 0x0b, 0x98} }
> +
> [Ppis]
> ## The PPI GUID for that TPM physical presence should be locked.
> # Include/Ppi/LockPhysicalPresence.h
> @@ -242,6 +254,10 @@ [Ppis]
> ## Include/Ppi/Tcg.h
> gEdkiiTcgPpiGuid = {0x57a13b87, 0x133d, 0x4bf3, { 0xbf, 0xf1, 0x1b, 0xca,
> 0xc7, 0x17, 0x6c, 0xf1 } }
>
> + ## Key Service Ppi
> + # Include/Ppi/KeyServicePpi.h
> + gKeyServicePpiGuid = {0x583592f6, 0xEC34, 0x4CED, {0x8E, 0x81, 0xC8, 0xD1,
> 0x36, 0x93, 0x04, 0x27}}
> +
> #
> # [Error.gEfiSecurityPkgTokenSpaceGuid]
> # 0x80000001 | Invalid value provided.
> @@ -325,6 +341,31 @@ [PcdsFixedAtBuild, PcdsPatchableInModule]
>
>
> gEfiSecurityPkgTokenSpaceGuid.PcdCpuRngSupportedAlgorithm|{0x00,0x00,0x0
> 0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}|VOID
> *|0x00010032
>
> + ## Progress Code for variable integrity check result.<BR><BR>
> + # DEFAULT: (EFI_PERIPHERAL_FIXED_MEDIA | [EFI_STATUS&0xFF])
> + # @Prompt Status Code for variable integiry check result
> +
> gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeVariableIntegrity|0x01070000|U
> INT32|0x00010033
> +
> + ## Null-terminated Unicode string of the Platform Variable Name
> + # @Prompt known unprotected variable name
> +
> gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName|L""|VOID*|0x00010
> 034
> +
> + ## Guid name to identify Platform Variable Guid
> + # @Prompt known unprotected variable guid
> + gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid|{ 0x00, 0x00, 0x00,
> 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> 0x00 }|VOID*|0x00010035
> +
> + ## Defines Protected Variable Integrity support.
> + # TRUE - Enable Protected Variable Integrity.<BR>
> + # FALSE - Disable Protected Variable Integrity.<BR>
> + # @Prompt Protected Variable Integrity support.
> +
> gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity|FALSE|BOOLEA
> N|0x00010036
> +
> + ## Defines Protected Variable Confidentiality support.
> + # TRUE - Enable Protected Variable Confidentiality.<BR>
> + # FALSE - Disable Protected Variable Confidentiality.<BR>
> + # @Prompt Protected Variable Integrity support.
> +
> gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality|FALSE|BO
> OLEAN|0x00010037
> +
> [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
> ## Image verification policy for OptionRom. Only following values are
> valid:<BR><BR>
> # NOTE: Do NOT use 0x5 and 0x2 since it violates the UEFI specification and
> has been removed.<BR>
> --
> 2.35.1.windows.2
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [edk2-devel] [Patch v2 00/28] UEFI variable protection
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
` (27 preceding siblings ...)
2022-04-29 18:04 ` [Patch v2 28/28] CryptoPkg: Enable cypto HMAC KDF library Judah Vang
@ 2022-05-17 2:48 ` Michael Kubacki
[not found] ` <16EFC4965F71DFB8.20068@groups.io>
29 siblings, 0 replies; 49+ messages in thread
From: Michael Kubacki @ 2022-05-17 2:48 UTC (permalink / raw)
To: devel, judah.vang
Hi Judah,
Do you have reference information for the following?
1. Overall boot time impact for a sample variable store?
- In particular:
- Initial HMAC calculation/verification time.
- Non-volatile write impact time to caluclate new store HMAC value
and update MetaDataHmacVar.
- Variable reclaim before and after time.
2. Overall non-volatile store size overhead impact with AES-CBC
encrypted variables?
I understand these will vary based on system properties like SPI flash
parameters, cryptographic processor details, etc. I'm trying to get an
idea of the impact from sample data or averages on a particular system
configuration. Also to learn whether the native encryption instruction
(AES-NI) was used and if that could provide any benefit given the
potential number of encryption/decryption operations introduced.
For the code design, I feel the ProtectedVariableLib interface is a bit
too coupled against internal implementation details of the variable
driver. I generally understand why the code is split out to wrap
operations around the new functionality and it follows the AuthVarLib
pattern but changing the library or driver will continue to require
large changes across both like this due to the coupling.
Small things I noticed:
1. VariableKeyLib.inf should not be "BASE", it directly depends on PEI
services
2. Typo "varabile" in some files
3. Does ProtectedVariableLibNull actually need to depend on BaseMemoryLib?
Thanks,
Michael
On 4/29/2022 2:04 PM, Judah Vang wrote:
> For a more detail description of the UEFI variable protected feature you can
> view the Readme.md located at the following location:
> https://github.com/judahvang/edk2/tree/rpmc-update
>
>
> Judah Vang (28):
> MdeModulePkg: Add new GUID for Variable Store Info
> SecurityPkg: Add new GUIDs for
> MdeModulePkg: Update AUTH_VARIABLE_INFO struct
> MdeModulePkg: Add reference to new Ppi Guid
> MdeModulePkg: Add new ProtectedVariable GUIDs
> MdeModulePkg: Add new include files
> MdeModulePkg: Add Null ProtectedVariable Library
> MdeModulePkg: Add new Variable functionality
> MdeModulePkg: Add support for Protected Variables
> SecurityPkg: Add new KeyService types and defines
> SecurityPkg: Update RPMC APIs with index
> SecurityPkg: Add new variable types and functions
> SecurityPkg: Fix GetVariableKey API
> SecurityPkg: Add null encryption variable libs
> SecurityPkg: Add VariableKey library function
> SecurityPkg: Add EncryptionVariable lib with AES
> SecurityPkg: Add Protected Variable Services
> MdeModulePkg: Reference Null ProtectedVariableLib
> SecurityPkg: Add references to new *.inf files
> ArmVirtPkg: Add reference to ProtectedVariableNull
> UefiPayloadPkg: Add ProtectedVariable reference
> EmulatorPkg: Add ProtectedVariable reference
> OvmfPkg: Add ProtectedVariable reference
> OvmfPkg: Add ProtectedVariableLib reference
> OvmfPkg: Add ProtectedVariableLib reference
> OvmfPkg: Add ProtectedVariableLib reference
> OvmfPkg: Add ProtectedVariable reference
> CryptoPkg: Enable cypto HMAC KDF library
>
> MdeModulePkg/MdeModulePkg.dec | 13 +-
> SecurityPkg/SecurityPkg.dec | 43 +-
> ArmVirtPkg/ArmVirtQemu.dsc | 3 +-
> EmulatorPkg/EmulatorPkg.dsc | 3 +-
> MdeModulePkg/MdeModulePkg.dsc | 4 +-
> OvmfPkg/AmdSev/AmdSevX64.dsc | 3 +-
> OvmfPkg/Bhyve/BhyveX64.dsc | 3 +-
> OvmfPkg/CloudHv/CloudHvX64.dsc | 1 +
> OvmfPkg/Microvm/MicrovmX64.dsc | 3 +-
> OvmfPkg/OvmfPkgIa32.dsc | 1 +
> OvmfPkg/OvmfPkgIa32X64.dsc | 1 +
> OvmfPkg/OvmfPkgX64.dsc | 1 +
> OvmfPkg/OvmfXen.dsc | 3 +-
> SecurityPkg/SecurityPkg.dsc | 13 +-
> UefiPayloadPkg/UefiPayloadPkg.dsc | 2 +
> CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf | 2 +-
> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf | 34 +
> MdeModulePkg/Universal/Variable/Pei/VariablePei.inf | 10 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf | 3 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf | 3 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf | 4 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf | 3 +-
> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf | 43 +
> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf | 38 +
> SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf | 64 +
> SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf | 68 +
> SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf | 67 +
> SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf | 62 +
> SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf | 36 +
> MdeModulePkg/Include/Guid/ProtectedVariable.h | 22 +
> MdeModulePkg/Include/Library/AuthVariableLib.h | 4 +-
> MdeModulePkg/Include/Library/EncryptionVariableLib.h | 165 ++
> MdeModulePkg/Include/Library/ProtectedVariableLib.h | 700 +++++++
> MdeModulePkg/Universal/Variable/Pei/Variable.h | 80 +-
> MdeModulePkg/Universal/Variable/Pei/VariableParsing.h | 309 +++
> MdeModulePkg/Universal/Variable/Pei/VariableStore.h | 116 ++
> MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h | 126 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h | 91 +-
> MdePkg/Include/Ppi/ReadOnlyVariable2.h | 4 +-
> SecurityPkg/Include/Library/RpmcLib.h | 15 +-
> SecurityPkg/Include/Library/VariableKeyLib.h | 37 +-
> SecurityPkg/Include/Ppi/KeyServicePpi.h | 57 +
> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h | 49 +
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h | 611 ++++++
> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c | 449 ++++
> MdeModulePkg/Universal/Variable/Pei/Variable.c | 886 ++------
> MdeModulePkg/Universal/Variable/Pei/VariableParsing.c | 941 +++++++++
> MdeModulePkg/Universal/Variable/Pei/VariableStore.c | 305 +++
> MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c | 349 +++-
> MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c | 2139 +++++++++++---------
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c | 26 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c | 167 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c | 194 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c | 320 ++-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c | 2 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c | 39 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c | 41 +-
> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c | 728 +++++++
> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c | 107 +
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c | 2095 +++++++++++++++++++
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c | 163 ++
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c | 1331 ++++++++++++
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c | 209 ++
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c | 975 +++++++++
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c | 233 +++
> SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c | 8 +-
> SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c | 59 +
> SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c | 6 +-
> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni | 16 +
> 69 files changed, 12845 insertions(+), 1863 deletions(-)
> create mode 100644 MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
> create mode 100644 SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
> create mode 100644 SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
> create mode 100644 SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
> create mode 100644 SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
> create mode 100644 SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
> create mode 100644 SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf
> create mode 100644 SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
> create mode 100644 MdeModulePkg/Include/Guid/ProtectedVariable.h
> create mode 100644 MdeModulePkg/Include/Library/EncryptionVariableLib.h
> create mode 100644 MdeModulePkg/Include/Library/ProtectedVariableLib.h
> create mode 100644 MdeModulePkg/Universal/Variable/Pei/VariableParsing.h
> create mode 100644 MdeModulePkg/Universal/Variable/Pei/VariableStore.h
> create mode 100644 SecurityPkg/Include/Ppi/KeyServicePpi.h
> create mode 100644 SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
> create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
> create mode 100644 MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
> create mode 100644 MdeModulePkg/Universal/Variable/Pei/VariableParsing.c
> create mode 100644 MdeModulePkg/Universal/Variable/Pei/VariableStore.c
> create mode 100644 SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
> create mode 100644 SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
> create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
> create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
> create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
> create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
> create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c
> create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
> create mode 100644 SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c
> create mode 100644 SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni
>
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [Patch v2 07/28] MdeModulePkg: Add Null ProtectedVariable Library
2022-04-29 18:04 ` [Patch v2 07/28] MdeModulePkg: Add Null ProtectedVariable Library Judah Vang
@ 2022-05-22 8:38 ` Wang, Jian J
0 siblings, 0 replies; 49+ messages in thread
From: Wang, Jian J @ 2022-05-22 8:38 UTC (permalink / raw)
To: Vang, Judah, devel@edk2.groups.io; +Cc: Gao, Liming, Mistry, Nishant C
Judah,
Following interface has no non-Null version implemented.
Consider removing them completely.
ProtectedVariableLibGetStore()
ProtectedVariableLibReclaim()
ProtectedVariableLibGetDataInfo()
ProtectedVariableLibGetNextEx()
ProtectedVariableLibGetNext ()
Regards,
Jian
> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Saturday, April 30, 2022 2:04 AM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [Patch v2 07/28] MdeModulePkg: Add Null ProtectedVariable Library
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> Add Null versions of the ProtectedVariable Library.
> This will be the default libraries for platforms that
> do not support ProtectedVariable.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
> | 34 ++
> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c |
> 449 ++++++++++++++++++++
> 2 files changed, 483 insertions(+)
>
> diff --git
> a/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.in
> f
> b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.in
> f
> new file mode 100644
> index 000000000000..6a17191c4e1e
> --- /dev/null
> +++
> b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.in
> f
> @@ -0,0 +1,34 @@
> +## @file
> +# Provides null version of protected variable services.
> +#
> +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010029
> + BASE_NAME = ProtectedVariableLibNull
> + FILE_GUID = 352C6A1B-403A-4E37-8517-FAA50BC45251
> + MODULE_TYPE = BASE
> + VERSION_STRING = 0.1
> + LIBRARY_CLASS = ProtectedVariableLib
> +
> +#
> +# The following information is for reference only and not required by the build
> tools.
> +#
> +# VALID_ARCHITECTURES = IA32 X64
> +#
> +
> +[Sources]
> + ProtectedVariable.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> +
> +[LibraryClasses]
> + BaseLib
> + BaseMemoryLib
> + DebugLib
> +
> diff --git
> a/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
> b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
> new file mode 100644
> index 000000000000..cc1e16c1a671
> --- /dev/null
> +++ b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
> @@ -0,0 +1,449 @@
> +/** @file
> + NULL version of ProtectedVariableLib used to disable protected variable
> services.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiDxe.h>
> +#include <Uefi.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/ProtectedVariableLib.h>
> +
> +/**
> +
> + Initialization for protected varibale services.
> +
> + @param[in] ContextIn Pointer to variable service context needed by
> + protected variable.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibInitialize (
> + IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Get a verified copy of NV variable storage.
> +
> + @param[out] VariableFvHeader Pointer to the header of whole NV
> firmware volume.
> + @param[out] VariableStoreHeader Pointer to the header of variable
> storage.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetStore (
> + OUT EFI_FIRMWARE_VOLUME_HEADER **VariableFvHeader,
> + OUT VARIABLE_STORE_HEADER **VariableStoreHeader
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Prepare for variable update.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibWriteInit (
> + VOID
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Update a variable with protection provided by this library.
> +
> + @param[in,out] CurrVariable Variable to be updated. It's NULL if
> + adding a new variable.
> + @param[in] CurrVariableInDel In-delete-transiion copy of updating
> variable.
> + @param[in,out] NewVariable Buffer of new variable data.
> + Buffer of "MetaDataHmacVar" and new
> + variable (encrypted).
> + @param[in,out] NewVariableSize Size of NewVariable.
> + Size of (encrypted) NewVariable and
> + "MetaDataHmacVar".
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibUpdate (
> + IN OUT VARIABLE_HEADER *CurrVariable,
> + IN VARIABLE_HEADER *CurrVariableInDel,
> + IN OUT VARIABLE_HEADER *NewVariable,
> + IN OUT UINTN *NewVariableSize
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Finalize a variable updating after it's written to NV variable storage
> + successfully.
> +
> + @param[in] NewVariable Buffer of new variables and
> MetaDataHmacVar.
> + @param[in] VariableSize Size of buffer pointed by NewVariable.
> + @param[in] StoreIndex New index of the variable in store.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibWriteFinal (
> + IN VARIABLE_HEADER *NewVariable,
> + IN UINTN VariableSize,
> + IN UINT64 StoreIndex
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Perform garbage collection against the cached copy of NV variable storage.
> +
> + @param[in] VariableStoreBuffer Buffer used to do the reclaim.
> + @param[out] LastVariableOffset New free space start point.
> + @param[in] CurrVariableOffset Offset of existing variable.
> + @param[in] CurrVariableInDelOffset Offset of old copy of existing
> variable.
> + @param[in,out] NewVariable Buffer of new variable data.
> + @param[in] NewVariableSize Size of new variable data.
> + @param[in,out] HwErrVariableTotalSize Total size of variables with HR
> attribute.
> + @param[in,out] CommonVariableTotalSize Total size of common variables.
> + @param[in,out] CommonUserVariableTotalSize Total size of user variables.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibReclaim (
> + IN VARIABLE_STORE_HEADER *VariableStoreBuffer,
> + OUT UINTN *LastVariableOffset,
> + IN UINTN CurrVariableOffset,
> + IN UINTN CurrVariableInDelOffset,
> + IN OUT VARIABLE_HEADER **NewVariable,
> + IN UINTN NewVariableSize,
> + IN OUT UINTN *HwErrVariableTotalSize,
> + IN OUT UINTN *CommonVariableTotalSize,
> + IN OUT UINTN *CommonUserVariableTotalSize
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + An alternative version of ProtectedVariableLibGetData to get plain data, if
> + encrypted, from given variable, for different use cases.
> +
> + @param[in,out] VarInfo Pointer to structure containing variable
> information.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetDataInfo (
> + IN OUT PROTECTED_VARIABLE_INFO *VarInfo
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Retrieve plain data, if encrypted, of given variable.
> +
> + @param[in] Variable Pointer to header of a Variable.
> + @param[in,out] Data Pointer to plain data of the given variable.
> + @param[in,out] DataSize Size of data returned or data buffer needed.
> + @param[in] AuthFlag Auth-variable indicator.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetData (
> + IN VARIABLE_HEADER *Variable,
> + IN OUT VOID *Data,
> + IN OUT UINT32 *DataSize,
> + IN BOOLEAN AuthFlag
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Retrieve next protected variable stub.
> +
> + @param[in,out] VarInfo Pointer to structure containing variable
> information.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetNextEx (
> + IN OUT PROTECTED_VARIABLE_INFO *VarInfo
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Retrieve next protected variable.
> +
> + @param[in,out] VariableNameSize Pointer to size of variable name.
> + @param[in,out] VariableName Pointer to variable name.
> + @param[in,out] VariableGuid Pointer to vairable GUID.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetNext (
> + IN OUT UINTN *VariableNameSize,
> + IN OUT CHAR16 *VariableName,
> + IN OUT EFI_GUID *VariableGuid
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Get the specified protected variable.
> +
> + @param[in] VariableName Pointer to variable name.
> + @param[in] VariableGuid Pointer to vairable GUID.
> + @param[out] Attributes Pointer to attributes.
> + @param[in,out] DataSize Pointer to data size.
> + @param[out] Data Pointer to data.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGet (
> + IN CONST CHAR16 *VariableName,
> + IN CONST EFI_GUID *VariableGuid,
> + OUT UINT32 *Attributes,
> + IN OUT UINTN *DataSize,
> + OUT VOID *Data OPTIONAL
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Find the protected variable.
> +
> + @param[in,out] VarInfo Pointer to structure containing variable
> information.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibFind (
> + IN OUT PROTECTED_VARIABLE_INFO *VarInfo
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Find next protected variable.
> +
> + @param[in,out] VariableNameSize Pointer to size of variable name.
> + @param[in,out] VariableName Pointer to variable name.
> + @param[in,out] VariableGuid Pointer to vairable GUID.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibFindNext (
> + IN OUT UINTN *VariableNameSize,
> + IN OUT CHAR16 *VariableName,
> + IN OUT EFI_GUID *VariableGuid
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Find next protected variable stub.
> +
> + @param[in,out] VarInfo Pointer to structure containing variable
> information.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibFindNextEx (
> + IN OUT PROTECTED_VARIABLE_INFO *VarInfo
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Get protected variable by information.
> +
> + @param[in,out] VarInfo Pointer to structure containing variable
> information.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetByInfo (
> + IN OUT PROTECTED_VARIABLE_INFO *VarInfo
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Get protected variable by name.
> +
> + @param[in] VariableName Pointer to variable name.
> + @param[in] VariableGuid Pointer to vairable GUID.
> + @param[out] Attributes Pointer to attributes.
> + @param[in,out] DataSize Pointer to data size.
> + @param[out] Data Pointer to data.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetByName (
> + IN CONST CHAR16 *VariableName,
> + IN CONST EFI_GUID *VariableGuid,
> + OUT UINT32 *Attributes,
> + IN OUT UINTN *DataSize,
> + OUT VOID *Data OPTIONAL
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Get protected variable by name.
> +
> + @param[in] Variable Pointer to variable name.
> + @param[in,out] Data Pointer to variable data.
> + @param[in,out] DataSize Pointer to data size.
> + @param[in] AuthFlag Authenticate flag.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetByBuffer (
> + IN VARIABLE_HEADER *Variable,
> + IN OUT VOID *Data,
> + IN OUT UINT32 *DataSize,
> + IN BOOLEAN AuthFlag
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> + Refresh variable information changed by variable service.
> +
> + @param[in] Variable Pointer to buffer of the updated variable.
> + @param[in] VariableSize Size of variable pointed by Variable.
> + @param[in] StoreIndex New index of the variable in store.
> + @param[in] RefreshData Flag to indicate if the variable has been updated.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibRefresh (
> + IN VARIABLE_HEADER *Variable,
> + IN UINTN VariableSize,
> + IN UINT64 StoreIndex,
> + IN BOOLEAN RefreshData
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Get sorted protected variable list.
> +
> + @param[in,out] Buffer Pointer to buffer.
> + @param[in,out] NumElements Pointer to number of elements.
> +
> + @retval EFI_UNSUPPORTED Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetSortedList (
> + IN OUT EFI_PHYSICAL_ADDRESS **Buffer,
> + IN OUT UINTN *NumElements
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> + Determine if the variable is the HMAC variable.
> +
> + @param[in] VariableName Pointer to variable name.
> +
> + @return FALSE Variable is not HMAC variable
> +
> +**/
> +BOOLEAN
> +ProtectedVariableLibIsHmac (
> + IN CHAR16 *VariableName
> + )
> +{
> + return FALSE;
> +}
> --
> 2.35.1.windows.2
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [Patch v2 08/28] MdeModulePkg: Add new Variable functionality
2022-04-29 18:04 ` [Patch v2 08/28] MdeModulePkg: Add new Variable functionality Judah Vang
@ 2022-05-22 10:24 ` Wang, Jian J
0 siblings, 0 replies; 49+ messages in thread
From: Wang, Jian J @ 2022-05-22 10:24 UTC (permalink / raw)
To: Vang, Judah, devel@edk2.groups.io; +Cc: Gao, Liming, Mistry, Nishant C
Judah,
One general comment: please add variable store provision/recovery flow and
explanations in the readme.
See my other inline comments below.
Regards,
Jian
> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Saturday, April 30, 2022 2:04 AM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [Patch v2 08/28] MdeModulePkg: Add new Variable functionality
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> Provide new APIs for retrieving variable information.
> Add new function stubs for retrieving Protected
> variable information.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> MdeModulePkg/Universal/Variable/Pei/VariablePei.inf | 10 +-
> MdeModulePkg/Universal/Variable/Pei/Variable.h | 80 +-
> MdeModulePkg/Universal/Variable/Pei/VariableParsing.h | 309 +++++++
> MdeModulePkg/Universal/Variable/Pei/VariableStore.h | 116 +++
> MdeModulePkg/Universal/Variable/Pei/Variable.c | 886 +++---------------
> MdeModulePkg/Universal/Variable/Pei/VariableParsing.c | 941
> ++++++++++++++++++++
> MdeModulePkg/Universal/Variable/Pei/VariableStore.c | 305 +++++++
> 7 files changed, 1891 insertions(+), 756 deletions(-)
>
> diff --git a/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
> b/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
> index 7cbdd2385e8f..af172126a011 100644
> --- a/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
> +++ b/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
> @@ -3,7 +3,7 @@
> #
> # This module implements ReadOnly Variable Services required by PEIM and
> installs PEI ReadOnly Varaiable2 PPI.
> #
> -# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> # SPDX-License-Identifier: BSD-2-Clause-Patent
> #
> ##
> @@ -26,6 +26,10 @@ [Defines]
> [Sources]
> Variable.c
> Variable.h
> + VariableStore.c
> + VariableStore.h
> + VariableParsing.c
> + VariableParsing.h
>
> [Packages]
> MdePkg/MdePkg.dec
> @@ -39,6 +43,7 @@ [LibraryClasses]
> DebugLib
> PeiServicesTablePointerLib
> PeiServicesLib
> + ProtectedVariableLib
>
> [Guids]
> ## CONSUMES ## GUID # Variable store header
> @@ -56,7 +61,8 @@ [Guids]
> gEdkiiFaultTolerantWriteGuid
>
> [Ppis]
> - gEfiPeiReadOnlyVariable2PpiGuid ## PRODUCES
> + gEfiPeiReadOnlyVariable2PpiGuid ## PRODUCES
> + gEfiPeiVariableStoreDiscoveredPpiGuid ## CONSUMES
>
> [Pcd]
> gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ##
> SOMETIMES_CONSUMES
> diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.h
> b/MdeModulePkg/Universal/Variable/Pei/Variable.h
> index 7f9ad5bfc357..115426edd626 100644
> --- a/MdeModulePkg/Universal/Variable/Pei/Variable.h
> +++ b/MdeModulePkg/Universal/Variable/Pei/Variable.h
> @@ -2,7 +2,7 @@
> The internal header file includes the common header files, defines
> internal structure and functions used by PeiVariable module.
>
> -Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> **/
> @@ -20,11 +20,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> #include <Library/BaseMemoryLib.h>
> #include <Library/PeiServicesTablePointerLib.h>
> #include <Library/PeiServicesLib.h>
> +#include <Library/ProtectedVariableLib.h>
>
> #include <Guid/VariableFormat.h>
> #include <Guid/VariableIndexTable.h>
> #include <Guid/SystemNvDataGuid.h>
> #include <Guid/FaultTolerantWrite.h>
> +#include <Guid/ProtectedVariable.h>
>
> typedef enum {
> VariableStoreTypeHob,
> @@ -142,4 +144,80 @@ PeiGetNextVariableName (
> IN OUT EFI_GUID *VariableGuid
> );
>
> +/**
> + This service retrieves a variable's value using its name and GUID.
> +
> + Read the specified variable from the UEFI variable store. If the Data
> + buffer is too small to hold the contents of the variable, the error
> + EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
> + size to obtain the data.
> +
> + @param This A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> + @param VariableName A pointer to a null-terminated string that is the
> variable's name.
> + @param VariableGuid A pointer to an EFI_GUID that is the variable's
> GUID. The combination of
> + VariableGuid and VariableName must be unique.
> + @param Attributes If non-NULL, on return, points to the variable's
> attributes.
> + @param DataSize On entry, points to the size in bytes of the Data
> buffer.
> + On return, points to the size of the data returned in Data.
> + @param Data Points to the buffer which will hold the returned
> variable value.
> + May be NULL with a zero DataSize in order to determine the
> size of the buffer needed.
> +
> + @retval EFI_SUCCESS The variable was read successfully.
> + @retval EFI_NOT_FOUND The variable was not found.
> + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting
> data.
> + DataSize is updated with the size required for
> + the specified variable.
> + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> Data is NULL.
> + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetVariableEx (
> + IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
> + IN CONST CHAR16 *VariableName,
> + IN CONST EFI_GUID *VariableGuid,
> + OUT UINT32 *Attributes,
> + IN OUT UINTN *DataSize,
> + OUT VOID *Data OPTIONAL
> + );
> +
> +/**
> + Return the next variable name and GUID.
> +
> + This function is called multiple times to retrieve the VariableName
> + and VariableGuid of all variables currently available in the system.
> + On each call, the previous results are passed into the interface,
> + and, on return, the interface returns the data for the next
> + interface. When the entire variable list has been returned,
> + EFI_NOT_FOUND is returned.
> +
> + @param This A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +
> + @param VariableNameSize On entry, points to the size of the buffer pointed
> to by VariableName.
> + @param VariableName On entry, a pointer to a null-terminated string that
> is the variable's name.
> + On return, points to the next variable's null-terminated name
> string.
> +
> + @param VariableGuid On entry, a pointer to an UEFI _GUID that is the
> variable's GUID.
> + On return, a pointer to the next variable's GUID.
> +
> + @retval EFI_SUCCESS The variable was read successfully.
> + @retval EFI_NOT_FOUND The variable could not be found.
> + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the
> resulting
> + data. VariableNameSize is updated with the size
> + required for the specified variable.
> + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> + VariableNameSize is NULL.
> + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetNextVariableNameEx (
> + IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
> + IN OUT UINTN *VariableNameSize,
> + IN OUT CHAR16 *VariableName,
> + IN OUT EFI_GUID *VariableGuid
> + );
> +
> #endif
> diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableParsing.h
> b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.h
> new file mode 100644
> index 000000000000..d7af6cb6e8be
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.h
> @@ -0,0 +1,309 @@
> +/** @file
> + The internal header file includes the common header files, defines
> + internal structure and functions used by PeiVariable module.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PEI_VARIABLE_PARSING_H_
> +#define PEI_VARIABLE_PARSING_H_
> +
> +#include "Variable.h"
> +
> +/**
> +
> + Gets the pointer to the first variable header in given variable store area.
> +
> + @param[in] VarStoreHeader Pointer to the Variable Store Header.
> +
> + @return Pointer to the first variable header.
> +
> +**/
> +VARIABLE_HEADER *
> +GetStartPointer (
> + IN VARIABLE_STORE_HEADER *VarStoreHeader
> + );
> +
> +/**
> +
> + Gets the pointer to the end of the variable storage area.
> +
> + This function gets pointer to the end of the variable storage
> + area, according to the input variable store header.
> +
> + @param[in] VarStoreHeader Pointer to the Variable Store Header.
> +
> + @return Pointer to the end of the variable storage area.
> +
> +**/
> +VARIABLE_HEADER *
> +GetEndPointer (
> + IN VARIABLE_STORE_HEADER *VarStoreHeader
> + );
> +
> +/**
> + This code checks if variable header is valid or not.
> +
> + @param[in] Variable Pointer to the Variable Header.
> +
> + @retval TRUE Variable header is valid.
> + @retval FALSE Variable header is not valid.
> +
> +**/
> +BOOLEAN
> +IsValidVariableHeader (
> + IN VARIABLE_HEADER *Variable
> + );
> +
> +/**
> + This code gets the pointer to the next variable header.
> +
> + @param[in] StoreInfo Pointer to variable store info structure.
> + @param[in] Variable Pointer to the Variable Header.
> + @param[in] VariableHeader Pointer to the Variable Header that has
> consecutive content.
> +
> + @return A VARIABLE_HEADER* pointer to next variable header.
> +
> +**/
> +VARIABLE_HEADER *
> +GetNextVariablePtr (
> + IN VARIABLE_STORE_INFO *StoreInfo,
> + IN VARIABLE_HEADER *Variable,
> + IN VARIABLE_HEADER *VariableHeader
> + );
> +
> +/**
> + This code gets the pointer to the variable guid.
> +
> + @param[in] Variable Pointer to the Variable Header.
> + @param[in] AuthFlag Authenticated variable flag.
> +
> + @return A EFI_GUID* pointer to Vendor Guid.
> +
> +**/
> +EFI_GUID *
> +GetVendorGuidPtr (
> + IN VARIABLE_HEADER *Variable,
> + IN BOOLEAN AuthFlag
> + );
> +
> +/**
> + This code gets the pointer to the variable name.
> +
> + @param[in] Variable Pointer to the Variable Header.
> + @param[in] AuthFlag Authenticated variable flag.
> +
> + @return A CHAR16* pointer to Variable Name.
> +
> +**/
> +CHAR16 *
> +GetVariableNamePtr (
> + IN VARIABLE_HEADER *Variable,
> + IN BOOLEAN AuthFlag
> + );
> +
> +/**
> + This code gets the size of name of variable.
> +
> + @param[in] Variable Pointer to the Variable Header.
> + @param[in] AuthFlag Authenticated variable flag.
> +
> + @return Size of variable in bytes in type UINTN.
> +
> +**/
> +UINTN
> +NameSizeOfVariable (
> + IN VARIABLE_HEADER *Variable,
> + IN BOOLEAN AuthFlag
> + );
> +
> +/**
> + This code gets the size of data of variable.
> +
> + @param[in] Variable Pointer to the Variable Header.
> + @param[in] AuthFlag Authenticated variable flag.
> +
> + @return Size of variable in bytes in type UINTN.
> +
> +**/
> +UINTN
> +DataSizeOfVariable (
> + IN VARIABLE_HEADER *Variable,
> + IN BOOLEAN AuthFlag
> + );
> +
> +/**
> + This code gets the pointer to the variable data.
> +
> + @param[in] Variable Pointer to the Variable Header.
> + @param[in] VariableHeader Pointer to the Variable Header that has
> consecutive content.
> + @param[in] AuthFlag Authenticated variable flag.
> +
> + @return A UINT8* pointer to Variable Data.
> +
> +**/
> +UINT8 *
> +GetVariableDataPtr (
> + IN VARIABLE_HEADER *Variable,
> + IN VARIABLE_HEADER *VariableHeader,
> + IN BOOLEAN AuthFlag
> + );
> +
> +/**
> + Get variable header that has consecutive content.
> +
> + @param[in] StoreInfo Pointer to variable store info structure.
> + @param[in] Variable Pointer to the Variable Header.
> + @param[out] VariableHeader Pointer to Pointer to the Variable Header that
> has consecutive content.
> +
> + @retval TRUE Variable header is valid.
> + @retval FALSE Variable header is not valid.
> +
> +**/
> +BOOLEAN
> +GetVariableHeader (
> + IN VARIABLE_STORE_INFO *StoreInfo,
> + IN VARIABLE_HEADER *Variable,
> + OUT VARIABLE_HEADER **VariableHeader
> + );
> +
> +/**
> + This code gets the size of variable header.
> +
> + @param[in] AuthFlag Authenticated variable flag.
> +
> + @return Size of variable header in bytes in type UINTN.
> +
> +**/
> +UINTN
> +GetVariableHeaderSize (
> + IN BOOLEAN AuthFlag
> + );
> +
> +/**
> + Get variable name or data to output buffer.
> +
> + @param[in] StoreInfo Pointer to variable store info structure.
> + @param[in] NameOrData Pointer to the variable name/data that may be
> inconsecutive.
> + @param[in] Size Variable name/data size.
> + @param[out] Buffer Pointer to output buffer to hold the variable
> name/data.
> +
> +**/
> +VOID
> +GetVariableNameOrData (
> + IN VARIABLE_STORE_INFO *StoreInfo,
> + IN UINT8 *NameOrData,
> + IN UINTN Size,
> + OUT UINT8 *Buffer
> + );
> +
> +/**
> + This function compares a variable with variable entries in database.
> +
> + @param[in] StoreInfo Pointer to variable store info structure.
> + @param[in] Variable Pointer to the variable in our database
> + @param[in] VariableHeader Pointer to the Variable Header that has
> consecutive content.
> + @param[in] VariableName Name of the variable to compare to 'Variable'
> + @param[in] VendorGuid GUID of the variable to compare to 'Variable'
> + @param[out] PtrTrack Variable Track Pointer structure that contains
> Variable Information.
> +
> + @retval EFI_SUCCESS Found match variable
> + @retval EFI_NOT_FOUND Variable not found
> +
> +**/
> +EFI_STATUS
> +CompareWithValidVariable (
> + IN VARIABLE_STORE_INFO *StoreInfo,
> + IN VARIABLE_HEADER *Variable,
> + IN VARIABLE_HEADER *VariableHeader,
> + IN CONST CHAR16 *VariableName,
> + IN CONST EFI_GUID *VendorGuid,
> + OUT VARIABLE_POINTER_TRACK *PtrTrack
> + );
> +
> +/**
> +
> + Retrieve details of the variable next to given variable within VariableStore.
> +
> + If VarInfo->Address is NULL, the first one in VariableStore is returned.
> +
> + VariableStart and/or VariableEnd can be given optionally for the situation
> + in which the valid storage space is smaller than the VariableStore->Size.
> + This usually happens when PEI variable services make a compact variable
> + cache to save memory, which cannot make use VariableStore->Size to
> determine
> + the correct variable storage range.
> +
> + @param[in,out] VariableInfo Pointer to variable information.
> +
> + @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL.
> + @retval EFI_NOT_FOUND If the end of VariableStore is reached.
> + @retval EFI_SUCCESS The next variable is retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetNextVariableInfo (
> + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
> + );
> +
> +/**
> +
> + Retrieve details about a variable and return them in VariableInfo->Header.
> +
> + If VariableInfo->Address is given, this function will calculate its offset
> + relative to given variable storage via VariableStore; Otherwise, it will try
> + other internal variable storages or cached copies. It's assumed that, for all
> + copies of NV variable storage, all variables are stored in the same relative
> + position. If VariableInfo->Address is found in the range of any storage copies,
> + its offset relative to that storage should be the same in other copies.
> +
> + If VariableInfo->Offset is given (non-zero) but not VariableInfo->Address,
> + this function will return the variable memory address inside VariableStore,
> + if given, via VariableInfo->Address; Otherwise, the address of other storage
> + copies will be returned, if any.
> +
> + For a new variable whose offset has not been determined, a value of -1 as
> + VariableInfo->Offset should be passed to skip the offset calculation.
> +
> + @param[in,out] VariableInfo Pointer to variable information.
> +
> + @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo-
> >Address
> + and VariableInfo->Offset are NULL (0).
> + @retval EFI_NOT_FOUND If given Address or Offset is out of range of
> + any given or internal storage copies.
> + @retval EFI_SUCCESS Variable details are retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetVariableInfo (
> + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
> + );
> +
> +/**
> +
> + Find variable specified with input parameters.
> +
> + @param[in] StoreInfo Pointer to variable information.
> + @param[in] VariableName Pointer to variable name.
> + @param[in] VendorGuid Pointer to variable GUID.
> + @param[in] PtrTrack Pointer to variable track.
> +
> + @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo-
> >Address
> + and VariableInfo->Offset are NULL (0).
> + @retval EFI_NOT_FOUND If given Address or Offset is out of range of
> + any given or internal storage copies.
> + @retval EFI_SUCCESS Variable details are retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +FindVariableEx (
> + IN VARIABLE_STORE_INFO *StoreInfo,
> + IN CONST CHAR16 *VariableName,
> + IN CONST EFI_GUID *VendorGuid,
> + OUT VARIABLE_POINTER_TRACK *PtrTrack
> + );
> +
> +#endif
> diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableStore.h
> b/MdeModulePkg/Universal/Variable/Pei/VariableStore.h
> new file mode 100644
> index 000000000000..6e2f6f939bab
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Pei/VariableStore.h
> @@ -0,0 +1,116 @@
> +/** @file
> + Implement ReadOnly Variable Services required by PEIM and install
> + PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage
> space.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PEI_VARIABLE_STORE_H_
> +#define PEI_VARIABLE_STORE_H_
> +
> +/**
> + Get variable store status.
> +
> + @param[in] VarStoreHeader Pointer to the Variable Store Header.
> +
> + @retval EfiRaw Variable store is raw
> + @retval EfiValid Variable store is valid
> + @retval EfiInvalid Variable store is invalid
> +
> +**/
> +VARIABLE_STORE_STATUS
> +GetVariableStoreStatus (
> + IN VARIABLE_STORE_HEADER *VarStoreHeader
> + );
> +
> +/**
> + Reports HOB variable store is available or not.
> +
> + @retval EFI_NOT_READY HOB variable store info not available.
> + @retval EFI_NOT_FOUND HOB variable store is NOT available.
> + @retval EFI_SUCCESS HOB variable store is available.
> +**/
> +EFI_STATUS
> +EFIAPI
> +IsHobVariableStoreAvailable (
> + VOID
> + );
> +
> +/**
> + Get HOB variable store.
> +
> + @param[out] StoreInfo Return the store info.
> +
> +**/
> +VOID
> +GetHobVariableStore (
> + OUT VARIABLE_STORE_INFO *StoreInfo
> + );
> +
> +/**
> + Get NV variable store.
> +
> + @param[out] StoreInfo Return the store info.
> + @param[out] VariableStoreHeader Return header of FV containing the store.
> +
> +**/
> +VOID
> +GetNvVariableStore (
> + OUT VARIABLE_STORE_INFO *StoreInfo,
> + OUT EFI_FIRMWARE_VOLUME_HEADER **VariableFvHeader
> + );
> +
> +/**
> + Return the variable store header and the store info based on the Index.
> +
> + @param[in] Type The type of the variable store.
> + @param[out] StoreInfo Return the store info.
> +
> + @return Pointer to the variable store header.
> +**/
> +VARIABLE_STORE_HEADER *
> +GetVariableStore (
> + IN VARIABLE_STORE_TYPE Type,
> + OUT VARIABLE_STORE_INFO *StoreInfo
> + );
> +
> +/**
> + Make a cached copy of NV variable storage.
> +
> + To save memory in PEI phase, only valid variables are copied into cache.
> + An IndexTable could be used to store the offset (relative to NV storage
> + base) of each copied variable, in case we need to restore the storage
> + as the same (valid) variables layout as in original one.
> +
> + Variables with valid format and following state can be taken as valid:
> + - with state VAR_ADDED;
> + - with state VAR_IN_DELETED_TRANSITION but without the same variable
> + with state VAR_ADDED;
> + - with state VAR_ADDED and/or VAR_IN_DELETED_TRANSITION for variable
> + MetaDataHmacVar.
> +
> + @param[out] StoreCacheBase Base address of variable storage cache.
> + @param[in,out] StoreCacheSize Size of space in StoreCacheBase.
> + @param[out] IndexTable Buffer of index (offset) table with entries of
> + VariableNumber.
> + @param[out] VariableNumber Number of valid variables.
> + @param[out] AuthFlag Aut-variable indicator.
> +
> + @return EFI_INVALID_PARAMETER Invalid StoreCacheSize and/or
> StoreCacheBase.
> + @return EFI_VOLUME_CORRUPTED Invalid or no NV variable storage found.
> + @return EFI_BUFFER_TOO_SMALL StoreCacheSize is smaller than needed.
> + @return EFI_SUCCESS NV variable storage is cached successfully.
> +**/
> +EFI_STATUS
> +EFIAPI
> +InitNvVariableStore (
> + OUT EFI_PHYSICAL_ADDRESS StoreCacheBase OPTIONAL,
> + IN OUT UINT32 *StoreCacheSize,
> + OUT UINT32 *IndexTable OPTIONAL,
> + OUT UINT32 *VariableNumber OPTIONAL,
> + OUT BOOLEAN *AuthFlag OPTIONAL
> + );
> +
> +#endif
> diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.c
> b/MdeModulePkg/Universal/Variable/Pei/Variable.c
> index b36dd0de67b2..ce790946626e 100644
> --- a/MdeModulePkg/Universal/Variable/Pei/Variable.c
> +++ b/MdeModulePkg/Universal/Variable/Pei/Variable.c
> @@ -2,20 +2,22 @@
> Implement ReadOnly Variable Services required by PEIM and install
> PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage
> space.
>
> -Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> Copyright (c) Microsoft Corporation.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> **/
>
> #include "Variable.h"
> +#include "VariableParsing.h"
> +#include "VariableStore.h"
>
> //
> // Module globals
> //
> EFI_PEI_READ_ONLY_VARIABLE2_PPI mVariablePpi = {
> - PeiGetVariable,
> - PeiGetNextVariableName
> + PeiGetVariableEx,
> + PeiGetNextVariableNameEx
> };
>
> EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = {
> @@ -41,759 +43,33 @@ PeimInitializeVariableServices (
> IN CONST EFI_PEI_SERVICES **PeiServices
> )
> {
> + EFI_STATUS Status;
> + PROTECTED_VARIABLE_CONTEXT_IN ContextIn;
> +
> + //
> + // If protected variable services are not supported, EFI_UNSUPPORTED should
> + // be always returned. Check it here.
> + //
> + ContextIn.StructVersion =
> PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
> + ContextIn.StructSize = sizeof (ContextIn);
> +
> + ContextIn.MaxVariableSize = 0;
> + ContextIn.VariableServiceUser = FromPeiModule;
> + ContextIn.GetVariableInfo = GetVariableInfo;
> + ContextIn.GetNextVariableInfo = GetNextVariableInfo;
> + ContextIn.FindVariableSmm = NULL;
> + ContextIn.UpdateVariableStore = NULL;
> + ContextIn.UpdateVariable = NULL;
> + ContextIn.IsHobVariableStoreAvailable = IsHobVariableStoreAvailable;
> +
> + Status = ProtectedVariableLibInitialize (&ContextIn);
> + if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
> + return Status;
> + }
> +
> return PeiServicesInstallPpi (&mPpiListVariable);
> }
>
> -/**
> -
> - Gets the pointer to the first variable header in given variable store area.
> -
> - @param VarStoreHeader Pointer to the Variable Store Header.
> -
> - @return Pointer to the first variable header.
> -
> -**/
> -VARIABLE_HEADER *
> -GetStartPointer (
> - IN VARIABLE_STORE_HEADER *VarStoreHeader
> - )
> -{
> - //
> - // The start of variable store
> - //
> - return (VARIABLE_HEADER *)HEADER_ALIGN (VarStoreHeader + 1);
> -}
> -
> -/**
> -
> - Gets the pointer to the end of the variable storage area.
> -
> - This function gets pointer to the end of the variable storage
> - area, according to the input variable store header.
> -
> - @param VarStoreHeader Pointer to the Variable Store Header.
> -
> - @return Pointer to the end of the variable storage area.
> -
> -**/
> -VARIABLE_HEADER *
> -GetEndPointer (
> - IN VARIABLE_STORE_HEADER *VarStoreHeader
> - )
> -{
> - //
> - // The end of variable store
> - //
> - return (VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)VarStoreHeader +
> VarStoreHeader->Size);
> -}
> -
> -/**
> - This code checks if variable header is valid or not.
> -
> - @param Variable Pointer to the Variable Header.
> -
> - @retval TRUE Variable header is valid.
> - @retval FALSE Variable header is not valid.
> -
> -**/
> -BOOLEAN
> -IsValidVariableHeader (
> - IN VARIABLE_HEADER *Variable
> - )
> -{
> - if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
> - return FALSE;
> - }
> -
> - return TRUE;
> -}
> -
> -/**
> - This code gets the size of variable header.
> -
> - @param AuthFlag Authenticated variable flag.
> -
> - @return Size of variable header in bytes in type UINTN.
> -
> -**/
> -UINTN
> -GetVariableHeaderSize (
> - IN BOOLEAN AuthFlag
> - )
> -{
> - UINTN Value;
> -
> - if (AuthFlag) {
> - Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
> - } else {
> - Value = sizeof (VARIABLE_HEADER);
> - }
> -
> - return Value;
> -}
> -
> -/**
> - This code gets the size of name of variable.
> -
> - @param Variable Pointer to the Variable Header.
> - @param AuthFlag Authenticated variable flag.
> -
> - @return Size of variable in bytes in type UINTN.
> -
> -**/
> -UINTN
> -NameSizeOfVariable (
> - IN VARIABLE_HEADER *Variable,
> - IN BOOLEAN AuthFlag
> - )
> -{
> - AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
> -
> - AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> - if (AuthFlag) {
> - if ((AuthVariable->State == (UINT8)(-1)) ||
> - (AuthVariable->DataSize == (UINT32)(-1)) ||
> - (AuthVariable->NameSize == (UINT32)(-1)) ||
> - (AuthVariable->Attributes == (UINT32)(-1)))
> - {
> - return 0;
> - }
> -
> - return (UINTN)AuthVariable->NameSize;
> - } else {
> - if ((Variable->State == (UINT8)(-1)) ||
> - (Variable->DataSize == (UINT32)(-1)) ||
> - (Variable->NameSize == (UINT32)(-1)) ||
> - (Variable->Attributes == (UINT32)(-1)))
> - {
> - return 0;
> - }
> -
> - return (UINTN)Variable->NameSize;
> - }
> -}
> -
> -/**
> - This code gets the size of data of variable.
> -
> - @param Variable Pointer to the Variable Header.
> - @param AuthFlag Authenticated variable flag.
> -
> - @return Size of variable in bytes in type UINTN.
> -
> -**/
> -UINTN
> -DataSizeOfVariable (
> - IN VARIABLE_HEADER *Variable,
> - IN BOOLEAN AuthFlag
> - )
> -{
> - AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
> -
> - AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> - if (AuthFlag) {
> - if ((AuthVariable->State == (UINT8)(-1)) ||
> - (AuthVariable->DataSize == (UINT32)(-1)) ||
> - (AuthVariable->NameSize == (UINT32)(-1)) ||
> - (AuthVariable->Attributes == (UINT32)(-1)))
> - {
> - return 0;
> - }
> -
> - return (UINTN)AuthVariable->DataSize;
> - } else {
> - if ((Variable->State == (UINT8)(-1)) ||
> - (Variable->DataSize == (UINT32)(-1)) ||
> - (Variable->NameSize == (UINT32)(-1)) ||
> - (Variable->Attributes == (UINT32)(-1)))
> - {
> - return 0;
> - }
> -
> - return (UINTN)Variable->DataSize;
> - }
> -}
> -
> -/**
> - This code gets the pointer to the variable name.
> -
> - @param Variable Pointer to the Variable Header.
> - @param AuthFlag Authenticated variable flag.
> -
> - @return A CHAR16* pointer to Variable Name.
> -
> -**/
> -CHAR16 *
> -GetVariableNamePtr (
> - IN VARIABLE_HEADER *Variable,
> - IN BOOLEAN AuthFlag
> - )
> -{
> - return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag));
> -}
> -
> -/**
> - This code gets the pointer to the variable guid.
> -
> - @param Variable Pointer to the Variable Header.
> - @param AuthFlag Authenticated variable flag.
> -
> - @return A EFI_GUID* pointer to Vendor Guid.
> -
> -**/
> -EFI_GUID *
> -GetVendorGuidPtr (
> - IN VARIABLE_HEADER *Variable,
> - IN BOOLEAN AuthFlag
> - )
> -{
> - AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
> -
> - AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> - if (AuthFlag) {
> - return &AuthVariable->VendorGuid;
> - } else {
> - return &Variable->VendorGuid;
> - }
> -}
> -
> -/**
> - This code gets the pointer to the variable data.
> -
> - @param Variable Pointer to the Variable Header.
> - @param VariableHeader Pointer to the Variable Header that has
> consecutive content.
> - @param AuthFlag Authenticated variable flag.
> -
> - @return A UINT8* pointer to Variable Data.
> -
> -**/
> -UINT8 *
> -GetVariableDataPtr (
> - IN VARIABLE_HEADER *Variable,
> - IN VARIABLE_HEADER *VariableHeader,
> - IN BOOLEAN AuthFlag
> - )
> -{
> - UINTN Value;
> -
> - //
> - // Be careful about pad size for alignment
> - //
> - Value = (UINTN)GetVariableNamePtr (Variable, AuthFlag);
> - Value += NameSizeOfVariable (VariableHeader, AuthFlag);
> - Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));
> -
> - return (UINT8 *)Value;
> -}
> -
> -/**
> - This code gets the pointer to the next variable header.
> -
> - @param StoreInfo Pointer to variable store info structure.
> - @param Variable Pointer to the Variable Header.
> - @param VariableHeader Pointer to the Variable Header that has
> consecutive content.
> -
> - @return A VARIABLE_HEADER* pointer to next variable header.
> -
> -**/
> -VARIABLE_HEADER *
> -GetNextVariablePtr (
> - IN VARIABLE_STORE_INFO *StoreInfo,
> - IN VARIABLE_HEADER *Variable,
> - IN VARIABLE_HEADER *VariableHeader
> - )
> -{
> - EFI_PHYSICAL_ADDRESS TargetAddress;
> - EFI_PHYSICAL_ADDRESS SpareAddress;
> - UINTN Value;
> -
> - Value = (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo-
> >AuthFlag);
> - Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);
> - Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo-
> >AuthFlag));
> - //
> - // Be careful about pad size for alignment
> - //
> - Value = HEADER_ALIGN (Value);
> -
> - if (StoreInfo->FtwLastWriteData != NULL) {
> - TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> - SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
> - if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >=
> (UINTN)TargetAddress)) {
> - //
> - // Next variable is in spare block.
> - //
> - Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress);
> - }
> - }
> -
> - return (VARIABLE_HEADER *)Value;
> -}
> -
> -/**
> - Get variable store status.
> -
> - @param VarStoreHeader Pointer to the Variable Store Header.
> -
> - @retval EfiRaw Variable store is raw
> - @retval EfiValid Variable store is valid
> - @retval EfiInvalid Variable store is invalid
> -
> -**/
> -VARIABLE_STORE_STATUS
> -GetVariableStoreStatus (
> - IN VARIABLE_STORE_HEADER *VarStoreHeader
> - )
> -{
> - if ((CompareGuid (&VarStoreHeader->Signature,
> &gEfiAuthenticatedVariableGuid) ||
> - CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
> - (VarStoreHeader->Format == VARIABLE_STORE_FORMATTED) &&
> - (VarStoreHeader->State == VARIABLE_STORE_HEALTHY)
> - )
> - {
> - return EfiValid;
> - }
> -
> - if ((((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff) &&
> - (((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff) &&
> - (((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff) &&
> - (((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff) &&
> - (VarStoreHeader->Size == 0xffffffff) &&
> - (VarStoreHeader->Format == 0xff) &&
> - (VarStoreHeader->State == 0xff)
> - )
> - {
> - return EfiRaw;
> - } else {
> - return EfiInvalid;
> - }
> -}
> -
> -/**
> - Compare two variable names, one of them may be inconsecutive.
> -
> - @param StoreInfo Pointer to variable store info structure.
> - @param Name1 Pointer to one variable name.
> - @param Name2 Pointer to another variable name.
> - @param NameSize Variable name size.
> -
> - @retval TRUE Name1 and Name2 are identical.
> - @retval FALSE Name1 and Name2 are not identical.
> -
> -**/
> -BOOLEAN
> -CompareVariableName (
> - IN VARIABLE_STORE_INFO *StoreInfo,
> - IN CONST CHAR16 *Name1,
> - IN CONST CHAR16 *Name2,
> - IN UINTN NameSize
> - )
> -{
> - EFI_PHYSICAL_ADDRESS TargetAddress;
> - EFI_PHYSICAL_ADDRESS SpareAddress;
> - UINTN PartialNameSize;
> -
> - if (StoreInfo->FtwLastWriteData != NULL) {
> - TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> - SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
> - if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 +
> NameSize) > (UINTN)TargetAddress)) {
> - //
> - // Name1 is inconsecutive.
> - //
> - PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1;
> - //
> - // Partial content is in NV storage.
> - //
> - if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize) == 0)
> {
> - //
> - // Another partial content is in spare block.
> - //
> - if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 +
> PartialNameSize, NameSize - PartialNameSize) == 0) {
> - return TRUE;
> - }
> - }
> -
> - return FALSE;
> - } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 +
> NameSize) > (UINTN)TargetAddress)) {
> - //
> - // Name2 is inconsecutive.
> - //
> - PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2;
> - //
> - // Partial content is in NV storage.
> - //
> - if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize) == 0)
> {
> - //
> - // Another partial content is in spare block.
> - //
> - if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 +
> PartialNameSize, NameSize - PartialNameSize) == 0) {
> - return TRUE;
> - }
> - }
> -
> - return FALSE;
> - }
> - }
> -
> - //
> - // Both Name1 and Name2 are consecutive.
> - //
> - if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) {
> - return TRUE;
> - }
> -
> - return FALSE;
> -}
> -
> -/**
> - This function compares a variable with variable entries in database.
> -
> - @param StoreInfo Pointer to variable store info structure.
> - @param Variable Pointer to the variable in our database
> - @param VariableHeader Pointer to the Variable Header that has consecutive
> content.
> - @param VariableName Name of the variable to compare to 'Variable'
> - @param VendorGuid GUID of the variable to compare to 'Variable'
> - @param PtrTrack Variable Track Pointer structure that contains Variable
> Information.
> -
> - @retval EFI_SUCCESS Found match variable
> - @retval EFI_NOT_FOUND Variable not found
> -
> -**/
> -EFI_STATUS
> -CompareWithValidVariable (
> - IN VARIABLE_STORE_INFO *StoreInfo,
> - IN VARIABLE_HEADER *Variable,
> - IN VARIABLE_HEADER *VariableHeader,
> - IN CONST CHAR16 *VariableName,
> - IN CONST EFI_GUID *VendorGuid,
> - OUT VARIABLE_POINTER_TRACK *PtrTrack
> - )
> -{
> - VOID *Point;
> - EFI_GUID *TempVendorGuid;
> -
> - TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag);
> -
> - if (VariableName[0] == 0) {
> - PtrTrack->CurrPtr = Variable;
> - return EFI_SUCCESS;
> - } else {
> - //
> - // Don't use CompareGuid function here for performance reasons.
> - // Instead we compare the GUID a UINT32 at a time and branch
> - // on the first failed comparison.
> - //
> - if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) &&
> - (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) &&
> - (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) &&
> - (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3])
> - )
> - {
> - ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);
> - Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag);
> - if (CompareVariableName (StoreInfo, VariableName, Point,
> NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {
> - PtrTrack->CurrPtr = Variable;
> - return EFI_SUCCESS;
> - }
> - }
> - }
> -
> - return EFI_NOT_FOUND;
> -}
> -
> -/**
> - Get HOB variable store.
> -
> - @param[out] StoreInfo Return the store info.
> - @param[out] VariableStoreHeader Return variable store header.
> -
> -**/
> -VOID
> -GetHobVariableStore (
> - OUT VARIABLE_STORE_INFO *StoreInfo,
> - OUT VARIABLE_STORE_HEADER **VariableStoreHeader
> - )
> -{
> - EFI_HOB_GUID_TYPE *GuidHob;
> -
> - //
> - // Make sure there is no more than one Variable HOB.
> - //
> - DEBUG_CODE_BEGIN ();
> - GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
> - if (GuidHob != NULL) {
> - if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB
> (GuidHob)) != NULL)) {
> - DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
> - ASSERT (FALSE);
> - } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
> - DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable
> HOBs\n"));
> - ASSERT (FALSE);
> - }
> - } else {
> - GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
> - if (GuidHob != NULL) {
> - if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) !=
> NULL)) {
> - DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
> - ASSERT (FALSE);
> - }
> - }
> - }
> -
> - DEBUG_CODE_END ();
> -
> - GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
> - if (GuidHob != NULL) {
> - *VariableStoreHeader = (VARIABLE_STORE_HEADER
> *)GET_GUID_HOB_DATA (GuidHob);
> - StoreInfo->AuthFlag = TRUE;
> - } else {
> - GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
> - if (GuidHob != NULL) {
> - *VariableStoreHeader = (VARIABLE_STORE_HEADER
> *)GET_GUID_HOB_DATA (GuidHob);
> - StoreInfo->AuthFlag = FALSE;
> - }
> - }
> -}
> -
> -/**
> - Return the variable store header and the store info based on the Index.
> -
> - @param Type The type of the variable store.
> - @param StoreInfo Return the store info.
> -
> - @return Pointer to the variable store header.
> -**/
> -VARIABLE_STORE_HEADER *
> -GetVariableStore (
> - IN VARIABLE_STORE_TYPE Type,
> - OUT VARIABLE_STORE_INFO *StoreInfo
> - )
> -{
> - EFI_HOB_GUID_TYPE *GuidHob;
> - EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
> - VARIABLE_STORE_HEADER *VariableStoreHeader;
> - EFI_PHYSICAL_ADDRESS NvStorageBase;
> - UINT32 NvStorageSize;
> - FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
> - UINT32 BackUpOffset;
> -
> - StoreInfo->IndexTable = NULL;
> - StoreInfo->FtwLastWriteData = NULL;
> - StoreInfo->AuthFlag = FALSE;
> - VariableStoreHeader = NULL;
> - switch (Type) {
> - case VariableStoreTypeHob:
> - GetHobVariableStore (StoreInfo, &VariableStoreHeader);
> -
> - break;
> -
> - case VariableStoreTypeNv:
> - if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
> - //
> - // Emulated non-volatile variable mode is not enabled.
> - //
> -
> - NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
> - NvStorageBase = (EFI_PHYSICAL_ADDRESS)(PcdGet64
> (PcdFlashNvStorageVariableBase64) != 0 ?
> - PcdGet64 (PcdFlashNvStorageVariableBase64) :
> - PcdGet32 (PcdFlashNvStorageVariableBase)
> - );
> - ASSERT (NvStorageBase != 0);
> -
> - //
> - // First let FvHeader point to NV storage base.
> - //
> - FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase;
> -
> - //
> - // Check the FTW last write data hob.
> - //
> - BackUpOffset = 0;
> - GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
> - if (GuidHob != NULL) {
> - FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
> *)GET_GUID_HOB_DATA (GuidHob);
> - if (FtwLastWriteData->TargetAddress == NvStorageBase) {
> - //
> - // Let FvHeader point to spare block.
> - //
> - FvHeader = (EFI_FIRMWARE_VOLUME_HEADER
> *)(UINTN)FtwLastWriteData->SpareAddress;
> - DEBUG ((DEBUG_INFO, "PeiVariable: NV storage is backed up in spare
> block: 0x%x\n", (UINTN)FtwLastWriteData->SpareAddress));
> - } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&
> (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {
> - StoreInfo->FtwLastWriteData = FtwLastWriteData;
> - //
> - // Flash NV storage from the offset is backed up in spare block.
> - //
> - BackUpOffset = (UINT32)(FtwLastWriteData->TargetAddress -
> NvStorageBase);
> - DEBUG ((DEBUG_INFO, "PeiVariable: High partial NV storage from
> offset: %x is backed up in spare block: 0x%x\n", BackUpOffset,
> (UINTN)FtwLastWriteData->SpareAddress));
> - //
> - // At least one block data in flash NV storage is still valid, so still leave
> FvHeader point to NV storage base.
> - //
> - }
> - }
> -
> - //
> - // Check if the Firmware Volume is not corrupted
> - //
> - if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid
> (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {
> - DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is
> corrupted\n"));
> - break;
> - }
> -
> - VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINT8 *)FvHeader +
> FvHeader->HeaderLength);
> -
> - StoreInfo->AuthFlag = (BOOLEAN)(CompareGuid (&VariableStoreHeader-
> >Signature, &gEfiAuthenticatedVariableGuid));
> -
> - GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
> - if (GuidHob != NULL) {
> - StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
> - } else {
> - //
> - // If it's the first time to access variable region in flash, create a guid hob
> to record
> - // VAR_ADDED type variable info.
> - // Note that as the resource of PEI phase is limited, only store the limited
> number of
> - // VAR_ADDED type variables to reduce access time.
> - //
> - StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE *)BuildGuidHob
> (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
> - StoreInfo->IndexTable->Length = 0;
> - StoreInfo->IndexTable->StartPtr = GetStartPointer
> (VariableStoreHeader);
> - StoreInfo->IndexTable->EndPtr = GetEndPointer (VariableStoreHeader);
> - StoreInfo->IndexTable->GoneThrough = 0;
> - }
> - }
> -
> - break;
> -
> - default:
> - ASSERT (FALSE);
> - break;
> - }
> -
> - StoreInfo->VariableStoreHeader = VariableStoreHeader;
> - return VariableStoreHeader;
> -}
> -
> -/**
> - Get variable header that has consecutive content.
> -
> - @param StoreInfo Pointer to variable store info structure.
> - @param Variable Pointer to the Variable Header.
> - @param VariableHeader Pointer to Pointer to the Variable Header that has
> consecutive content.
> -
> - @retval TRUE Variable header is valid.
> - @retval FALSE Variable header is not valid.
> -
> -**/
> -BOOLEAN
> -GetVariableHeader (
> - IN VARIABLE_STORE_INFO *StoreInfo,
> - IN VARIABLE_HEADER *Variable,
> - OUT VARIABLE_HEADER **VariableHeader
> - )
> -{
> - EFI_PHYSICAL_ADDRESS TargetAddress;
> - EFI_PHYSICAL_ADDRESS SpareAddress;
> - EFI_HOB_GUID_TYPE *GuidHob;
> - UINTN PartialHeaderSize;
> -
> - if (Variable == NULL) {
> - return FALSE;
> - }
> -
> - //
> - // First assume variable header pointed by Variable is consecutive.
> - //
> - *VariableHeader = Variable;
> -
> - if (StoreInfo->FtwLastWriteData != NULL) {
> - TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> - SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
> - if (((UINTN)Variable > (UINTN)SpareAddress) &&
> - (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >=
> (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader)))
> - {
> - //
> - // Reach the end of variable store.
> - //
> - return FALSE;
> - }
> -
> - if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable +
> GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) {
> - //
> - // Variable header pointed by Variable is inconsecutive,
> - // create a guid hob to combine the two partial variable header content
> together.
> - //
> - GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
> - if (GuidHob != NULL) {
> - *VariableHeader = (VARIABLE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
> - } else {
> - *VariableHeader = (VARIABLE_HEADER *)BuildGuidHob (&gEfiCallerIdGuid,
> GetVariableHeaderSize (StoreInfo->AuthFlag));
> - PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable;
> - //
> - // Partial content is in NV storage.
> - //
> - CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable,
> PartialHeaderSize);
> - //
> - // Another partial content is in spare block.
> - //
> - CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8
> *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) -
> PartialHeaderSize);
> - }
> - }
> - } else {
> - if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
> - //
> - // Reach the end of variable store.
> - //
> - return FALSE;
> - }
> - }
> -
> - return IsValidVariableHeader (*VariableHeader);
> -}
> -
> -/**
> - Get variable name or data to output buffer.
> -
> - @param StoreInfo Pointer to variable store info structure.
> - @param NameOrData Pointer to the variable name/data that may be
> inconsecutive.
> - @param Size Variable name/data size.
> - @param Buffer Pointer to output buffer to hold the variable name/data.
> -
> -**/
> -VOID
> -GetVariableNameOrData (
> - IN VARIABLE_STORE_INFO *StoreInfo,
> - IN UINT8 *NameOrData,
> - IN UINTN Size,
> - OUT UINT8 *Buffer
> - )
> -{
> - EFI_PHYSICAL_ADDRESS TargetAddress;
> - EFI_PHYSICAL_ADDRESS SpareAddress;
> - UINTN PartialSize;
> -
> - if (StoreInfo->FtwLastWriteData != NULL) {
> - TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> - SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
> - if (((UINTN)NameOrData < (UINTN)TargetAddress) &&
> (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) {
> - //
> - // Variable name/data is inconsecutive.
> - //
> - PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData;
> - //
> - // Partial content is in NV storage.
> - //
> - CopyMem (Buffer, NameOrData, PartialSize);
> - //
> - // Another partial content is in spare block.
> - //
> - CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size -
> PartialSize);
> - return;
> - }
> - }
> -
> - //
> - // Variable name/data is consecutive.
> - //
> - CopyMem (Buffer, NameOrData, Size);
> -}
> -
> /**
> Find the variable in the specified variable store.
>
> @@ -1246,3 +522,107 @@ PeiGetNextVariableName (
> }
> }
> }
> +
> +/**
> + This service retrieves a variable's value using its name and GUID.
> +
> + Read the specified variable from the UEFI variable store. If the Data
> + buffer is too small to hold the contents of the variable, the error
> + EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
> + size to obtain the data.
> +
> + @param This A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> + @param VariableName A pointer to a null-terminated string that is the
> variable's name.
> + @param VariableGuid A pointer to an EFI_GUID that is the variable's
> GUID. The combination of
> + VariableGuid and VariableName must be unique.
> + @param Attributes If non-NULL, on return, points to the variable's
> attributes.
> + @param DataSize On entry, points to the size in bytes of the Data
> buffer.
> + On return, points to the size of the data returned in Data.
> + @param Data Points to the buffer which will hold the returned
> variable value.
> + May be NULL with a zero DataSize in order to determine the
> size of the buffer needed.
> +
> + @retval EFI_SUCCESS The variable was read successfully.
> + @retval EFI_NOT_FOUND The variable was be found.
> + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting
> data.
> + DataSize is updated with the size required for
> + the specified variable.
> + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> Data is NULL.
> + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetVariableEx (
> + IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
> + IN CONST CHAR16 *VariableName,
> + IN CONST EFI_GUID *VariableGuid,
> + OUT UINT32 *Attributes,
> + IN OUT UINTN *DataSize,
> + OUT VOID *Data OPTIONAL
> + )
> +{
> + EFI_STATUS Status;
> +
> + //
> + // If variable protection is employed, always get variable data through
> + // ProtectedVariableLib.
> + //
> + Status = ProtectedVariableLibGetByName (VariableName, VariableGuid,
> Attributes, DataSize, Data);
> + if (Status != EFI_UNSUPPORTED) {
> + return Status;
> + }
> +
> + return PeiGetVariable (This, VariableName, VariableGuid, Attributes, DataSize,
> Data);
> +}
> +
> +/**
> + Return the next variable name and GUID.
> +
> + This function is called multiple times to retrieve the VariableName
> + and VariableGuid of all variables currently available in the system.
> + On each call, the previous results are passed into the interface,
> + and, on return, the interface returns the data for the next
> + interface. When the entire variable list has been returned,
> + EFI_NOT_FOUND is returned.
> +
> + @param This A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +
> + @param VariableNameSize On entry, points to the size of the buffer pointed
> to by VariableName.
> + On return, the size of the variable name buffer.
> + @param VariableName On entry, a pointer to a null-terminated string that
> is the variable's name.
> + On return, points to the next variable's null-terminated name
> string.
> + @param VariableGuid On entry, a pointer to an EFI_GUID that is the
> variable's GUID.
> + On return, a pointer to the next variable's GUID.
> +
> + @retval EFI_SUCCESS The variable was read successfully.
> + @retval EFI_NOT_FOUND The variable could not be found.
> + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the
> resulting
> + data. VariableNameSize is updated with the size
> + required for the specified variable.
> + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> + VariableNameSize is NULL.
> + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetNextVariableNameEx (
> + IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
> + IN OUT UINTN *VariableNameSize,
> + IN OUT CHAR16 *VariableName,
> + IN OUT EFI_GUID *VariableGuid
> + )
> +{
> + EFI_STATUS Status;
> +
> + //
> + // If variable protection is employed, always get next variable through
> + // ProtectedVariableLib.
> + //
> + Status = ProtectedVariableLibFindNext (VariableNameSize, VariableName,
> VariableGuid);
> + if (Status != EFI_UNSUPPORTED) {
> + return Status;
> + }
> +
> + return PeiGetNextVariableName (This, VariableNameSize, VariableName,
> VariableGuid);
> +}
> diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableParsing.c
> b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.c
> new file mode 100644
> index 000000000000..2d605d39cbb6
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.c
> @@ -0,0 +1,941 @@
> +/** @file
> + Implement ReadOnly Variable Services required by PEIM and install
> + PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage
> space.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "Variable.h"
> +#include "VariableStore.h"
> +
> +/**
> +
> + Gets the pointer to the first variable header in given variable store area.
> +
> + @param[in] VarStoreHeader Pointer to the Variable Store Header.
> +
> + @return Pointer to the first variable header.
> +
> +**/
> +VARIABLE_HEADER *
> +GetStartPointer (
> + IN VARIABLE_STORE_HEADER *VarStoreHeader
> + )
> +{
> + //
> + // The start of variable store
> + //
> + return (VARIABLE_HEADER *)HEADER_ALIGN (VarStoreHeader + 1);
> +}
> +
> +/**
> +
> + Gets the pointer to the end of the variable storage area.
> +
> + This function gets pointer to the end of the variable storage
> + area, according to the input variable store header.
> +
> + @param[in] VarStoreHeader Pointer to the Variable Store Header.
> +
> + @return Pointer to the end of the variable storage area.
> +
> +**/
> +VARIABLE_HEADER *
> +GetEndPointer (
> + IN VARIABLE_STORE_HEADER *VarStoreHeader
> + )
> +{
> + //
> + // The end of variable store
> + //
> + return (VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)VarStoreHeader +
> VarStoreHeader->Size);
> +}
> +
> +/**
> + This code checks if variable header is valid or not.
> +
> + @param[in] Variable Pointer to the Variable Header.
> +
> + @retval TRUE Variable header is valid.
> + @retval FALSE Variable header is not valid.
> +
> +**/
> +BOOLEAN
> +IsValidVariableHeader (
> + IN VARIABLE_HEADER *Variable
> + )
> +{
> + if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
> + return FALSE;
> + }
> +
> + return TRUE;
> +}
> +
> +/**
> + This code gets the size of variable header.
> +
> + @param[in] AuthFlag Authenticated variable flag.
> +
> + @return Size of variable header in bytes in type UINTN.
> +
> +**/
> +UINTN
> +GetVariableHeaderSize (
> + IN BOOLEAN AuthFlag
> + )
> +{
> + UINTN Value;
> +
> + if (AuthFlag) {
> + Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
> + } else {
> + Value = sizeof (VARIABLE_HEADER);
> + }
> +
> + return Value;
> +}
> +
> +/**
> + This code gets the size of name of variable.
> +
> + @param[in] Variable Pointer to the Variable Header.
> + @param[in] AuthFlag Authenticated variable flag.
> +
> + @return Size of variable in bytes in type UINTN.
> +
> +**/
> +UINTN
> +NameSizeOfVariable (
> + IN VARIABLE_HEADER *Variable,
> + IN BOOLEAN AuthFlag
> + )
> +{
> + AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
> +
> + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> + if (AuthFlag) {
> + if ((AuthVariable->State == (UINT8)(-1)) ||
> + (AuthVariable->DataSize == (UINT32)(-1)) ||
> + (AuthVariable->NameSize == (UINT32)(-1)) ||
> + (AuthVariable->Attributes == (UINT32)(-1)))
> + {
> + return 0;
> + }
> +
> + return (UINTN)AuthVariable->NameSize;
> + } else {
> + if ((Variable->State == (UINT8)(-1)) ||
> + (Variable->DataSize == (UINT32)(-1)) ||
> + (Variable->NameSize == (UINT32)(-1)) ||
> + (Variable->Attributes == (UINT32)(-1)))
> + {
> + return 0;
> + }
> +
> + return (UINTN)Variable->NameSize;
> + }
> +}
> +
> +/**
> + This code gets the size of data of variable.
> +
> + @param[in] Variable Pointer to the Variable Header.
> + @param[in] AuthFlag Authenticated variable flag.
> +
> + @return Size of variable in bytes in type UINTN.
> +
> +**/
> +UINTN
> +DataSizeOfVariable (
> + IN VARIABLE_HEADER *Variable,
> + IN BOOLEAN AuthFlag
> + )
> +{
> + AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
> +
> + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> + if (AuthFlag) {
> + if ((AuthVariable->State == (UINT8)(-1)) ||
> + (AuthVariable->DataSize == (UINT32)(-1)) ||
> + (AuthVariable->NameSize == (UINT32)(-1)) ||
> + (AuthVariable->Attributes == (UINT32)(-1)))
> + {
> + return 0;
> + }
> +
> + return (UINTN)AuthVariable->DataSize;
> + } else {
> + if ((Variable->State == (UINT8)(-1)) ||
> + (Variable->DataSize == (UINT32)(-1)) ||
> + (Variable->NameSize == (UINT32)(-1)) ||
> + (Variable->Attributes == (UINT32)(-1)))
> + {
> + return 0;
> + }
> +
> + return (UINTN)Variable->DataSize;
> + }
> +}
> +
> +/**
> + This code gets the pointer to the variable name.
> +
> + @param[in] Variable Pointer to the Variable Header.
> + @param[in] AuthFlag Authenticated variable flag.
> +
> + @return A CHAR16* pointer to Variable Name.
> +
> +**/
> +CHAR16 *
> +GetVariableNamePtr (
> + IN VARIABLE_HEADER *Variable,
> + IN BOOLEAN AuthFlag
> + )
> +{
> + return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag));
> +}
> +
> +/**
> + This code gets the pointer to the variable guid.
> +
> + @param[in] Variable Pointer to the Variable Header.
> + @param[in] AuthFlag Authenticated variable flag.
> +
> + @return A EFI_GUID* pointer to Vendor Guid.
> +
> +**/
> +EFI_GUID *
> +GetVendorGuidPtr (
> + IN VARIABLE_HEADER *Variable,
> + IN BOOLEAN AuthFlag
> + )
> +{
> + AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
> +
> + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> + if (AuthFlag) {
> + return &AuthVariable->VendorGuid;
> + } else {
> + return &Variable->VendorGuid;
> + }
> +}
> +
> +/**
> + This code gets the pointer to the variable data.
> +
> + @param[in] Variable Pointer to the Variable Header.
> + @param[in] VariableHeader Pointer to the Variable Header that has
> consecutive content.
> + @param[in] AuthFlag Authenticated variable flag.
> +
> + @return A UINT8* pointer to Variable Data.
> +
> +**/
> +UINT8 *
> +GetVariableDataPtr (
> + IN VARIABLE_HEADER *Variable,
> + IN VARIABLE_HEADER *VariableHeader,
> + IN BOOLEAN AuthFlag
> + )
> +{
> + UINTN Value;
> +
> + //
> + // Be careful about pad size for alignment
> + //
> + Value = (UINTN)GetVariableNamePtr (Variable, AuthFlag);
> + Value += NameSizeOfVariable (VariableHeader, AuthFlag);
> + Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));
> +
> + return (UINT8 *)Value;
> +}
> +
> +/**
> + This code gets the pointer to the next variable header.
> +
> + @param[in] StoreInfo Pointer to variable store info structure.
> + @param[in] Variable Pointer to the Variable Header.
> + @param[in] VariableHeader Pointer to the Variable Header that has
> consecutive content.
> +
> + @return A VARIABLE_HEADER* pointer to next variable header.
> +
> +**/
> +VARIABLE_HEADER *
> +GetNextVariablePtr (
> + IN VARIABLE_STORE_INFO *StoreInfo,
> + IN VARIABLE_HEADER *Variable,
> + IN VARIABLE_HEADER *VariableHeader
> + )
> +{
> + EFI_PHYSICAL_ADDRESS TargetAddress;
> + EFI_PHYSICAL_ADDRESS SpareAddress;
> + UINTN Value;
> +
> + Value = (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo-
> >AuthFlag);
> + Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);
> + Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo-
> >AuthFlag));
> + //
> + // Be careful about pad size for alignment
> + //
> + Value = HEADER_ALIGN (Value);
> +
> + if (StoreInfo->FtwLastWriteData != NULL) {
> + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
> + if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >=
> (UINTN)TargetAddress)) {
> + //
> + // Next variable is in spare block.
> + //
> + Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress);
> + }
> + }
> +
> + return (VARIABLE_HEADER *)Value;
> +}
> +
> +/**
> + Compare two variable names, one of them may be inconsecutive.
> +
> + @param[in] StoreInfo Pointer to variable store info structure.
> + @param[in] Name1 Pointer to one variable name.
> + @param[in] Name2 Pointer to another variable name.
> + @param[in] NameSize Variable name size.
> +
> + @retval TRUE Name1 and Name2 are identical.
> + @retval FALSE Name1 and Name2 are not identical.
> +
> +**/
> +BOOLEAN
> +CompareVariableName (
> + IN VARIABLE_STORE_INFO *StoreInfo,
> + IN CONST CHAR16 *Name1,
> + IN CONST CHAR16 *Name2,
> + IN UINTN NameSize
> + )
> +{
> + EFI_PHYSICAL_ADDRESS TargetAddress;
> + EFI_PHYSICAL_ADDRESS SpareAddress;
> + UINTN PartialNameSize;
> +
> + if (StoreInfo->FtwLastWriteData != NULL) {
> + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
> + if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 +
> NameSize) > (UINTN)TargetAddress)) {
> + //
> + // Name1 is inconsecutive.
> + //
> + PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1;
> + //
> + // Partial content is in NV storage.
> + //
> + if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize) ==
> 0) {
> + //
> + // Another partial content is in spare block.
> + //
> + if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 +
> PartialNameSize, NameSize - PartialNameSize) == 0) {
> + return TRUE;
> + }
> + }
> +
> + return FALSE;
> + } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 +
> NameSize) > (UINTN)TargetAddress)) {
> + //
> + // Name2 is inconsecutive.
> + //
> + PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2;
> + //
> + // Partial content is in NV storage.
> + //
> + if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize) ==
> 0) {
> + //
> + // Another partial content is in spare block.
> + //
> + if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 +
> PartialNameSize, NameSize - PartialNameSize) == 0) {
> + return TRUE;
> + }
> + }
> +
> + return FALSE;
> + }
> + }
> +
> + //
> + // Both Name1 and Name2 are consecutive.
> + //
> + if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + This function compares a variable with variable entries in database.
> +
> + @param[in] StoreInfo Pointer to variable store info structure.
> + @param[in] Variable Pointer to the variable in our database
> + @param[in] VariableHeader Pointer to the Variable Header that has
> + consecutive content.
> + @param[in] VariableName Name of the variable to compare to 'Variable'
> + @param[in] VendorGuid GUID of the variable to compare to 'Variable'
> + @param[out] PtrTrack Variable Track Pointer structure that contains
> + Variable Information.
> +
> + @retval EFI_SUCCESS Found match variable
> + @retval EFI_NOT_FOUND Variable not found
> +
> +**/
> +EFI_STATUS
> +CompareWithValidVariable (
> + IN VARIABLE_STORE_INFO *StoreInfo,
> + IN VARIABLE_HEADER *Variable,
> + IN VARIABLE_HEADER *VariableHeader,
> + IN CONST CHAR16 *VariableName,
> + IN CONST EFI_GUID *VendorGuid,
> + OUT VARIABLE_POINTER_TRACK *PtrTrack
> + )
> +{
> + VOID *Point;
> + EFI_GUID *TempVendorGuid;
> +
> + TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag);
> +
> + if (VariableName[0] == 0) {
> + PtrTrack->CurrPtr = Variable;
> + return EFI_SUCCESS;
> + } else {
> + //
> + // Don't use CompareGuid function here for performance reasons.
> + // Instead we compare the GUID a UINT32 at a time and branch
> + // on the first failed comparison.
> + //
> + if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) &&
> + (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) &&
> + (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) &&
> + (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3])
> + )
> + {
> + ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);
> + Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag);
> + if (CompareVariableName (StoreInfo, VariableName, Point,
> NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {
> + PtrTrack->CurrPtr = Variable;
> + return EFI_SUCCESS;
> + }
> + }
> + }
> +
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> + Get variable header that has consecutive content.
> +
> + @param[in] StoreInfo Pointer to variable store info structure.
> + @param[in] Variable Pointer to the Variable Header.
> + @param[out] VariableHeader Pointer to Pointer to the Variable Header
> + that has consecutive content.
> +
> + @retval TRUE Variable header is valid.
> + @retval FALSE Variable header is not valid.
> +
> +**/
> +BOOLEAN
> +GetVariableHeader (
> + IN VARIABLE_STORE_INFO *StoreInfo,
> + IN VARIABLE_HEADER *Variable,
> + OUT VARIABLE_HEADER **VariableHeader
> + )
> +{
> + EFI_PHYSICAL_ADDRESS TargetAddress;
> + EFI_PHYSICAL_ADDRESS SpareAddress;
> + EFI_HOB_GUID_TYPE *GuidHob;
> + UINTN PartialHeaderSize;
> +
> + if (Variable == NULL) {
> + return FALSE;
> + }
> +
> + //
> + // First assume variable header pointed by Variable is consecutive.
> + //
> + *VariableHeader = Variable;
> +
> + if (StoreInfo->FtwLastWriteData != NULL) {
> + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
> + if (((UINTN)Variable > (UINTN)SpareAddress) &&
> + (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >=
> (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader)))
> + {
> + //
> + // Reach the end of variable store.
> + //
> + return FALSE;
> + }
> +
> + if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable +
> GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) {
> + //
> + // Variable header pointed by Variable is inconsecutive,
> + // create a guid hob to combine the two partial variable header content
> together.
> + //
> + GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
> + if (GuidHob != NULL) {
> + *VariableHeader = (VARIABLE_HEADER *)GET_GUID_HOB_DATA
> (GuidHob);
> + } else {
> + *VariableHeader = (VARIABLE_HEADER *)BuildGuidHob
> (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag));
> + PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable;
> + //
> + // Partial content is in NV storage.
> + //
> + CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable,
> PartialHeaderSize);
> + //
> + // Another partial content is in spare block.
> + //
> + CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8
> *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) -
> PartialHeaderSize);
> + }
> + }
> + } else {
> + if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
> + //
> + // Reach the end of variable store.
> + //
> + return FALSE;
> + }
> + }
> +
> + return IsValidVariableHeader (*VariableHeader);
> +}
> +
> +/**
> + Get variable name or data to output buffer.
> +
> + @param[in] StoreInfo Pointer to variable store info structure.
> + @param[in] NameOrData Pointer to the variable name/data that may be
> inconsecutive.
> + @param[in] Size Variable name/data size.
> + @param[out] Buffer Pointer to output buffer to hold the variable
> name/data.
> +
> +**/
> +VOID
> +GetVariableNameOrData (
> + IN VARIABLE_STORE_INFO *StoreInfo,
> + IN UINT8 *NameOrData,
> + IN UINTN Size,
> + OUT UINT8 *Buffer
> + )
> +{
> + EFI_PHYSICAL_ADDRESS TargetAddress;
> + EFI_PHYSICAL_ADDRESS SpareAddress;
> + UINTN PartialSize;
> +
> + if (StoreInfo->FtwLastWriteData != NULL) {
> + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
> + if (((UINTN)NameOrData < (UINTN)TargetAddress) &&
> (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) {
> + //
> + // Variable name/data is inconsecutive.
> + //
> + PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData;
> + //
> + // Partial content is in NV storage.
> + //
> + CopyMem (Buffer, NameOrData, PartialSize);
> + //
> + // Another partial content is in spare block.
> + //
> + CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size -
> PartialSize);
> + return;
> + }
> + }
> +
> + //
> + // Variable name/data is consecutive.
> + //
> + CopyMem (Buffer, NameOrData, Size);
> +}
> +
> +/**
> +
> + Internal function to retrieve variable information.
> +
> + @param[in,out] VariableInfo Pointer to variable information.
> + @param[in] StoreInfo Pointer to store copy of variable (optional).
> + @param[in] VariablePtr Pointer to variable buffer.
> + @param[in] VariableHeader Pointer to variable header.
> +
> + @retval EFI_INVALID_PARAMETER One ore more required parameters are
> NULL.
> + @retval EFI_BUFFER_TOO_SMALL Given buffer is too small to hold data.
> + @retval EFI_SUCCESS Variable details are retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetVariableInfoInternal (
> + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo,
> + IN VARIABLE_STORE_INFO *StoreInfo OPTIONAL,
> + IN VARIABLE_HEADER *VariablePtr,
> + IN VARIABLE_HEADER *VariableHeader
> + )
> +{
> + VARIABLE_HEADER *VariableBuffer;
> + AUTHENTICATED_VARIABLE_HEADER *AuthVariableHeader;
> + UINTN NameSize;
> + UINTN DataSize;
> + UINTN VariableSize;
> +
> + if ((VariableInfo == NULL) || (VariablePtr == NULL) || (VariableHeader ==
> NULL)) {
> + ASSERT (VariableInfo != NULL);
> + ASSERT (VariablePtr != NULL);
> + ASSERT (VariableHeader != NULL);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + VariableBuffer = VariableInfo->Buffer;
> +
> + //
> + // Make a copy of the whole variable if VariableInfo->Buffer is given. But
> + // don't do this if StoreInfo is not given, because VariableInfo->Buffer
> + // has already hold a copy of variable in such situation.
> + //
> + NameSize = NameSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
> + DataSize = DataSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
> + if ((VariableBuffer != NULL) && (VariableBuffer != VariablePtr)) {
> + if (StoreInfo != NULL) {
> + CopyMem (
> + VariableBuffer,
> + VariableHeader,
> + GetVariableHeaderSize (VariableInfo->Flags.Auth)
> + );
> + GetVariableNameOrData (
> + StoreInfo,
> + (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
> + NameSize,
> + (UINT8 *)GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth)
> + );
> + GetVariableNameOrData (
> + StoreInfo,
> + (UINT8 *)GetVariableDataPtr (VariablePtr, VariableHeader, VariableInfo-
> >Flags.Auth),
> + DataSize,
> + (UINT8 *)GetVariableDataPtr (VariableBuffer, VariableHeader,
> VariableInfo->Flags.Auth)
> + );
> + } else {
> + //
> + // Suppose the variable is in consecutive space.
> + //
> + VariableSize = GetVariableHeaderSize (VariableInfo->Flags.Auth)
> + + NameSize + GET_PAD_SIZE (NameSize)
> + + DataSize;
> + CopyMem (VariableBuffer, VariablePtr, VariableSize);
> + }
> + }
> +
> + //
> + // Generally, if no consecutive buffer passed in, don't return back any data.
> + //
> + // If follow pointers are NULL, return back pointers to following data inside
> + // VariableInfo->Buffer, if it's given.
> + //
> + // VariableInfo->Header.VariableName
> + // VariableInfo->Header.Data
> + // VariableInfo->Header.VendorGuid
> + // VariableInfo->Header.TimeStamp
> + //
> + // Otherwise, suppose they're buffers used to hold a copy of corresponding
> + // data.
> + //
> + //
> +
> + //
> + // AuthVariable header
> + //
> + if (VariableInfo->Flags.Auth) {
> + AuthVariableHeader = (AUTHENTICATED_VARIABLE_HEADER
> *)VariableHeader;
> +
> + VariableInfo->Header.State = AuthVariableHeader->State;
> + VariableInfo->Header.Attributes = AuthVariableHeader->Attributes;
> + VariableInfo->Header.PubKeyIndex = AuthVariableHeader->PubKeyIndex;
> + VariableInfo->Header.MonotonicCount = ReadUnaligned64 (
> + &(AuthVariableHeader->MonotonicCount)
> + );
> + if (VariableInfo->Header.TimeStamp != NULL) {
> + CopyMem (
> + VariableInfo->Header.TimeStamp,
> + &AuthVariableHeader->TimeStamp,
> + sizeof (EFI_TIME)
> + );
> + } else if (VariableBuffer != NULL) {
> + AuthVariableHeader = (AUTHENTICATED_VARIABLE_HEADER
> *)VariableBuffer;
> + VariableInfo->Header.TimeStamp = &AuthVariableHeader->TimeStamp;
> + }
> + } else {
> + VariableInfo->Header.State = VariableHeader->State;
> + VariableInfo->Header.Attributes = VariableHeader->Attributes;
> + VariableInfo->Header.PubKeyIndex = 0;
> + VariableInfo->Header.MonotonicCount = 0;
> + VariableInfo->Header.TimeStamp = NULL;
> + }
> +
> + //
> + // VendorGuid
> + //
> + if (VariableInfo->Header.VendorGuid != NULL) {
> + CopyGuid (
> + VariableInfo->Header.VendorGuid,
> + GetVendorGuidPtr (VariableHeader, VariableInfo->Flags.Auth)
> + );
> + } else if (VariableBuffer != NULL) {
> + VariableInfo->Header.VendorGuid
> + = GetVendorGuidPtr (VariableBuffer, VariableInfo->Flags.Auth);
> + }
> +
> + //
> + // VariableName
> + //
> + if ( (VariableInfo->Header.VariableName != NULL)
> + && (VariableInfo->Header.NameSize >= NameSize))
> + {
> + GetVariableNameOrData (
> + StoreInfo,
> + (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
> + NameSize,
> + (UINT8 *)VariableInfo->Header.VariableName
> + );
> + } else if (VariableBuffer != NULL) {
> + VariableInfo->Header.VariableName
> + = GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth);
> + } else if (VariableInfo->Header.VariableName != NULL) {
> + return EFI_BUFFER_TOO_SMALL;
> + }
> +
> + //
> + // Data
> + //
> + if ( (VariableInfo->Header.Data != NULL)
> + && (VariableInfo->Header.DataSize >= DataSize))
> + {
> + GetVariableNameOrData (
> + StoreInfo,
> + GetVariableDataPtr (VariablePtr, VariableHeader, StoreInfo->AuthFlag),
> + DataSize,
> + VariableInfo->Header.Data
> + );
> + } else if (VariableBuffer != NULL) {
> + VariableInfo->Header.Data
> + = GetVariableDataPtr (VariableBuffer, VariableBuffer, VariableInfo-
> >Flags.Auth);
> + } else if (VariableInfo->Header.Data != NULL) {
> + return EFI_BUFFER_TOO_SMALL;
> + }
> +
> + //
> + // Update size information about name & data.
> + //
> + VariableInfo->Header.NameSize = NameSize;
> + VariableInfo->Header.DataSize = DataSize;
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> +
> + Retrieve details about a variable, given by VariableInfo->Buffer or
> + VariableInfo->Index, and pass the details back in VariableInfo->Header.
> +
> + This function is used to resolve the variable data structure into
> + VariableInfo->Header, for easier access later without revisiting the variable
> + data in variable store. If pointers in the structure of VariableInfo->Header
> + are not NULL, it's supposed that they are buffers passed in to hold a copy of
> + data of corresponding data fields in variable data structure. Otherwise, this
> + function simply returns pointers pointing to address of those data fields.
> +
> + The variable is specified by either VariableInfo->Index or VariableInfo->Buffer.
> + If VariableInfo->Index is given, this function finds the corresponding variable
> + first from variable storage according to the Index.
> +
> + If both VariableInfo->Index and VariableInfo->Buffer are given, it's supposed
> + that VariableInfo->Buffer is a buffer passed in to hold a whole copy of
> + requested variable data to be returned.
> +
> + @param[in,out] VariableInfo Pointer to variable information.
> +
> + @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo-
> >Buffer
> + and VariableInfo->Index are NULL (0).
> + @retval EFI_NOT_FOUND If given Buffer or Index is out of range of
> + any given or internal storage copies.
> + @retval EFI_SUCCESS Variable details are retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetVariableInfo (
> + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
> + )
> +{
> + VARIABLE_HEADER *VariablePtr;
> + VARIABLE_HEADER *VariableHeader;
> + VARIABLE_STORE_TYPE StoreType;
> + VARIABLE_STORE_INFO StoreInfo;
> + UINTN Offset;
> +
> + if ((VariableInfo == NULL) ||
> + ((VariableInfo->Buffer == NULL) && (VariableInfo->StoreIndex ==
> VAR_INDEX_INVALID)))
> + {
> + ASSERT (VariableInfo != NULL);
> + ASSERT (VariableInfo->StoreIndex != VAR_INDEX_INVALID || VariableInfo-
> >Buffer != NULL);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + StoreInfo.VariableStoreHeader = NULL;
> + for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax;
> ++StoreType) {
> + GetVariableStore (StoreType, &StoreInfo);
> + if (StoreInfo.VariableStoreHeader != NULL) {
> + break;
> + }
> + }
> +
> + ASSERT (StoreInfo.VariableStoreHeader != NULL);
> +
> + //
> + // No StoreIndex? Don't retrieve variable information from store but just from
> + // VariableInfo->Buffer.
> + //
> + if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
> + VariablePtr = VariableInfo->Buffer;
> + VariableHeader = VariablePtr;
> +
> + return GetVariableInfoInternal (VariableInfo, NULL, VariablePtr,
> VariableHeader);
> + }
> +
> + Offset = (UINTN)VariableInfo->StoreIndex;
> + if ( (StoreInfo.FtwLastWriteData != NULL)
> + && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> + - (UINTN)StoreInfo.VariableStoreHeader)))
> + {
> + Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> + - (UINTN)StoreInfo.VariableStoreHeader);
> + VariablePtr = (VARIABLE_HEADER *)
> + ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
> + } else {
> + VariablePtr = (VARIABLE_HEADER *)
> + ((UINTN)StoreInfo.VariableStoreHeader + Offset);
> + }
> +
> + //
> + // Note that variable might be in unconsecutive space. Always get a copy
> + // of its header in consecutive buffer.
> + //
> + if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
> + return EFI_NOT_FOUND;
> + }
> +
> + return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr,
> VariableHeader);
> +}
> +
> +/**
> +
> + Retrieve details of the variable next to given variable within VariableStore.
> +
> + If VarInfo->Buffer is NULL, the first one in VariableStore is returned.
> +
> + VariableStart and/or VariableEnd can be given optionally for the situation
> + in which the valid storage space is smaller than the VariableStore->Size.
> + This usually happens when PEI variable services make a compact variable
> + cache to save memory, which cannot make use VariableStore->Size to
> determine
> + the correct variable storage range.
> +
> + @param[in,out] VariableInfo Pointer to variable information.
> +
> + @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL.
> + @retval EFI_NOT_FOUND If the end of VariableStore is reached.
> + @retval EFI_SUCCESS The next variable is retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetNextVariableInfo (
> + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
> + )
> +{
> + VARIABLE_HEADER *VariablePtr;
> + VARIABLE_HEADER *VariableHeader;
> + VARIABLE_STORE_INFO StoreInfo;
> + VARIABLE_STORE_TYPE StoreType;
> + UINTN Offset;
> +
> + if (VariableInfo == NULL) {
> + ASSERT (VariableInfo != NULL);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + StoreInfo.VariableStoreHeader = NULL;
> + for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax;
> ++StoreType) {
> + GetVariableStore (StoreType, &StoreInfo);
> + if (StoreInfo.VariableStoreHeader != NULL) {
> + break;
> + }
> + }
> +
> + ASSERT (StoreInfo.VariableStoreHeader != NULL);
> +
> + //
> + // VariableInfo->StoreIndex is supposed to be the index to variable found
> + // last time. Use it to get the variable next to it in store. If it's invalid,
> + // return the first variable available in store.
> + //
> + VariableInfo->Flags.Auth = StoreInfo.AuthFlag;
> + if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
> + VariablePtr = GetStartPointer (StoreInfo.VariableStoreHeader);
> + } else {
> + Offset = (UINTN)VariableInfo->StoreIndex;
> + if ( (StoreInfo.FtwLastWriteData != NULL)
> + && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> + - (UINTN)StoreInfo.VariableStoreHeader)))
> + {
> + Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> + - (UINTN)StoreInfo.VariableStoreHeader);
> + VariablePtr = (VARIABLE_HEADER *)
> + ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
> + } else {
> + VariablePtr = (VARIABLE_HEADER *)
> + ((UINTN)StoreInfo.VariableStoreHeader + Offset);
> + }
> +
> + //
> + // Note that variable might be in unconsecutive space. Always get a copy
> + // of its header in consecutive buffer.
> + //
> + if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
> + return EFI_NOT_FOUND;
> + }
> +
> + VariablePtr = GetNextVariablePtr (&StoreInfo, VariablePtr, VariableHeader);
> + }
> +
> + //
> + // Get a copy of variable header in consecutive buffer.
> + //
> + if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
> + return EFI_NOT_FOUND;
> + }
> +
> + //
> + // Use the offset to the start of variable store as index of the variable.
> + //
> + if ( (StoreInfo.FtwLastWriteData == NULL)
> + || ((UINTN)VariablePtr < (UINTN)StoreInfo.FtwLastWriteData-
> >TargetAddress))
> + {
> + VariableInfo->StoreIndex
> + = (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.VariableStoreHeader);
> + } else {
> + VariableInfo->StoreIndex
> + = (UINT64)((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> + - (UINTN)StoreInfo.VariableStoreHeader);
> + VariableInfo->StoreIndex
> + += (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.FtwLastWriteData-
> >SpareAddress);
> + }
> +
> + if ((StoreType == VariableStoreTypeHob) && (VariableInfo->Buffer == NULL)) {
> + VariableInfo->Buffer = VariablePtr;
> + }
> +
> + return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr,
> VariableHeader);
> +}
> diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableStore.c
> b/MdeModulePkg/Universal/Variable/Pei/VariableStore.c
> new file mode 100644
> index 000000000000..72bd17a43048
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Pei/VariableStore.c
> @@ -0,0 +1,305 @@
> +/** @file
> + Implement ReadOnly Variable Services required by PEIM and install
> + PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage
> space.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "VariableParsing.h"
> +#include "VariableStore.h"
> +
> +/**
> + Get variable store status.
> +
> + @param[in] VarStoreHeader Pointer to the Variable Store Header.
> +
> + @retval EfiRaw Variable store is raw
> + @retval EfiValid Variable store is valid
> + @retval EfiInvalid Variable store is invalid
> +
> +**/
> +VARIABLE_STORE_STATUS
> +GetVariableStoreStatus (
> + IN VARIABLE_STORE_HEADER *VarStoreHeader
> + )
> +{
> + if ((CompareGuid (&VarStoreHeader->Signature,
> &gEfiAuthenticatedVariableGuid) ||
> + CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
> + (VarStoreHeader->Format == VARIABLE_STORE_FORMATTED) &&
> + (VarStoreHeader->State == VARIABLE_STORE_HEALTHY)
> + )
> + {
> + return EfiValid;
> + }
> +
> + if ((((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff) &&
> + (((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff) &&
> + (((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff) &&
> + (((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff) &&
> + (VarStoreHeader->Size == 0xffffffff) &&
> + (VarStoreHeader->Format == 0xff) &&
> + (VarStoreHeader->State == 0xff)
> + )
> + {
> + return EfiRaw;
> + } else {
> + return EfiInvalid;
> + }
> +}
> +
> +/**
> + Reports HOB variable store is available or not.
> +
> + @retval EFI_NOT_READY HOB variable store info not available.
> + @retval EFI_NOT_FOUND HOB variable store is NOT available.
> + @retval EFI_SUCCESS HOB variable store is available.
> +**/
> +EFI_STATUS
> +EFIAPI
> +IsHobVariableStoreAvailable (
> + VOID
> + )
> +{
> + EFI_HOB_GUID_TYPE *GuidHob;
> + VOID *VariableStoreInfoHob;
> +
> + //
> + // Discover if Variable Store Info Hob has been published by platform driver.
> + // It contains information regards to HOB or NV Variable Store availability
> + //
> + GuidHob = GetFirstGuidHob (&gEfiPeiVariableStoreDiscoveredPpiGuid);
> + if (GuidHob == NULL) {
> + return EFI_NOT_READY;
> + }
> +
> + //
> + // Check if HOB Variable Store is available
> + //
> + VariableStoreInfoHob = GET_GUID_HOB_DATA (GuidHob);
> + if (*(BOOLEAN *)VariableStoreInfoHob == TRUE) {
[JianJW]
What's the scenario in which *(BOOLEAN *)VariableStoreInfoHob equals FALSE?
Which case the VariableStoreInfoHob is generated but HOB variable store available?
Is it possible to simply use VariableStoreDiscoveredPpi notify callback only? Then
you can just check HOB(gEfiAuthenticatedVariableGuid) or HOB(gEfiVariableGuid)
to confirm if the HOB version of variable store is available now.
> + return EFI_SUCCESS;
> + }
> +
> + //
> + // This might be NV Variable Store
> + //
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> + Get HOB variable store.
> +
> + @param[out] StoreInfo Return the store info.
> +
> +**/
> +VOID
> +GetHobVariableStore (
> + OUT VARIABLE_STORE_INFO *StoreInfo
> + )
> +{
> + EFI_HOB_GUID_TYPE *GuidHob;
> +
> + //
> + // Make sure there is no more than one Variable HOB.
> + //
> + DEBUG_CODE_BEGIN ();
> + GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
> + if (GuidHob != NULL) {
> + if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB
> (GuidHob)) != NULL)) {
> + DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
> + ASSERT (FALSE);
> + } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
> + DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable
> HOBs\n"));
> + ASSERT (FALSE);
> + }
> + } else {
> + GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
> + if (GuidHob != NULL) {
> + if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) !=
> NULL)) {
> + DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
> + ASSERT (FALSE);
> + }
> + }
> + }
> +
> + DEBUG_CODE_END ();
> +
> + GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
> + if (GuidHob != NULL) {
> + StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER
> *)GET_GUID_HOB_DATA (GuidHob);
> + StoreInfo->AuthFlag = TRUE;
> + } else {
> + GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
> + if (GuidHob != NULL) {
> + StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER
> *)GET_GUID_HOB_DATA (GuidHob);
> + StoreInfo->AuthFlag = FALSE;
> + }
> + }
> +}
> +
> +/**
> + Get NV variable store.
> +
> + @param[out] StoreInfo Return the store info.
> + @param[out] VariableFvHeader Return header of FV containing the store.
> +
> +**/
> +VOID
> +GetNvVariableStore (
> + OUT VARIABLE_STORE_INFO *StoreInfo,
> + OUT EFI_FIRMWARE_VOLUME_HEADER **VariableFvHeader
> + )
> +{
> + EFI_HOB_GUID_TYPE *GuidHob;
> + EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
> + VARIABLE_STORE_HEADER *StoreHeader;
> + FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *HobData;
> + FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
> + EFI_PHYSICAL_ADDRESS NvStorageBase;
> + UINT32 NvStorageSize;
> + UINT32 BackUpOffset;
> +
> + NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
> + NvStorageBase = (EFI_PHYSICAL_ADDRESS)
> + (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0)
> + ? PcdGet64 (PcdFlashNvStorageVariableBase64)
> + : PcdGet32 (PcdFlashNvStorageVariableBase);
> + ASSERT (NvStorageBase != 0);
> +
> + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase;
> +
> + //
> + // Check the FTW last write data hob.
> + //
> + BackUpOffset = 0;
> + FtwLastWriteData = NULL;
> + HobData = NULL;
> + GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
> +
> + if (GuidHob != NULL) {
> + HobData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
> *)GET_GUID_HOB_DATA (GuidHob);
> + if (HobData->TargetAddress == NvStorageBase) {
> + //
> + // Let FvHeader point to spare block.
> + //
> + DEBUG ((
> + EFI_D_INFO,
> + "PeiVariable: NV storage is backed up in spare block: 0x%x\n",
> + (UINTN)HobData->SpareAddress
> + ));
> +
> + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)HobData-
> >SpareAddress;
> + HobData = NULL;
> + } else if ((HobData->TargetAddress > NvStorageBase) &&
> + (HobData->TargetAddress < (NvStorageBase + NvStorageSize)))
> + {
> + //
> + // Flash NV storage from the offset is backed up in spare block.
> + //
> + BackUpOffset = (UINT32)(HobData->TargetAddress - NvStorageBase);
> + DEBUG ((
> + EFI_D_INFO,
> + "PeiVariable: High partial NV storage from offset: %x is backed up in spare
> block: 0x%x\n",
> + BackUpOffset,
> + (UINTN)FtwLastWriteData->SpareAddress
> + ));
> + //
> + // At least one block data in flash NV storage is still valid, so still
> + // leave FvHeader point to NV storage base.
> + //
> + }
> + }
> +
> + if (StoreInfo != NULL) {
> + StoreInfo->FtwLastWriteData = HobData;
> + }
> +
> + if (VariableFvHeader != NULL) {
> + *VariableFvHeader = FvHeader;
> + }
> +
> + //
> + // Check if the Firmware Volume is not corrupted
> + //
> + if ((FvHeader->Signature == EFI_FVH_SIGNATURE) &&
> + CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))
[JianJW] It'd be better also validate the FvHeader->HeaderLength, to make sure
StoreHeader is in the valid area.
> + {
> + StoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)FvHeader + FvHeader-
> >HeaderLength);
> + } else {
> + StoreHeader = NULL;
> + DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is
> corrupted\n"));
> + }
> +
> + if (StoreInfo != NULL) {
> + StoreInfo->VariableStoreHeader = StoreHeader;
> + if (StoreHeader != NULL) {
> + StoreInfo->AuthFlag = CompareGuid (
> + &StoreHeader->Signature,
> + &gEfiAuthenticatedVariableGuid
> + );
> + }
> + }
> +}
> +
> +/**
> + Return the variable store header and the store info based on the Index.
> +
> + @param[in] Type The type of the variable store.
> + @param[out] StoreInfo Return the store info.
> +
> + @return Pointer to the variable store header.
> +**/
> +VARIABLE_STORE_HEADER *
> +GetVariableStore (
> + IN VARIABLE_STORE_TYPE Type,
> + OUT VARIABLE_STORE_INFO *StoreInfo
> + )
> +{
> + EFI_HOB_GUID_TYPE *GuidHob;
> +
> + StoreInfo->VariableStoreHeader = NULL;
> + StoreInfo->IndexTable = NULL;
> + StoreInfo->FtwLastWriteData = NULL;
> + StoreInfo->AuthFlag = FALSE;
> + switch (Type) {
> + case VariableStoreTypeHob:
> + GetHobVariableStore (StoreInfo);
> + break;
> +
> + case VariableStoreTypeNv:
> + if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
> + //
> + // Emulated non-volatile variable mode is not enabled.
> + //
> + GetNvVariableStore (StoreInfo, NULL);
> + if (StoreInfo->VariableStoreHeader != NULL) {
> + GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
> + if (GuidHob != NULL) {
> + StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
> + } else {
> + //
> + // If it's the first time to access variable region in flash, create a guid hob
> to record
> + // VAR_ADDED type variable info.
> + // Note that as the resource of PEI phase is limited, only store the
> limited number of
> + // VAR_ADDED type variables to reduce access time.
> + //
> + StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE
> *)BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
> + StoreInfo->IndexTable->Length = 0;
> + StoreInfo->IndexTable->StartPtr = GetStartPointer (StoreInfo-
> >VariableStoreHeader);
> + StoreInfo->IndexTable->EndPtr = GetEndPointer (StoreInfo-
> >VariableStoreHeader);
> + StoreInfo->IndexTable->GoneThrough = 0;
> + }
> + }
> + }
> +
> + break;
> +
> + default:
> + ASSERT (FALSE);
> + break;
> + }
> +
> + return StoreInfo->VariableStoreHeader;
> +}
> --
> 2.35.1.windows.2
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [Patch v2 09/28] MdeModulePkg: Add support for Protected Variables
2022-04-29 18:04 ` [Patch v2 09/28] MdeModulePkg: Add support for Protected Variables Judah Vang
@ 2022-05-22 14:03 ` Wang, Jian J
0 siblings, 0 replies; 49+ messages in thread
From: Wang, Jian J @ 2022-05-22 14:03 UTC (permalink / raw)
To: Vang, Judah, devel@edk2.groups.io; +Cc: Gao, Liming, Mistry, Nishant C
Judah,
See my inline comments below.
Regards,
Jian
> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Saturday, April 30, 2022 2:04 AM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [Patch v2 09/28] MdeModulePkg: Add support for Protected Variables
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> Add support for Protected Variables.
> Add new API to retrieve Variable Infomation and data.
> Add new API to update variable in non-volatile storage or
> cached copy.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf | 3
> +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf | 3 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf |
> 4 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf |
> 3 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h | 126 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h | 91 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c | 349 +++-
> MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c | 2139
> +++++++++++---------
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c | 26 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c | 167 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c | 194
> +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c | 320
> ++-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c |
> 2 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c | 39 +-
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c |
> 41 +-
> 15 files changed, 2454 insertions(+), 1053 deletions(-)
>
> diff --git
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> index c9434df631ee..c0b90e6ca066 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> @@ -9,7 +9,7 @@
> # This external input must be validated carefully to avoid security issues such as
> # buffer overflow or integer overflow.
> #
> -# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> # Copyright (c) Microsoft Corporation.
> # SPDX-License-Identifier: BSD-2-Clause-Patent
> #
> @@ -73,6 +73,7 @@ [LibraryClasses]
> VarCheckLib
> VariablePolicyLib
> VariablePolicyHelperLib
> + ProtectedVariableLib
>
> [Protocols]
> gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES
> diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
> index eaa97a01c6e5..6f9f027fbb0f 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
> @@ -18,7 +18,7 @@
> # may not be modified without authorization. If platform fails to protect these
> resources,
> # the authentication service provided in this driver will be broken, and the
> behavior is undefined.
> #
> -# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
> # Copyright (c) Microsoft Corporation.
> # SPDX-License-Identifier: BSD-2-Clause-Patent
> #
> @@ -82,6 +82,7 @@ [LibraryClasses]
> UefiBootServicesTableLib
> VariablePolicyLib
> VariablePolicyHelperLib
> + ProtectedVariableLib
>
> [Protocols]
> gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES
> diff --git
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
> index a0d8b2267e92..5d2fc78ea917 100644
> ---
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
> +++
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
> @@ -13,7 +13,7 @@
> # may not be modified without authorization. If platform fails to protect these
> resources,
> # the authentication service provided in this driver will be broken, and the
> behavior is undefined.
> #
> -# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
> # Copyright (c) Microsoft Corporation.<BR>
> # SPDX-License-Identifier: BSD-2-Clause-Patent
> #
> @@ -61,6 +61,8 @@ [LibraryClasses]
> SafeIntLib
> PcdLib
> MmUnblockMemoryLib
> + ProtectedVariableLib
> + IoLib
[JianJW]
Why's IoLib needed here? I didn't find any of its interfaces used in this patch.
>
> [Protocols]
> gEfiVariableWriteArchProtocolGuid ## PRODUCES
> diff --git
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
> index d8c4f77e7f1f..6ea7b8d4293e 100644
> ---
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
> +++
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
> @@ -18,7 +18,7 @@
> # may not be modified without authorization. If platform fails to protect these
> resources,
> # the authentication service provided in this driver will be broken, and the
> behavior is undefined.
> #
> -# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
> # Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
> # Copyright (c) Microsoft Corporation.
> # SPDX-License-Identifier: BSD-2-Clause-Patent
> @@ -78,6 +78,7 @@ [LibraryClasses]
> VarCheckLib
> VariablePolicyLib
> VariablePolicyHelperLib
> + ProtectedVariableLib
>
> [Protocols]
> gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES
> diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
> index 31e408976a35..97b4f9c906ff 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
> @@ -2,7 +2,7 @@
> The internal header file includes the common header files, defines
> internal structure and functions used by Variable modules.
>
> -Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> **/
> @@ -31,6 +31,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> #include <Library/MemoryAllocationLib.h>
> #include <Library/AuthVariableLib.h>
> #include <Library/VarCheckLib.h>
> +#include <Library/ProtectedVariableLib.h>
> #include <Guid/GlobalVariable.h>
> #include <Guid/EventGroup.h>
> #include <Guid/VariableFormat.h>
> @@ -823,4 +824,127 @@ VariableExLibAtRuntime (
> VOID
> );
>
> +/**
> + Is user variable?
> +
> + @param[in] Variable Pointer to variable header.
> +
> + @retval TRUE User variable.
> + @retval FALSE System variable.
> +
> +**/
> +BOOLEAN
> +IsUserVariable (
> + IN VARIABLE_HEADER *Variable
> + );
> +
> +/**
> +
> + Variable store garbage collection and reclaim operation.
> +
> + @param[in] VariableBase Base address of variable store.
> + @param[out] LastVariableOffset Offset of last variable.
> + @param[in] IsVolatile The variable store is volatile or not;
> + if it is non-volatile, need FTW.
> + @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer
> track structure.
> + @param[in] NewVariable Pointer to new variable.
> + @param[in] NewVariableSize New variable size.
> +
> + @return EFI_SUCCESS Reclaim operation has finished successfully.
> + @return EFI_OUT_OF_RESOURCES No enough memory resources or
> variable space.
> + @return Others Unexpect error happened during reclaim
> operation.
> +
> +**/
> +EFI_STATUS
> +Reclaim (
> + IN EFI_PHYSICAL_ADDRESS VariableBase,
> + OUT UINTN *LastVariableOffset,
> + IN BOOLEAN IsVolatile,
> + IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
> + IN VARIABLE_HEADER *NewVariable,
> + IN UINTN NewVariableSize
> + );
> +
> +/**
> +
> + This function writes data to the FWH at the correct LBA even if the LBAs
> + are fragmented.
> +
> + @param Global Pointer to VARIABLE_GLOBAL structure.
> + @param Volatile Point out the Variable is Volatile or Non-Volatile.
> + @param SetByIndex TRUE if target pointer is given as index.
> + FALSE if target pointer is absolute.
> + @param Fvb Pointer to the writable FVB protocol.
> + @param DataPtrIndex Pointer to the Data from the end of
> VARIABLE_STORE_HEADER
> + structure.
> + @param DataSize Size of data to be written.
> + @param Buffer Pointer to the buffer from which data is written.
> +
> + @retval EFI_INVALID_PARAMETER Parameters not valid.
> + @retval EFI_UNSUPPORTED Fvb is a NULL for Non-Volatile variable
> update.
> + @retval EFI_OUT_OF_RESOURCES The remaining size is not enough.
> + @retval EFI_SUCCESS Variable store successfully updated.
> +
> +**/
> +EFI_STATUS
> +UpdateVariableStore (
> + IN VARIABLE_GLOBAL *Global,
> + IN BOOLEAN Volatile,
> + IN BOOLEAN SetByIndex,
> + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
> + IN UINTN DataPtrIndex,
> + IN UINT32 DataSize,
> + IN UINT8 *Buffer
> + );
> +
> +/**
> + Update partial data of a variable on NV storage and/or cached copy.
> +
> + @param[in] VariableInfo Pointer to a variable with detailed information.
> + @param[in] Offset Offset to write from.
> + @param[in] Size Size of data Buffer to update.
> + @param[in] Buffer Pointer to data buffer to update.
> +
> + @retval EFI_SUCCESS The variable data was updated successfully.
> + @retval EFI_UNSUPPORTED If this function is called directly in runtime.
> + @retval EFI_INVALID_PARAMETER If VariableInfo, Buffer or Size are not
> valid.
> + @retval Others Failed to update NV storage or variable cache.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +VariableExLibUpdateNvVariable (
> + IN PROTECTED_VARIABLE_INFO *VariableInfo,
> + IN UINTN Offset,
> + IN UINT32 Size,
> + IN UINT8 *Buffer
> + );
> +
> +/**
> + Finds the given variable in a variable store in SMM.
> +
> + Caution: This function may receive untrusted input.
> + The data size is external input, so this function will validate it carefully to
> avoid buffer overflow.
> +
> + @param[in] VariableName Name of Variable to be found.
> + @param[in] VendorGuid Variable vendor GUID.
> + @param[out] Attributes Attribute value of the variable found.
> + @param[in, out] DataSize Size of Data found. If size is less than the
> + data, this value contains the required size.
> + @param[out] Data Data pointer.
> +
> + @retval EFI_SUCCESS Found the specified variable.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_NOT_FOUND The specified variable could not be found.
> +
> +**/
> +EFI_STATUS
> +FindVariableInSmm (
> + IN CHAR16 *VariableName,
> + IN EFI_GUID *VendorGuid,
> + OUT UINT32 *Attributes OPTIONAL,
> + IN OUT UINTN *DataSize,
> + OUT VOID *Data OPTIONAL
> + );
> +
> #endif
> diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
> index 951e8a089e34..3a4e8019aaf9 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
> @@ -2,7 +2,7 @@
> Functions in this module are associated with variable parsing operations and
> are intended to be usable across variable driver source files.
>
> -Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> **/
> @@ -19,6 +19,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>
> @param[in] Variable Pointer to the Variable Header.
> @param[in] VariableStoreEnd Pointer to the Variable Store End.
> + @param[in] AuthFormat Auth-variable indicator.
>
> @retval TRUE Variable header is valid.
> @retval FALSE Variable header is not valid.
> @@ -27,7 +28,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> BOOLEAN
> IsValidVariableHeader (
> IN VARIABLE_HEADER *Variable,
> - IN VARIABLE_HEADER *VariableStoreEnd
> + IN VARIABLE_HEADER *VariableStoreEnd,
> + IN BOOLEAN AuthFormat
> );
>
> /**
> @@ -192,6 +194,28 @@ GetVariableDataOffset (
> IN BOOLEAN AuthFormat
> );
>
> +/**
> + Get variable data payload.
> +
> + @param[in] Variable Pointer to the Variable Header.
> + @param[out] Data Pointer to buffer used to store the variable data.
> + @param[in] DataSize Size of buffer passed by Data.
> + @param[out] DataSize Size of data copied into Data buffer.
> + @param[in] AuthFlag Auth-variable indicator.
> +
> + @return EFI_SUCCESS Data was fetched.
> + @return EFI_INVALID_PARAMETER DataSize is NULL.
> + @return EFI_BUFFER_TOO_SMALL DataSize is smaller than size of variable
> data.
> +
> +**/
> +EFI_STATUS
> +GetVariableData (
> + IN VARIABLE_HEADER *Variable,
> + IN OUT VOID *Data,
> + IN OUT UINT32 *DataSize,
> + IN BOOLEAN AuthFlag
> + );
> +
> /**
>
> This code gets the pointer to the next variable header.
> @@ -344,4 +368,67 @@ UpdateVariableInfo (
> IN OUT VARIABLE_INFO_ENTRY **VariableInfo
> );
>
> +/**
> +
> + Retrieve details of the variable next to given variable within VariableStore.
> +
> + If VarInfo->Address is NULL, the first one in VariableStore is returned.
> +
> + VariableStart and/or VariableEnd can be given optionally for the situation
> + in which the valid storage space is smaller than the VariableStore->Size.
> + This usually happens when PEI variable services make a compact variable
> + cache to save memory, which cannot make use VariableStore->Size to
> determine
> + the correct variable storage range.
> +
> + @param VariableStore Pointer to a variable storage. It's optional.
> + @param VariableStart Start point of valid range in VariableStore.
> + @param VariableEnd End point of valid range in VariableStore.
> + @param VariableInfo Pointer to variable information.
[JianJW]
The parameters don't match the prototype below
> +
> + @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL.
> + @retval EFI_NOT_FOUND If the end of VariableStore is reached.
> + @retval EFI_SUCCESS The next variable is retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetNextVariableInfo (
> + IN OUT PROTECTED_VARIABLE_INFO *VarInfo
> + );
> +
> +/**
> +
> + Retrieve details about a variable and return them in VariableInfo->Header.
> +
> + If VariableInfo->Address is given, this function will calculate its offset
> + relative to given variable storage via VariableStore; Otherwise, it will try
> + other internal variable storages or cached copies. It's assumed that, for all
> + copies of NV variable storage, all variables are stored in the same relative
> + position. If VariableInfo->Address is found in the range of any storage copies,
> + its offset relative to that storage should be the same in other copies.
> +
> + If VariableInfo->Offset is given (non-zero) but not VariableInfo->Address,
> + this function will return the variable memory address inside VariableStore,
> + if given, via VariableInfo->Address; Otherwise, the address of other storage
> + copies will be returned, if any.
> +
> + For a new variable whose offset has not been determined, a value of -1 as
> + VariableInfo->Offset should be passed to skip the offset calculation.
> +
> + @param VariableStore Pointer to a variable storage. It's optional.
> + @param VariableInfo Pointer to variable information.
[JianJW]
The parameters doesn't match the prototype below
> +
> + @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo-
> >Address
> + and VariableInfo->Offset are NULL (0).
> + @retval EFI_NOT_FOUND If given Address or Offset is out of range of
> + any given or internal storage copies.
> + @retval EFI_SUCCESS Variable details are retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetVariableInfo (
> + IN OUT PROTECTED_VARIABLE_INFO *VarInfo
> + );
> +
> #endif
> diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
> index fe64d0a2b3dd..a5b7f8a1fbe2 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
> @@ -2,12 +2,15 @@
> Handles non-volatile variable store garbage collection, using FTW
> (Fault Tolerant Write) protocol.
>
> -Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> **/
>
> #include "Variable.h"
> +#include "VariableNonVolatile.h"
> +#include "VariableParsing.h"
> +#include "VariableRuntimeCache.h"
>
> /**
> Gets LBA of block and offset by given address.
> @@ -155,3 +158,347 @@ FtwVariableSpace (
>
> return Status;
> }
> +
> +/**
> +
> + Variable store garbage collection and reclaim operation.
> +
> + @param[in] VariableBase Base address of variable store.
> + @param[out] LastVariableOffset Offset of last variable.
> + @param[in] IsVolatile The variable store is volatile or not;
> + if it is non-volatile, need FTW.
> + @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer
> track structure.
> + @param[in] NewVariable Pointer to new variable.
> + @param[in] NewVariableSize New variable size.
> +
> + @return EFI_SUCCESS Reclaim operation has finished successfully.
> + @return EFI_OUT_OF_RESOURCES No enough memory resources or
> variable space.
> + @return Others Unexpect error happened during reclaim
> operation.
> +
> +**/
> +EFI_STATUS
> +Reclaim (
> + IN EFI_PHYSICAL_ADDRESS VariableBase,
> + OUT UINTN *LastVariableOffset,
> + IN BOOLEAN IsVolatile,
> + IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
> + IN VARIABLE_HEADER *NewVariable,
> + IN UINTN NewVariableSize
> + )
> +{
> + VARIABLE_HEADER *Variable;
> + VARIABLE_HEADER *AddedVariable;
> + VARIABLE_HEADER *NextVariable;
> + VARIABLE_HEADER *NextAddedVariable;
> + VARIABLE_STORE_HEADER *VariableStoreHeader;
> + UINT8 *ValidBuffer;
> + UINTN MaximumBufferSize;
> + UINTN VariableSize;
> + UINTN NameSize;
> + UINT8 *CurrPtr;
> + VOID *Point0;
> + VOID *Point1;
> + BOOLEAN FoundAdded;
> + EFI_STATUS Status;
> + EFI_STATUS DoneStatus;
> + UINTN CommonVariableTotalSize;
> + UINTN CommonUserVariableTotalSize;
> + UINTN HwErrVariableTotalSize;
> + VARIABLE_HEADER *UpdatingVariable;
> + VARIABLE_HEADER *UpdatingInDeletedTransition;
> + BOOLEAN AuthFormat;
> +
> + AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
> + UpdatingVariable = NULL;
> + UpdatingInDeletedTransition = NULL;
> + if (UpdatingPtrTrack != NULL) {
> + UpdatingVariable = UpdatingPtrTrack->CurrPtr;
> + UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;
> + }
> +
> + VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)VariableBase);
> +
> + CommonVariableTotalSize = 0;
> + CommonUserVariableTotalSize = 0;
> + HwErrVariableTotalSize = 0;
> +
> + if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
> + //
> + // Start Pointers for the variable.
> + //
> + Variable = GetStartPointer (VariableStoreHeader);
> + MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
> +
> + while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader),
> AuthFormat)) {
> + NextVariable = GetNextVariablePtr (Variable, AuthFormat);
> + if (((Variable->State == VAR_ADDED) || (Variable->State ==
> (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) &&
> + (Variable != UpdatingVariable) &&
> + (Variable != UpdatingInDeletedTransition)
> + )
> + {
> + VariableSize = (UINTN)NextVariable - (UINTN)Variable;
> + MaximumBufferSize += VariableSize;
> + }
> +
> + Variable = NextVariable;
> + }
> +
> + if (NewVariable != NULL) {
> + //
> + // Add the new variable size.
> + //
> + MaximumBufferSize += NewVariableSize;
> + }
> +
> + //
> + // Reserve the 1 Bytes with Oxff to identify the
> + // end of the variable buffer.
> + //
> + MaximumBufferSize += 1;
> + ValidBuffer = AllocatePool (MaximumBufferSize);
> + if (ValidBuffer == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> + } else {
> + //
> + // For NV variable reclaim, don't allocate pool here and just use
> mNvVariableCache
> + // as the buffer to reduce SMRAM consumption for SMM variable driver.
> + //
> + MaximumBufferSize = mNvVariableCache->Size;
> + ValidBuffer = (UINT8 *)mNvVariableCache;
> + }
> +
> + SetMem (ValidBuffer, MaximumBufferSize, 0xff);
> +
> + //
> + // Copy variable store header.
> + //
> + CopyMem (ValidBuffer, VariableStoreHeader, sizeof
> (VARIABLE_STORE_HEADER));
> + CurrPtr = (UINT8 *)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
> +
> + //
> + // Reinstall all ADDED variables as long as they are not identical to Updating
> Variable.
> + //
> + Variable = GetStartPointer (VariableStoreHeader);
> + while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader),
> AuthFormat)) {
> + NextVariable = GetNextVariablePtr (Variable, AuthFormat);
> + if ((Variable != UpdatingVariable) && (Variable->State == VAR_ADDED)) {
> + VariableSize = (UINTN)NextVariable - (UINTN)Variable;
> + CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
> + if (!IsVolatile) {
> + (VOID)ProtectedVariableLibRefresh (
> + (VARIABLE_HEADER *)CurrPtr,
> + VariableSize,
> + (UINTN)CurrPtr - (UINTN)ValidBuffer,
> + FALSE
> + );
> +
> + if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
> + == EFI_VARIABLE_HARDWARE_ERROR_RECORD)
> + {
> + HwErrVariableTotalSize += VariableSize;
> + } else {
> + CommonVariableTotalSize += VariableSize;
> + if (IsUserVariable (Variable)) {
> + CommonUserVariableTotalSize += VariableSize;
> + }
> + }
> + }
> +
> + CurrPtr += VariableSize;
> + }
> +
> + Variable = NextVariable;
> + }
> +
> + //
> + // Reinstall all in delete transition variables.
> + //
> + Variable = GetStartPointer (VariableStoreHeader);
> + while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader),
> AuthFormat)) {
> + NextVariable = GetNextVariablePtr (Variable, AuthFormat);
> + if ((Variable != UpdatingVariable) && (Variable !=
> UpdatingInDeletedTransition) && (Variable->State ==
> (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) &&
> + (ProtectedVariableLibIsHmac (GetVariableNamePtr (Variable, AuthFormat))
> == FALSE))
> + {
> + FoundAdded = FALSE;
> + AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
> + while (IsValidVariableHeader (AddedVariable, GetEndPointer
> ((VARIABLE_STORE_HEADER *)ValidBuffer), AuthFormat)) {
> + NextAddedVariable = GetNextVariablePtr (AddedVariable, AuthFormat);
> + NameSize = NameSizeOfVariable (AddedVariable, AuthFormat);
> + if (CompareGuid (
> + GetVendorGuidPtr (AddedVariable, AuthFormat),
> + GetVendorGuidPtr (Variable, AuthFormat)
> + ) && (NameSize == NameSizeOfVariable (Variable, AuthFormat)))
> + {
> + Point0 = (VOID *)GetVariableNamePtr (AddedVariable, AuthFormat);
> + Point1 = (VOID *)GetVariableNamePtr (Variable, AuthFormat);
> + if (CompareMem (Point0, Point1, NameSize) == 0) {
> + FoundAdded = TRUE;
> + break;
> + }
> + }
> +
> + AddedVariable = NextAddedVariable;
> + }
> +
> + if (!FoundAdded) {
> + //
> + // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
> + //
> + VariableSize = (UINTN)NextVariable - (UINTN)Variable;
> + CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
> + ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
> + if (!IsVolatile) {
> + (VOID)ProtectedVariableLibRefresh (
> + (VARIABLE_HEADER *)CurrPtr,
> + VariableSize,
> + (UINTN)CurrPtr - (UINTN)ValidBuffer,
> + FALSE
> + );
> +
> + if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
> + == EFI_VARIABLE_HARDWARE_ERROR_RECORD)
> + {
> + HwErrVariableTotalSize += VariableSize;
> + } else {
> + CommonVariableTotalSize += VariableSize;
> + if (IsUserVariable (Variable)) {
> + CommonUserVariableTotalSize += VariableSize;
> + }
> + }
> + }
> +
> + CurrPtr += VariableSize;
> + }
> + }
> +
> + Variable = NextVariable;
> + }
> +
> + //
> + // Install the new variable if it is not NULL.
> + //
> + if (NewVariable != NULL) {
> + if (((UINTN)CurrPtr - (UINTN)ValidBuffer) + NewVariableSize >
> VariableStoreHeader->Size) {
> + //
> + // No enough space to store the new variable.
> + //
> + Status = EFI_OUT_OF_RESOURCES;
> + goto Done;
> + }
> +
> + if (!IsVolatile) {
> + if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
> == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
> + HwErrVariableTotalSize += NewVariableSize;
> + } else if ((NewVariable->Attributes &
> EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=
> EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
> + CommonVariableTotalSize += NewVariableSize;
> + if (IsUserVariable (NewVariable)) {
> + CommonUserVariableTotalSize += NewVariableSize;
> + }
> + }
> +
> + if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||
> + (CommonVariableTotalSize > mVariableModuleGlobal-
> >CommonVariableSpace) ||
> + (CommonUserVariableTotalSize > mVariableModuleGlobal-
> >CommonMaxUserVariableSpace))
> + {
> + //
> + // No enough space to store the new variable by NV or NV+HR attribute.
> + //
> + Status = EFI_OUT_OF_RESOURCES;
> + goto Done;
> + }
> + }
> +
> + CopyMem (CurrPtr, (UINT8 *)NewVariable, NewVariableSize);
> + ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
> + if (UpdatingVariable != NULL) {
> + UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER
> *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr -
> (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer)));
> + UpdatingPtrTrack->InDeletedTransitionPtr = NULL;
> + }
> +
> + CurrPtr += NewVariableSize;
> + }
> +
> + if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
> + //
> + // If volatile/emulated non-volatile variable store, just copy valid buffer.
> + //
> + SetMem ((UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size, 0xff);
> + CopyMem ((UINT8 *)(UINTN)VariableBase, ValidBuffer, (UINTN)CurrPtr -
> (UINTN)ValidBuffer);
> + *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
> + if (!IsVolatile) {
> + //
> + // Emulated non-volatile variable mode.
> + //
> + mVariableModuleGlobal->HwErrVariableTotalSize =
> HwErrVariableTotalSize;
> + mVariableModuleGlobal->CommonVariableTotalSize =
> CommonVariableTotalSize;
> + mVariableModuleGlobal->CommonUserVariableTotalSize =
> CommonUserVariableTotalSize;
> + }
> +
> + Status = EFI_SUCCESS;
> + } else {
> + //
> + // If non-volatile variable store, perform FTW here.
> + //
> + Status = FtwVariableSpace (
> + VariableBase,
> + (VARIABLE_STORE_HEADER *)ValidBuffer
> + );
> + if (!EFI_ERROR (Status)) {
> + *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
> + mVariableModuleGlobal->HwErrVariableTotalSize =
> HwErrVariableTotalSize;
> + mVariableModuleGlobal->CommonVariableTotalSize =
> CommonVariableTotalSize;
> + mVariableModuleGlobal->CommonUserVariableTotalSize =
> CommonUserVariableTotalSize;
> + } else {
> + mVariableModuleGlobal->HwErrVariableTotalSize = 0;
> + mVariableModuleGlobal->CommonVariableTotalSize = 0;
> + mVariableModuleGlobal->CommonUserVariableTotalSize = 0;
> + Variable = GetStartPointer
> ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);
> + while (IsValidVariableHeader (Variable, GetEndPointer
> ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase), AuthFormat)) {
> + NextVariable = GetNextVariablePtr (Variable, AuthFormat);
> + VariableSize = (UINTN)NextVariable - (UINTN)Variable;
> + if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
> == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
> + mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
> + } else if ((Variable->Attributes &
> EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=
> EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
> + mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
> + if (IsUserVariable (Variable)) {
> + mVariableModuleGlobal->CommonUserVariableTotalSize +=
> VariableSize;
> + }
> + }
> +
> + Variable = NextVariable;
> + }
> +
> + *LastVariableOffset = (UINTN)Variable - (UINTN)VariableBase;
> + }
> + }
> +
> +Done:
> + DoneStatus = EFI_SUCCESS;
> + if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
> + DoneStatus = SynchronizeRuntimeVariableCache (
> + &mVariableModuleGlobal-
> >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache,
> + 0,
> + VariableStoreHeader->Size
> + );
> + ASSERT_EFI_ERROR (DoneStatus);
> + FreePool (ValidBuffer);
> + } else {
> + //
> + // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy
> the data back.
> + //
> + CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase,
> VariableStoreHeader->Size);
> + DoneStatus = SynchronizeRuntimeVariableCache (
> + &mVariableModuleGlobal-
> >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,
> + 0,
> + VariableStoreHeader->Size
> + );
> + ASSERT_EFI_ERROR (DoneStatus);
> + }
> +
> + if (!EFI_ERROR (Status) && EFI_ERROR (DoneStatus)) {
> + Status = DoneStatus;
> + }
> +
> + return Status;
> +}
> diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
> index 6c1a3440ac8c..6e86099eb72b 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
> @@ -16,7 +16,7 @@
> VariableServiceSetVariable() should also check authenticate data to avoid
> buffer overflow,
> integer overflow. It should also check attribute to avoid authentication bypass.
>
> -Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> (C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>
> Copyright (c) Microsoft Corporation.<BR>
> Copyright (c) 2022, ARM Limited. All rights reserved.<BR>
> @@ -30,7 +30,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> #include "VariableParsing.h"
> #include "VariableRuntimeCache.h"
>
> -VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
> +VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal = NULL;
>
> ///
> /// Define a memory cache that improves the search performance for a variable.
> @@ -458,7 +458,7 @@ CalculateCommonUserVariableTotalSize (
> //
> if (mEndOfDxe && (mVariableModuleGlobal-
> >CommonMaxUserVariableSpace != mVariableModuleGlobal-
> >CommonVariableSpace)) {
> Variable = GetStartPointer (mNvVariableCache);
> - while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
> + while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache),
> mVariableModuleGlobal->VariableGlobal.AuthFormat)) {
> NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal-
> >VariableGlobal.AuthFormat);
> VariableSize = (UINTN)NextVariable - (UINTN)Variable;
> if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=
> EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
> @@ -497,330 +497,6 @@ InitializeVariableQuota (
> CalculateCommonUserVariableTotalSize ();
> }
>
> -/**
> -
> - Variable store garbage collection and reclaim operation.
> -
> - @param[in] VariableBase Base address of variable store.
> - @param[out] LastVariableOffset Offset of last variable.
> - @param[in] IsVolatile The variable store is volatile or not;
> - if it is non-volatile, need FTW.
> - @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer
> track structure.
> - @param[in] NewVariable Pointer to new variable.
> - @param[in] NewVariableSize New variable size.
> -
> - @return EFI_SUCCESS Reclaim operation has finished successfully.
> - @return EFI_OUT_OF_RESOURCES No enough memory resources or
> variable space.
> - @return Others Unexpect error happened during reclaim
> operation.
> -
> -**/
> -EFI_STATUS
> -Reclaim (
> - IN EFI_PHYSICAL_ADDRESS VariableBase,
> - OUT UINTN *LastVariableOffset,
> - IN BOOLEAN IsVolatile,
> - IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
> - IN VARIABLE_HEADER *NewVariable,
> - IN UINTN NewVariableSize
> - )
> -{
> - VARIABLE_HEADER *Variable;
> - VARIABLE_HEADER *AddedVariable;
> - VARIABLE_HEADER *NextVariable;
> - VARIABLE_HEADER *NextAddedVariable;
> - VARIABLE_STORE_HEADER *VariableStoreHeader;
> - UINT8 *ValidBuffer;
> - UINTN MaximumBufferSize;
> - UINTN VariableSize;
> - UINTN NameSize;
> - UINT8 *CurrPtr;
> - VOID *Point0;
> - VOID *Point1;
> - BOOLEAN FoundAdded;
> - EFI_STATUS Status;
> - EFI_STATUS DoneStatus;
> - UINTN CommonVariableTotalSize;
> - UINTN CommonUserVariableTotalSize;
> - UINTN HwErrVariableTotalSize;
> - VARIABLE_HEADER *UpdatingVariable;
> - VARIABLE_HEADER *UpdatingInDeletedTransition;
> - BOOLEAN AuthFormat;
> -
> - AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
> - UpdatingVariable = NULL;
> - UpdatingInDeletedTransition = NULL;
> - if (UpdatingPtrTrack != NULL) {
> - UpdatingVariable = UpdatingPtrTrack->CurrPtr;
> - UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;
> - }
> -
> - VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)VariableBase);
> -
> - CommonVariableTotalSize = 0;
> - CommonUserVariableTotalSize = 0;
> - HwErrVariableTotalSize = 0;
> -
> - if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
> - //
> - // Start Pointers for the variable.
> - //
> - Variable = GetStartPointer (VariableStoreHeader);
> - MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
> -
> - while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader)))
> {
> - NextVariable = GetNextVariablePtr (Variable, AuthFormat);
> - if (((Variable->State == VAR_ADDED) || (Variable->State ==
> (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) &&
> - (Variable != UpdatingVariable) &&
> - (Variable != UpdatingInDeletedTransition)
> - )
> - {
> - VariableSize = (UINTN)NextVariable - (UINTN)Variable;
> - MaximumBufferSize += VariableSize;
> - }
> -
> - Variable = NextVariable;
> - }
> -
> - if (NewVariable != NULL) {
> - //
> - // Add the new variable size.
> - //
> - MaximumBufferSize += NewVariableSize;
> - }
> -
> - //
> - // Reserve the 1 Bytes with Oxff to identify the
> - // end of the variable buffer.
> - //
> - MaximumBufferSize += 1;
> - ValidBuffer = AllocatePool (MaximumBufferSize);
> - if (ValidBuffer == NULL) {
> - return EFI_OUT_OF_RESOURCES;
> - }
> - } else {
> - //
> - // For NV variable reclaim, don't allocate pool here and just use
> mNvVariableCache
> - // as the buffer to reduce SMRAM consumption for SMM variable driver.
> - //
> - MaximumBufferSize = mNvVariableCache->Size;
> - ValidBuffer = (UINT8 *)mNvVariableCache;
> - }
> -
> - SetMem (ValidBuffer, MaximumBufferSize, 0xff);
> -
> - //
> - // Copy variable store header.
> - //
> - CopyMem (ValidBuffer, VariableStoreHeader, sizeof
> (VARIABLE_STORE_HEADER));
> - CurrPtr = (UINT8 *)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
> -
> - //
> - // Reinstall all ADDED variables as long as they are not identical to Updating
> Variable.
> - //
> - Variable = GetStartPointer (VariableStoreHeader);
> - while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader)))
> {
> - NextVariable = GetNextVariablePtr (Variable, AuthFormat);
> - if ((Variable != UpdatingVariable) && (Variable->State == VAR_ADDED)) {
> - VariableSize = (UINTN)NextVariable - (UINTN)Variable;
> - CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
> - CurrPtr += VariableSize;
> - if ((!IsVolatile) && ((Variable->Attributes &
> EFI_VARIABLE_HARDWARE_ERROR_RECORD) ==
> EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
> - HwErrVariableTotalSize += VariableSize;
> - } else if ((!IsVolatile) && ((Variable->Attributes &
> EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=
> EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
> - CommonVariableTotalSize += VariableSize;
> - if (IsUserVariable (Variable)) {
> - CommonUserVariableTotalSize += VariableSize;
> - }
> - }
> - }
> -
> - Variable = NextVariable;
> - }
> -
> - //
> - // Reinstall all in delete transition variables.
> - //
> - Variable = GetStartPointer (VariableStoreHeader);
> - while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader)))
> {
> - NextVariable = GetNextVariablePtr (Variable, AuthFormat);
> - if ((Variable != UpdatingVariable) && (Variable !=
> UpdatingInDeletedTransition) && (Variable->State ==
> (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
> - //
> - // Buffer has cached all ADDED variable.
> - // Per IN_DELETED variable, we have to guarantee that
> - // no ADDED one in previous buffer.
> - //
> -
> - FoundAdded = FALSE;
> - AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
> - while (IsValidVariableHeader (AddedVariable, GetEndPointer
> ((VARIABLE_STORE_HEADER *)ValidBuffer))) {
> - NextAddedVariable = GetNextVariablePtr (AddedVariable, AuthFormat);
> - NameSize = NameSizeOfVariable (AddedVariable, AuthFormat);
> - if (CompareGuid (
> - GetVendorGuidPtr (AddedVariable, AuthFormat),
> - GetVendorGuidPtr (Variable, AuthFormat)
> - ) && (NameSize == NameSizeOfVariable (Variable, AuthFormat)))
> - {
> - Point0 = (VOID *)GetVariableNamePtr (AddedVariable, AuthFormat);
> - Point1 = (VOID *)GetVariableNamePtr (Variable, AuthFormat);
> - if (CompareMem (Point0, Point1, NameSize) == 0) {
> - FoundAdded = TRUE;
> - break;
> - }
> - }
> -
> - AddedVariable = NextAddedVariable;
> - }
> -
> - if (!FoundAdded) {
> - //
> - // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
> - //
> - VariableSize = (UINTN)NextVariable - (UINTN)Variable;
> - CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
> - ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
> - CurrPtr += VariableSize;
> - if ((!IsVolatile) && ((Variable->Attributes &
> EFI_VARIABLE_HARDWARE_ERROR_RECORD) ==
> EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
> - HwErrVariableTotalSize += VariableSize;
> - } else if ((!IsVolatile) && ((Variable->Attributes &
> EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=
> EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
> - CommonVariableTotalSize += VariableSize;
> - if (IsUserVariable (Variable)) {
> - CommonUserVariableTotalSize += VariableSize;
> - }
> - }
> - }
> - }
> -
> - Variable = NextVariable;
> - }
> -
> - //
> - // Install the new variable if it is not NULL.
> - //
> - if (NewVariable != NULL) {
> - if (((UINTN)CurrPtr - (UINTN)ValidBuffer) + NewVariableSize >
> VariableStoreHeader->Size) {
> - //
> - // No enough space to store the new variable.
> - //
> - Status = EFI_OUT_OF_RESOURCES;
> - goto Done;
> - }
> -
> - if (!IsVolatile) {
> - if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
> == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
> - HwErrVariableTotalSize += NewVariableSize;
> - } else if ((NewVariable->Attributes &
> EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=
> EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
> - CommonVariableTotalSize += NewVariableSize;
> - if (IsUserVariable (NewVariable)) {
> - CommonUserVariableTotalSize += NewVariableSize;
> - }
> - }
> -
> - if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||
> - (CommonVariableTotalSize > mVariableModuleGlobal-
> >CommonVariableSpace) ||
> - (CommonUserVariableTotalSize > mVariableModuleGlobal-
> >CommonMaxUserVariableSpace))
> - {
> - //
> - // No enough space to store the new variable by NV or NV+HR attribute.
> - //
> - Status = EFI_OUT_OF_RESOURCES;
> - goto Done;
> - }
> - }
> -
> - CopyMem (CurrPtr, (UINT8 *)NewVariable, NewVariableSize);
> - ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
> - if (UpdatingVariable != NULL) {
> - UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER
> *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr -
> (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer)));
> - UpdatingPtrTrack->InDeletedTransitionPtr = NULL;
> - }
> -
> - CurrPtr += NewVariableSize;
> - }
> -
> - if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
> - //
> - // If volatile/emulated non-volatile variable store, just copy valid buffer.
> - //
> - SetMem ((UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size, 0xff);
> - CopyMem ((UINT8 *)(UINTN)VariableBase, ValidBuffer, (UINTN)CurrPtr -
> (UINTN)ValidBuffer);
> - *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
> - if (!IsVolatile) {
> - //
> - // Emulated non-volatile variable mode.
> - //
> - mVariableModuleGlobal->HwErrVariableTotalSize =
> HwErrVariableTotalSize;
> - mVariableModuleGlobal->CommonVariableTotalSize =
> CommonVariableTotalSize;
> - mVariableModuleGlobal->CommonUserVariableTotalSize =
> CommonUserVariableTotalSize;
> - }
> -
> - Status = EFI_SUCCESS;
> - } else {
> - //
> - // If non-volatile variable store, perform FTW here.
> - //
> - Status = FtwVariableSpace (
> - VariableBase,
> - (VARIABLE_STORE_HEADER *)ValidBuffer
> - );
> - if (!EFI_ERROR (Status)) {
> - *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
> - mVariableModuleGlobal->HwErrVariableTotalSize =
> HwErrVariableTotalSize;
> - mVariableModuleGlobal->CommonVariableTotalSize =
> CommonVariableTotalSize;
> - mVariableModuleGlobal->CommonUserVariableTotalSize =
> CommonUserVariableTotalSize;
> - } else {
> - mVariableModuleGlobal->HwErrVariableTotalSize = 0;
> - mVariableModuleGlobal->CommonVariableTotalSize = 0;
> - mVariableModuleGlobal->CommonUserVariableTotalSize = 0;
> - Variable = GetStartPointer
> ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);
> - while (IsValidVariableHeader (Variable, GetEndPointer
> ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase))) {
> - NextVariable = GetNextVariablePtr (Variable, AuthFormat);
> - VariableSize = (UINTN)NextVariable - (UINTN)Variable;
> - if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) ==
> EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
> - mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
> - } else if ((Variable->Attributes &
> EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=
> EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
> - mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
> - if (IsUserVariable (Variable)) {
> - mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;
> - }
> - }
> -
> - Variable = NextVariable;
> - }
> -
> - *LastVariableOffset = (UINTN)Variable - (UINTN)VariableBase;
> - }
> - }
> -
> -Done:
> - DoneStatus = EFI_SUCCESS;
> - if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
> - DoneStatus = SynchronizeRuntimeVariableCache (
> - &mVariableModuleGlobal-
> >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache,
> - 0,
> - VariableStoreHeader->Size
> - );
> - ASSERT_EFI_ERROR (DoneStatus);
> - FreePool (ValidBuffer);
> - } else {
> - //
> - // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy
> the data back.
> - //
> - CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase,
> VariableStoreHeader->Size);
> - DoneStatus = SynchronizeRuntimeVariableCache (
> - &mVariableModuleGlobal-
> >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,
> - 0,
> - VariableStoreHeader->Size
> - );
> - ASSERT_EFI_ERROR (DoneStatus);
> - }
> -
> - if (!EFI_ERROR (Status) && EFI_ERROR (DoneStatus)) {
> - Status = DoneStatus;
> - }
> -
> - return Status;
> -}
> -
> /**
> Finds variable in storage blocks of volatile and non-volatile storage areas.
>
> @@ -1657,9 +1333,665 @@ AutoUpdateLangVariable (
> }
>
> /**
> - Update the variable region with Variable information. If
> EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
> - index of associated public key is needed.
> + Check if there's enough free space in storage to write the new variable.
>
> + @param[in] NewVariable Pointer to buffer of new variable.
> + @param[in] VariableSize Size of new variable.
> + @param[in] VariableName Name of variable.
> + @param[in] VendorGuid Guid of variable.
> + @param[in] Attributes Attributes of the variable.
> + @param[in] VolatileFlag Volatile/non-volatile variable indicator.
> +
> + @retval EFI_SUCCESS Enough free space on variable storage.
> + @retval EFI_BUFFER_TOO_SMALL There's not enough continuous free space.
> + @retval EFI_OUT_OF_RESOURCES There's not enough free space in total.
> +**/
> +EFI_STATUS
> +CheckVariableStoreSpace (
> + IN VARIABLE_HEADER *NewVariable,
> + IN UINTN VariableSize,
> + IN CHAR16 *VariableName,
> + IN EFI_GUID *VendorGuid,
> + IN UINT32 Attributes,
> + IN BOOLEAN VolatileFlag
> + )
> +{
> + BOOLEAN IsCommonVariable;
> + BOOLEAN IsCommonUserVariable;
> + UINTN CommonVariableTotalSize;
> + UINTN CommonUserVariableTotalSize;
> + UINTN HwErrVariableTotalSize;
> + VARIABLE_STORE_HEADER *VarStore;
> +
> + if ((NewVariable == NULL) || (VariableSize == 0)) {
> + return EFI_SUCCESS;
> + }
> +
> + if (VolatileFlag) {
> + VarStore = (VARIABLE_STORE_HEADER *)(UINTN)
> + mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
> + if ((UINT32)(VariableSize + mVariableModuleGlobal-
> >VolatileLastVariableOffset)
> + > VarStore->Size)
> + {
> + return EFI_BUFFER_TOO_SMALL;
> + }
> + } else {
> + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {
> + IsCommonVariable = TRUE;
> + IsCommonUserVariable = IsUserVariable (NewVariable);
> + } else {
> + IsCommonVariable = FALSE;
> + IsCommonUserVariable = FALSE;
> + }
> +
> + CommonVariableTotalSize = mVariableModuleGlobal-
> >CommonVariableTotalSize + VariableSize;
> + CommonUserVariableTotalSize = mVariableModuleGlobal-
> >CommonUserVariableTotalSize + VariableSize;
> + HwErrVariableTotalSize = mVariableModuleGlobal-
> >HwErrVariableTotalSize + VariableSize;
> +
> + if ( (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) &&
> + (HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)))
> + || (IsCommonVariable && (CommonVariableTotalSize >
> mVariableModuleGlobal->CommonVariableSpace))
> + || (IsCommonVariable &&
> + AtRuntime () &&
> + (CommonVariableTotalSize > mVariableModuleGlobal-
> >CommonRuntimeVariableSpace))
> + || (IsCommonUserVariable &&
> + (CommonUserVariableTotalSize > mVariableModuleGlobal-
> >CommonMaxUserVariableSpace)))
> + {
> + if (AtRuntime ()) {
> + if (IsCommonUserVariable &&
> + ((VariableSize + mVariableModuleGlobal-
> >CommonUserVariableTotalSize)
> + > mVariableModuleGlobal->CommonMaxUserVariableSpace))
> + {
> + RecordVarErrorFlag (
> + VAR_ERROR_FLAG_USER_ERROR,
> + VariableName,
> + VendorGuid,
> + Attributes,
> + VariableSize
> + );
> + }
> +
> + if (IsCommonVariable &&
> + ((VariableSize + mVariableModuleGlobal->CommonVariableTotalSize)
> + > mVariableModuleGlobal->CommonRuntimeVariableSpace))
> + {
> + RecordVarErrorFlag (
> + VAR_ERROR_FLAG_SYSTEM_ERROR,
> + VariableName,
> + VendorGuid,
> + Attributes,
> + VariableSize
> + );
> + }
> +
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + return EFI_BUFFER_TOO_SMALL;
> + }
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Fill specific data of auth-variable in buffer.
> +
> + @param[in,out] NewVariable Pointer to buffer of new variable.
> + @param[in] OldVariable Pointer to buffer of old copy of the variable.
> + @param[in] Attributes Attributes of the variable.
> + @param[in] KeyIndex Index of associated public key.
> + @param[in] MonotonicCount Value of associated monotonic count.
> + @param[in] TimeStamp Value of associated TimeStamp.
> +
> +**/
> +VOID
> +SetVariableAuthData (
> + IN OUT AUTHENTICATED_VARIABLE_HEADER *NewVariable,
> + IN AUTHENTICATED_VARIABLE_HEADER *OldVariable,
> + IN UINT32 Attributes,
> + IN UINT32 KeyIndex,
> + IN UINT64 MonotonicCount,
> + IN EFI_TIME *TimeStamp
> + )
> +{
> + NewVariable->PubKeyIndex = KeyIndex;
> + NewVariable->MonotonicCount = MonotonicCount;
> +
> + if ((TimeStamp != NULL) &&
> + ((Attributes &
> EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0))
> + {
> + //
> + // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
> + // when the new TimeStamp value is later than the current timestamp
> associated
> + // with the variable, we need associate the new timestamp with the updated
> value.
> + //
> + if (((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) &&
> + (OldVariable != NULL) &&
> + !VariableCompareTimeStampInternal (&OldVariable->TimeStamp,
> TimeStamp))
> + {
> + TimeStamp = &OldVariable->TimeStamp;
> + }
> +
> + CopyMem (&NewVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
> + } else {
> + ZeroMem (&NewVariable->TimeStamp, sizeof (EFI_TIME));
> + }
> +}
> +
> +/**
> + Fill the variable data buffer according to variable format on storage.
> +
> + @param[in,out] NewVariable Pointer to buffer of new variable.
> + @param[in] OldVariable Pointer to buffer of old copy of the variable.
> + @param[in] VariableName Name of variable.
> + @param[in] VendorGuid Guid of variable.
> + @param[in] Data Variable data.
> + @param[in] DataSize Size of data. 0 means delete.
> + @param[in] Attributes Attributes of the variable.
> + @param[in] KeyIndex Index of associated public key.
> + @param[in] MonotonicCount Value of associated monotonic count.
> + @param[in] TimeStamp Value of associated TimeStamp.
> +
> + @retval Size of the new variable.
> +
> +**/
> +UINTN
> +SetVariableData (
> + IN OUT VARIABLE_HEADER *NewVariable,
> + IN VARIABLE_HEADER *OldVariable,
> + IN CHAR16 *VariableName,
> + IN EFI_GUID *VendorGuid,
> + IN VOID *Data,
> + IN UINTN DataSize,
> + IN UINT32 Attributes,
> + IN UINT32 KeyIndex,
> + IN UINT64 MonotonicCount,
> + IN EFI_TIME *TimeStamp
> + )
> +{
> + EFI_STATUS Status;
> + BOOLEAN AuthFormat;
> + UINT8 *DataPtr;
> + UINTN NameSize;
> + UINTN OldDataSize;
> +
> + AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
> +
> + if (AuthFormat) {
> + SetVariableAuthData (
> + (AUTHENTICATED_VARIABLE_HEADER *)NewVariable,
> + (AUTHENTICATED_VARIABLE_HEADER *)OldVariable,
> + Attributes,
> + KeyIndex,
> + MonotonicCount,
> + TimeStamp
> + );
> + }
> +
> + NewVariable->StartId = VARIABLE_DATA;
> + NewVariable->State = VAR_ADDED;
> + NewVariable->Reserved = 0;
> + NewVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);
> +
> + CopyMem (
> + GetVendorGuidPtr (NewVariable, AuthFormat),
> + VendorGuid,
> + sizeof (EFI_GUID)
> + );
> +
> + NameSize = StrSize (VariableName);
> + SetNameSizeOfVariable (NewVariable, NameSize, AuthFormat);
> + CopyMem (
> + (UINT8 *)GetVariableNamePtr (NewVariable, AuthFormat),
> + VariableName,
> + NameSize
> + );
> +
> + //
> + // Set data size first otherwise we can't get correct data pointer in the
> + // buffer of new variable.
> + //
> + SetDataSizeOfVariable (NewVariable, DataSize, AuthFormat);
> + DataPtr = GetVariableDataPtr (NewVariable, AuthFormat);
> + if (((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) &&
> + (OldVariable != NULL) &&
> + ((OldVariable->State == VAR_ADDED) ||
> + (OldVariable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))))
> + {
> + //
> + // Get old data, which might be encrypted.
> + //
> + OldDataSize = mVariableModuleGlobal->ScratchBufferSize
> + - ((UINTN)DataPtr - (UINTN)NewVariable);
> + Status = ProtectedVariableLibGetByBuffer (
> + OldVariable,
> + DataPtr,
> + (UINT32 *)&OldDataSize,
> + AuthFormat
> + );
> + if (Status == EFI_UNSUPPORTED) {
> + OldDataSize = DataSizeOfVariable (OldVariable, AuthFormat);
> + CopyMem (DataPtr, GetVariableDataPtr (OldVariable, AuthFormat),
> OldDataSize);
> + } else if (EFI_ERROR (Status)) {
> + ASSERT_EFI_ERROR (Status);
> + return 0;
> + }
> +
> + DataPtr += OldDataSize;
> + //
> + // Update data size.
> + //
> + SetDataSizeOfVariable (NewVariable, DataSize + OldDataSize, AuthFormat);
> + }
> +
> + CopyMem (DataPtr, Data, DataSize);
> +
> + //
> + // The actual size of the variable stored in storage should include padding.
> + //
> + return ((UINTN)GetNextVariablePtr (NewVariable, AuthFormat) -
> (UINTN)NewVariable);
> +}
> +
> +/**
> + Update state of given variable as well as its cached copy.
> +
> + @param[in,out] Variable Pointer to the buffer of the variable.
> + @param[in,out] CacheVariable Cache copy of the variable.
> + @param[in] NewState New state value.
> + @param[in] Volatile Volatile/non-volatile variable indicator.
> +
> + @retval EFI_SUCCESS Variable state was updated successfully.
> + @retval Others Failed to update the variable state.
> +
> +**/
> +EFI_STATUS
> +UpdateVariableState (
> + IN OUT VARIABLE_HEADER *Variable,
> + IN OUT VARIABLE_HEADER *CacheVariable,
> + IN UINT8 NewState,
> + IN BOOLEAN Volatile
> + )
> +{
> + EFI_STATUS Status;
> +
> + Status = UpdateVariableStore (
> + &mVariableModuleGlobal->VariableGlobal,
> + Volatile,
> + FALSE,
> + mVariableModuleGlobal->FvbInstance,
> + (UINTN)&Variable->State,
> + sizeof (NewState),
> + &NewState
> + );
> + if (!EFI_ERROR (Status) && (CacheVariable != NULL)) {
> + CacheVariable->State = NewState;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Flush variable data to variable storage.
> +
> + @param[in] VarStoreBase Base address of variable storage.
> + @param[in,out] Offset Offset to write the variable from.
> + Offset from where next variable can be written.
> + @param[in,out] NewVariable Pointer to the buffer of new variable.
> + @param[in] VariableSize Size of new variable.
> + @param[in] Volatile Volatile/non-volatile variable indicator.
> + @param[in] AuthFormat Auth-variable indicator.
> +
> + @retval EFI_SUCCESS Variable(s) were written successfully.
> + @retval Others Failed to write the variable data.
> +
> +**/
> +EFI_STATUS
> +WriteVariable (
> + IN EFI_PHYSICAL_ADDRESS VarStoreBase,
> + IN OUT UINTN *Offset,
> + IN OUT VARIABLE_HEADER **NewVariable,
> + IN UINT32 VariableSize,
> + IN BOOLEAN Volatile,
> + IN BOOLEAN AuthFormat
> + )
> +{
> + EFI_STATUS Status;
> +
> + struct {
> + UINTN Offset;
> + UINT8 *Buffer;
> + UINT32 Size;
> + UINT8 State;
> + } WriteSteps[4];
> + UINTN Index;
> + UINTN Steps;
> + VARIABLE_HEADER *Variable;
> +
> + Variable = *NewVariable;
> + if (Volatile) {
> + //
> + // For non-volatile variable, one step only :
> + //
> + WriteSteps[0].Offset = *Offset;
> + WriteSteps[0].Buffer = (UINT8 *)Variable;
> + WriteSteps[0].Size = VariableSize;
> +
> + Steps = 1;
> + } else {
> + //
> + // Four steps for non-volatile variable:
> + //
> + // 1. Write variable header
> + // 2. Set variable state to header valid
> + // 3. Write variable name and data
> + // 4. Set variable state to valid
> + //
> + Variable->State = 0xff;
> + WriteSteps[0].Offset = *Offset;
> + WriteSteps[0].Buffer = (UINT8 *)Variable;
> + WriteSteps[0].Size = (UINT32)GetVariableHeaderSize (AuthFormat);
> +
> + WriteSteps[1].State = VAR_HEADER_VALID_ONLY;
> + WriteSteps[1].Offset = *Offset + OFFSET_OF (VARIABLE_HEADER, State);
> + WriteSteps[1].Buffer = &WriteSteps[1].State;
> + WriteSteps[1].Size = sizeof (Variable->State);
> +
> + WriteSteps[2].Offset = *Offset + GetVariableHeaderSize (AuthFormat);
> + WriteSteps[2].Buffer = (UINT8 *)Variable + GetVariableHeaderSize
> (AuthFormat);
> + WriteSteps[2].Size = VariableSize - (UINT32)GetVariableHeaderSize
> (AuthFormat);
> +
> + WriteSteps[3].State = VAR_ADDED;
> + WriteSteps[3].Offset = *Offset + OFFSET_OF (VARIABLE_HEADER, State);
> + WriteSteps[3].Buffer = &WriteSteps[3].State;
> + WriteSteps[3].Size = sizeof (Variable->State);
> +
> + Steps = ARRAY_SIZE (WriteSteps);
> + }
> +
> + for (Index = 0; Index < Steps; ++Index) {
> + Status = UpdateVariableStore (
> + &mVariableModuleGlobal->VariableGlobal,
> + Volatile,
> + TRUE,
> + mVariableModuleGlobal->FvbInstance,
> + WriteSteps[Index].Offset,
> + WriteSteps[Index].Size,
> + WriteSteps[Index].Buffer
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT_EFI_ERROR (Status);
> + return Status;
> + }
> + }
> +
> + Variable->State = VAR_ADDED;
> + if (!Volatile) {
> + CopyMem ((UINT8 *)mNvVariableCache + *Offset, Variable, VariableSize);
> + }
> +
> + *NewVariable = (VARIABLE_HEADER *)((UINTN)VarStoreBase + *Offset);
> + *Offset += HEADER_ALIGN (VariableSize);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Rebase the given variable pointer(s) to the equivalent one in given variable
> + storage via VarStore.
> +
> + @param[in] InVarTrackPtr Pointer to current variable in cache.
> + @param[out] OutVarTrackPtr Pointer to rebased variable against VarStore.
> + @param[in] VarStore Start of variable storage to rebase against.
> + @param[in] VariableName Name of variable.
> + @param[in] VendorGuid Guid of variable.
> + @param[in] ByOffset If TRUE, don't do variable search in VarStore.
> +
> + @retval EFI_SUCCESS Variable(s) were deleted successfully.
> + @retval EFI_INVALID_PARAMETER Invalid parameters passed.
> + @retval EFI_NOT_FOUND Given variable (VariableName & VendorGuid)
> was
> + not found in VarStore, if ByOffset is FALSE.
> +
> +**/
> +EFI_STATUS
> +RebaseVariablePtr (
> + IN VARIABLE_POINTER_TRACK *InVarTrackPtr,
> + OUT VARIABLE_POINTER_TRACK *OutVarTrackPtr,
> + IN VARIABLE_STORE_HEADER *VarStore,
> + IN CHAR16 *VariableName,
> + IN EFI_GUID *VendorGuid,
> + IN BOOLEAN ByOffset
> + )
> +{
> + EFI_STATUS Status;
> + BOOLEAN AuthFormat;
> + VARIABLE_HEADER *NewStart;
> +
> + if ((InVarTrackPtr == NULL) || (OutVarTrackPtr == NULL) || (VarStore ==
> NULL)) {
> + ASSERT (InVarTrackPtr != NULL);
> + ASSERT (OutVarTrackPtr != NULL);
> + ASSERT (VarStore != NULL);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
> +
> + if ( (InVarTrackPtr->CurrPtr == NULL)
> + || (InVarTrackPtr->StartPtr == GetStartPointer (VarStore)))
> + {
> + CopyMem (OutVarTrackPtr, InVarTrackPtr, sizeof
> (VARIABLE_POINTER_TRACK));
> + return EFI_SUCCESS;
> + }
> +
> + NewStart = GetStartPointer (VarStore);
> + if (ByOffset) {
> + OutVarTrackPtr->CurrPtr = (VARIABLE_HEADER *)
> + ((UINTN)NewStart + ((UINTN)InVarTrackPtr->CurrPtr -
> + (UINTN)InVarTrackPtr->StartPtr));
> +
> + if (InVarTrackPtr->InDeletedTransitionPtr != NULL) {
> + OutVarTrackPtr->InDeletedTransitionPtr =
> + (VARIABLE_HEADER *)((UINTN)NewStart +
> + ((UINTN)InVarTrackPtr->InDeletedTransitionPtr -
> + (UINTN)InVarTrackPtr->StartPtr));
> + } else {
> + OutVarTrackPtr->InDeletedTransitionPtr = NULL;
> + }
> +
> + OutVarTrackPtr->StartPtr = NewStart;
> + OutVarTrackPtr->EndPtr = GetEndPointer (VarStore);
> + } else {
> + OutVarTrackPtr->StartPtr = NewStart;
> + OutVarTrackPtr->EndPtr = GetEndPointer (VarStore);
> +
> + Status = FindVariableEx (VariableName, VendorGuid, FALSE, OutVarTrackPtr,
> AuthFormat);
> + if ((OutVarTrackPtr->CurrPtr == NULL) || EFI_ERROR (Status)) {
> + return EFI_NOT_FOUND;
> + }
> + }
> +
> + if ( (VarStore == mNvVariableCache)
> + || ((UINTN)VarStore == (UINTN)mVariableModuleGlobal-
> >VariableGlobal.NonVolatileVariableBase))
> + {
> + OutVarTrackPtr->Volatile = FALSE;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Check if the given variable is from HOB.
> +
> + @param[in] CacheVariable Pointer to current variable in cache.
> +
> + @retval TRUE The variable is from HOB.
> + @retval FALSE The variable is NOT from HOB.
> +
> +**/
> +BOOLEAN
> +IsHobVariable (
> + IN VARIABLE_POINTER_TRACK *CacheVariable
> + )
> +{
> + VARIABLE_STORE_HEADER *HobVarStore;
> +
> + HobVarStore = (VARIABLE_STORE_HEADER *)(UINTN)
> + mVariableModuleGlobal->VariableGlobal.HobVariableBase;
> + return (CacheVariable->CurrPtr != NULL &&
> + HobVarStore != NULL &&
> + CacheVariable->StartPtr == GetStartPointer (HobVarStore));
> +}
> +
> +/**
> + Get temporary buffer for a new variable data.
> +
> + @retval Pointer to the buffer address.
> +
> +**/
> +VARIABLE_HEADER *
> +GetNewVariableBuffer (
> + VOID
> + )
> +{
> + VARIABLE_HEADER *NewVariable;
> + VARIABLE_STORE_HEADER *VarStore;
> +
> + //
> + // Tricky part: Use scratch data area at the end of volatile variable store
> + // as a temporary storage.
> + //
> + VarStore = (VARIABLE_STORE_HEADER *)(UINTN)
> + mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
> + NewVariable = GetEndPointer (VarStore);
> +
> + SetMem (NewVariable, mVariableModuleGlobal->ScratchBufferSize, 0xff);
> +
> + return NewVariable;
> +}
> +
> +/**
> + Delete old copies of variable completely.
> +
> + @param[in] VariableName Name of variable.
> + @param[in] VendorGuid Guid of variable.
> + @param[in] Variable Pointer to current variable on storage.
> + @param[in,out] CacheVariable Pointer to current variable in cache.
> + @param[in] VolatileFlag Auth-variable indicator.
> +
> + @retval EFI_SUCCESS Variable(s) were deleted successfully.
> + @retval Others Failed to update variable state.
> +
> +**/
> +EFI_STATUS
> +DeleteVariable (
> + IN CHAR16 *VariableName,
> + IN EFI_GUID *VendorGuid,
> + IN VARIABLE_POINTER_TRACK *Variable,
> + IN OUT VARIABLE_POINTER_TRACK *CacheVariable,
> + IN BOOLEAN VolatileFlag
> + )
> +{
> + EFI_STATUS Status;
> +
> + if (Variable->InDeletedTransitionPtr != NULL) {
> + ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
> + //
> + // Both ADDED and IN_DELETED_TRANSITION variable are present,
> + // set IN_DELETED_TRANSITION one to DELETED state first.
> + //
> + Status = UpdateVariableState (
> + Variable->InDeletedTransitionPtr,
> + CacheVariable->InDeletedTransitionPtr,
> + CacheVariable->InDeletedTransitionPtr->State & VAR_DELETED,
> + VolatileFlag
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + }
> +
> + ASSERT (CacheVariable->CurrPtr != NULL);
> + Status = UpdateVariableState (
> + Variable->CurrPtr,
> + CacheVariable->CurrPtr,
> + CacheVariable->CurrPtr->State & VAR_DELETED,
> + VolatileFlag
> + );
> +
> + if (!EFI_ERROR (Status)) {
> + UpdateVariableInfo (
> + VariableName,
> + VendorGuid,
> + Variable->Volatile,
> + FALSE,
> + FALSE,
> + TRUE,
> + FALSE,
> + &gVariableInfo
> + );
> + if (!Variable->Volatile) {
> + FlushHobVariableToFlash (VariableName, VendorGuid);
> + }
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Check if it's the right time to update a variable.
> +
> + @param[in] Attributes Attributes of a variable.
> +
> + @retval TRUE It's ready for variable update.
> + @retval FALSE It's NOT ready for variable update.
> +
> +**/
> +BOOLEAN
> +ReadyForUpdate (
> + IN UINT32 Attributes
> + )
> +{
> + if ((mVariableModuleGlobal->FvbInstance == NULL) &&
> + !mVariableModuleGlobal->VariableGlobal.EmuNvMode)
> + {
> + //
> + // The FVB protocol is not ready, so the
> EFI_VARIABLE_WRITE_ARCH_PROTOCOL
> + // is not installed.
> + //
> + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
> + //
> + // Trying to update NV variable prior to the installation of
> + // EFI_VARIABLE_WRITE_ARCH_PROTOCOL
> + //
> + DEBUG ((
> + DEBUG_ERROR,
> + "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL
> ready - %r\n",
> + EFI_NOT_AVAILABLE_YET
> + ));
> + return FALSE;
> + } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
> + //
> + // Trying to update volatile authenticated variable prior to the
> + // installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL. The
> authenticated
> + // variable perhaps is not initialized, just return here.
> + //
> + DEBUG ((
> + DEBUG_ERROR,
> + "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL
> ready - %r\n",
> + EFI_NOT_AVAILABLE_YET
> + ));
> + return FALSE;
> + }
> + }
> +
> + return TRUE;
> +}
> +
> +/**
> + Check parameters associated with the variable to update.
> +
> + @param[in] Variable Pointer to current variable on storage.
> + @param[in] CacheVariable Pointer to current variable in cache.
> @param[in] VariableName Name of variable.
> @param[in] VendorGuid Guid of variable.
> @param[in] Data Variable data.
> @@ -1667,9 +1999,130 @@ AutoUpdateLangVariable (
> @param[in] Attributes Attributes of the variable.
> @param[in] KeyIndex Index of associated public key.
> @param[in] MonotonicCount Value of associated monotonic count.
> - @param[in, out] CacheVariable The variable information which is used to keep
> track of variable usage.
> @param[in] TimeStamp Value of associated TimeStamp.
>
> + @retval EFI_SUCCESS The variable is ok to be updated.
> + @retval EFI_ALREADY_STARTED No need to update the variable.
> + @retval EFI_WRITE_PROTECTED The variable cannot be updated.
> + @retval EFI_INVALID_PARAMETER The variable attributes are not valid.
> + @retval EFI_NOT_FOUND Trying to delete non-existing variable.
> +
> +**/
> +EFI_STATUS
> +ValidateVariableParameters (
> + IN VARIABLE_POINTER_TRACK *Variable,
> + IN VARIABLE_POINTER_TRACK *CacheVariable,
> + IN CHAR16 *VariableName,
> + IN EFI_GUID *VendorGuid,
> + IN VOID *Data,
> + IN UINTN DataSize,
> + IN UINT32 Attributes,
> + IN UINT32 KeyIndex,
> + IN UINT64 MonotonicCount,
> + IN EFI_TIME *TimeStamp
> + )
> +{
> + BOOLEAN AuthFlag;
> +
> + AuthFlag = mVariableModuleGlobal->VariableGlobal.AuthFormat;
> +
> + if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
> + return EFI_ALREADY_STARTED;
> + }
> +
> + if (Variable->CurrPtr != NULL) {
> + //
> + // Update/Delete existing variable.
> + //
> + if (AtRuntime ()) {
> + //
> + // If AtRuntime and the variable is Volatile and Runtime Access,
> + // the volatile is ReadOnly, and SetVariable should be aborted and
> + // return EFI_WRITE_PROTECTED.
> + //
> + if (Variable->Volatile) {
> + return EFI_WRITE_PROTECTED;
> + }
> +
> + //
> + // Only variable that have NV attributes can be updated/deleted in Runtime.
> + //
> + if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)
> == 0) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // Only variable that have RT attributes can be updated/deleted in Runtime.
> + //
> + if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)
> == 0) {
> + return EFI_INVALID_PARAMETER;
> + }
> + }
> +
> + //
> + // Variable content unchanged and no need to update timestamp, just return.
> + //
> + if ( ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)
> + && (TimeStamp == NULL)
> + && (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFlag) == DataSize)
> + && (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr,
> AuthFlag), DataSize) == 0))
> + {
> + UpdateVariableInfo (
> + VariableName,
> + VendorGuid,
> + Variable->Volatile,
> + FALSE,
> + TRUE,
> + FALSE,
> + FALSE,
> + &gVariableInfo
> + );
> + return EFI_ALREADY_STARTED;
> + }
> + } else {
> + //
> + // Create a new variable.
> + //
> +
> + //
> + // Make sure we are trying to create a new variable. You cannot delete a
> new
> + // variable.
> + //
> + if ((DataSize == 0) ||
> + ((Attributes &
> (EFI_VARIABLE_RUNTIME_ACCESS|EFI_VARIABLE_BOOTSERVICE_ACCESS)) ==
> 0))
> + {
> + return EFI_NOT_FOUND;
> + }
> +
> + //
> + // Only variable have NV|RT attribute can be created in Runtime.
> + //
> + if ( AtRuntime ()
> + && ( ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)
> + || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)))
> + {
> + return EFI_INVALID_PARAMETER;
> + }
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Update the variable region with Variable information. If
> EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
> + index of associated public key is needed.
> +
> + @param[in] VariableName Name of variable.
> + @param[in] VendorGuid Guid of variable.
> + @param[in] Data Variable data.
> + @param[in] DataSize Size of data. 0 means delete.
> + @param[in] Attributes Attributes of the variable.
> + @param[in] KeyIndex Index of associated public key.
> + @param[in] MonotonicCount Value of associated monotonic count.
> + @param[in,out] CacheVariable The variable information which is used
> + to keep track of variable usage.
> + @param[in] TimeStamp Value of associated TimeStamp.
> +
> @retval EFI_SUCCESS The update operation is success.
> @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other
> data into this region.
>
> @@ -1687,710 +2140,381 @@ UpdateVariable (
> IN EFI_TIME *TimeStamp OPTIONAL
> )
> {
> - EFI_STATUS Status;
> - VARIABLE_HEADER *NextVariable;
> - UINTN ScratchSize;
> - UINTN MaxDataSize;
> - UINTN VarNameOffset;
> - UINTN VarDataOffset;
> - UINTN VarNameSize;
> - UINTN VarSize;
> - BOOLEAN Volatile;
> - EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
> - UINT8 State;
> - VARIABLE_POINTER_TRACK *Variable;
> - VARIABLE_POINTER_TRACK NvVariable;
> - VARIABLE_STORE_HEADER *VariableStoreHeader;
> - VARIABLE_RUNTIME_CACHE *VolatileCacheInstance;
> - UINT8 *BufferForMerge;
> - UINTN MergedBufSize;
> - BOOLEAN DataReady;
> - UINTN DataOffset;
> - BOOLEAN IsCommonVariable;
> - BOOLEAN IsCommonUserVariable;
> - AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
> - BOOLEAN AuthFormat;
> + EFI_STATUS Status;
> + VARIABLE_GLOBAL *VarGlobal;
> + VARIABLE_HEADER *NewVariable;
> + VARIABLE_HEADER *NextVariable;
> + VARIABLE_HEADER *UpdatingVariable;
> + UINTN VarSize;
> + UINTN UpdateSize;
> + UINTN Offset;
> + VARIABLE_POINTER_TRACK *Variable;
> + VARIABLE_POINTER_TRACK NvVariable;
> + VARIABLE_STORE_HEADER *VariableStoreHeader;
> + VARIABLE_RUNTIME_CACHE *VolatileCacheInstance;
> + BOOLEAN IsCommonVariable;
> + BOOLEAN IsCommonUserVariable;
> + BOOLEAN DeleteFlag;
> + BOOLEAN VolatileFlag;
> + BOOLEAN HobVarOnlyFlag;
> + EFI_PHYSICAL_ADDRESS VarStoreBase;
> + UINTN *LastVariableOffset;
>
> - if ((mVariableModuleGlobal->FvbInstance == NULL)
> && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
> - //
> - // The FVB protocol is not ready, so the
> EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
> - //
> - if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
> - //
> - // Trying to update NV variable prior to the installation of
> EFI_VARIABLE_WRITE_ARCH_PROTOCOL
> - //
> - DEBUG ((DEBUG_ERROR, "Update NV variable before
> EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n",
> EFI_NOT_AVAILABLE_YET));
> - return EFI_NOT_AVAILABLE_YET;
> - } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
> - //
> - // Trying to update volatile authenticated variable prior to the installation of
> EFI_VARIABLE_WRITE_ARCH_PROTOCOL
> - // The authenticated variable perhaps is not initialized, just return here.
> - //
> - DEBUG ((DEBUG_ERROR, "Update AUTH variable before
> EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n",
> EFI_NOT_AVAILABLE_YET));
> - return EFI_NOT_AVAILABLE_YET;
> - }
> + if (!ReadyForUpdate (Attributes)) {
> + return EFI_NOT_AVAILABLE_YET;
> }
>
> - AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
> + VarGlobal = &mVariableModuleGlobal->VariableGlobal;
> +
> + if ( (((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0))
> + || (Attributes == 0)
> + || (AtRuntime () && ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS
> + |EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)))
> + {
> + DeleteFlag = TRUE;
> + } else {
> + DeleteFlag = FALSE;
> + }
> +
> + if ( ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)
> + || ((CacheVariable->CurrPtr != NULL) &&
> + ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) !=
> 0)))
> + {
> + VolatileFlag = FALSE;
> + } else {
> + VolatileFlag = TRUE;
> + }
>
> //
> // Check if CacheVariable points to the variable in variable HOB.
> // If yes, let CacheVariable points to the variable in NV variable cache.
> //
> - if ((CacheVariable->CurrPtr != NULL) &&
> - (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) &&
> - (CacheVariable->StartPtr == GetStartPointer ((VARIABLE_STORE_HEADER
> *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase))
> - )
> - {
> - CacheVariable->StartPtr = GetStartPointer (mNvVariableCache);
> - CacheVariable->EndPtr = GetEndPointer (mNvVariableCache);
> - CacheVariable->Volatile = FALSE;
> - Status = FindVariableEx (VariableName, VendorGuid, FALSE,
> CacheVariable, AuthFormat);
> + HobVarOnlyFlag = FALSE;
> + if (IsHobVariable (CacheVariable)) {
> + Status = RebaseVariablePtr (
> + CacheVariable,
> + CacheVariable,
> + mNvVariableCache,
> + VariableName,
> + VendorGuid,
> + FALSE
> + );
> if ((CacheVariable->CurrPtr == NULL) || EFI_ERROR (Status)) {
> //
> // There is no matched variable in NV variable cache.
> //
> - if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0))
> || (Attributes == 0)) {
> + if (DeleteFlag) {
> //
> - // It is to delete variable,
> - // go to delete this variable in variable HOB and
> - // try to flush other variables from HOB to flash.
> + // Leave the deletion to FlushHobVariableToFlash() before return.
> //
> - UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, FALSE,
> TRUE, FALSE, &gVariableInfo);
> - FlushHobVariableToFlash (VariableName, VendorGuid);
> - return EFI_SUCCESS;
> + HobVarOnlyFlag = TRUE;
> + Status = EFI_SUCCESS;
> + goto Done;
> }
> }
> }
>
> + //
> + // Determine the physical position of variable store to update, due to cache
> + // mechanims of variable service.
> + //
> if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {
> + //
> + // - Add new variable (volatile or non-volatile); Or
> + // - Update/delete volatile variable in place.
> + //
> Variable = CacheVariable;
> } else {
> //
> - // Update/Delete existing NV variable.
> - // CacheVariable points to the variable in the memory copy of Flash area
> - // Now let Variable points to the same variable in Flash area.
> + // - Update/Delete existing NV variable.
> + // CacheVariable points to the variable in the memory copy of Flash area.
> + // Now let Variable points to the same variable in Flash area.
> //
> - VariableStoreHeader = (VARIABLE_STORE_HEADER
> *)((UINTN)mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
> - Variable = &NvVariable;
> - Variable->StartPtr = GetStartPointer (VariableStoreHeader);
> - Variable->EndPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr +
> ((UINTN)CacheVariable->EndPtr - (UINTN)CacheVariable->StartPtr));
> -
> - Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr +
> ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));
> - if (CacheVariable->InDeletedTransitionPtr != NULL) {
> - Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable-
> >StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr -
> (UINTN)CacheVariable->StartPtr));
> - } else {
> - Variable->InDeletedTransitionPtr = NULL;
> - }
> -
> - Variable->Volatile = FALSE;
> + VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)
> + VarGlobal->NonVolatileVariableBase;
> + Variable = &NvVariable;
> + Status = RebaseVariablePtr (
> + CacheVariable,
> + Variable,
> + VariableStoreHeader,
> + VariableName,
> + VendorGuid,
> + TRUE
> + );
> + ASSERT_EFI_ERROR (Status);
> }
>
> - Fvb = mVariableModuleGlobal->FvbInstance;
> -
> //
> - // Tricky part: Use scratch data area at the end of volatile variable store
> - // as a temporary storage.
> + // Validate variable parameters.
> //
> - NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER
> *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
> - ScratchSize = mVariableModuleGlobal->ScratchBufferSize;
> - SetMem (NextVariable, ScratchSize, 0xff);
> - DataReady = FALSE;
> -
> - if (Variable->CurrPtr != NULL) {
> - //
> - // Update/Delete existing variable.
> - //
> - if (AtRuntime ()) {
> - //
> - // If AtRuntime and the variable is Volatile and Runtime Access,
> - // the volatile is ReadOnly, and SetVariable should be aborted and
> - // return EFI_WRITE_PROTECTED.
> - //
> - if (Variable->Volatile) {
> - Status = EFI_WRITE_PROTECTED;
> - goto Done;
> - }
> -
> - //
> - // Only variable that have NV attributes can be updated/deleted in Runtime.
> - //
> - if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) ==
> 0) {
> - Status = EFI_INVALID_PARAMETER;
> - goto Done;
> - }
> -
> - //
> - // Only variable that have RT attributes can be updated/deleted in Runtime.
> - //
> - if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)
> == 0) {
> - Status = EFI_INVALID_PARAMETER;
> - goto Done;
> - }
> - }
> -
> - //
> - // Setting a data variable with no access, or zero DataSize attributes
> - // causes it to be deleted.
> - // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero
> will
> - // not delete the variable.
> - //
> - if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) ||
> ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS |
> EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {
> - if (Variable->InDeletedTransitionPtr != NULL) {
> - //
> - // Both ADDED and IN_DELETED_TRANSITION variable are present,
> - // set IN_DELETED_TRANSITION one to DELETED state first.
> - //
> - ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
> - State = CacheVariable->InDeletedTransitionPtr->State;
> - State &= VAR_DELETED;
> - Status = UpdateVariableStore (
> - &mVariableModuleGlobal->VariableGlobal,
> - Variable->Volatile,
> - FALSE,
> - Fvb,
> - (UINTN)&Variable->InDeletedTransitionPtr->State,
> - sizeof (UINT8),
> - &State
> - );
> - if (!EFI_ERROR (Status)) {
> - if (!Variable->Volatile) {
> - CacheVariable->InDeletedTransitionPtr->State = State;
> - }
> - } else {
> - goto Done;
> - }
> - }
> -
> - State = CacheVariable->CurrPtr->State;
> - State &= VAR_DELETED;
> -
> - Status = UpdateVariableStore (
> - &mVariableModuleGlobal->VariableGlobal,
> - Variable->Volatile,
> - FALSE,
> - Fvb,
> - (UINTN)&Variable->CurrPtr->State,
> - sizeof (UINT8),
> - &State
> - );
> - if (!EFI_ERROR (Status)) {
> - UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE,
> FALSE, TRUE, FALSE, &gVariableInfo);
> - if (!Variable->Volatile) {
> - CacheVariable->CurrPtr->State = State;
> - FlushHobVariableToFlash (VariableName, VendorGuid);
> - }
> - }
> + Status = ValidateVariableParameters (
> + Variable,
> + CacheVariable,
> + VariableName,
> + VendorGuid,
> + Data,
> + DataSize,
> + Attributes,
> + KeyIndex,
> + MonotonicCount,
> + TimeStamp
> + );
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
>
> - goto Done;
> - }
> + //
> + // Add or update a variable. Allocate a buffer to hold it temporarily.
> + //
> + NewVariable = GetNewVariableBuffer ();
>
> + //
> + // Fill-up variable data first, if necessary.
> + //
> + IsCommonVariable = FALSE;
> + IsCommonUserVariable = FALSE;
> + if (DeleteFlag) {
> //
> - // If the variable is marked valid, and the same data has been passed in,
> - // then return to the caller immediately.
> + // No need to fill up variable buffer when deleting a variable. But the
> + // buffer is still needed if variable protection is employed.
> //
> - if ((DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) == DataSize)
> &&
> - (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr,
> AuthFormat), DataSize) == 0) &&
> - ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) &&
> - (TimeStamp == NULL))
> - {
> - //
> - // Variable content unchanged and no need to update timestamp, just return.
> - //
> - UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE,
> TRUE, FALSE, FALSE, &gVariableInfo);
> - Status = EFI_SUCCESS;
> - goto Done;
> - } else if ((CacheVariable->CurrPtr->State == VAR_ADDED) ||
> - (CacheVariable->CurrPtr->State == (VAR_ADDED &
> VAR_IN_DELETED_TRANSITION)))
> - {
> - //
> - // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.
> - //
> - if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {
> - //
> - // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable
> Header and Name.
> - // From DataOffset of NextVariable is to save the existing variable data.
> - //
> - DataOffset = GetVariableDataOffset (CacheVariable->CurrPtr,
> AuthFormat);
> - BufferForMerge = (UINT8 *)((UINTN)NextVariable + DataOffset);
> - CopyMem (
> - BufferForMerge,
> - (UINT8 *)((UINTN)CacheVariable->CurrPtr + DataOffset),
> - DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat)
> - );
> -
> - //
> - // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default
> MaxDataSize.
> - //
> - if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
> - MaxDataSize = mVariableModuleGlobal->MaxAuthVariableSize -
> DataOffset;
> - } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
> - MaxDataSize = mVariableModuleGlobal->MaxVariableSize - DataOffset;
> - } else {
> - MaxDataSize = mVariableModuleGlobal->MaxVolatileVariableSize -
> DataOffset;
> - }
> -
> - //
> - // Append the new data to the end of existing data.
> - // Max Harware error record variable data size is different from
> common/auth variable.
> - //
> - if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) ==
> EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
> - MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) -
> DataOffset;
> - }
> -
> - if (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) + DataSize >
> MaxDataSize) {
> - //
> - // Existing data size + new data size exceed maximum variable size
> limitation.
> - //
> - Status = EFI_INVALID_PARAMETER;
> - goto Done;
> - }
> -
> - CopyMem (
> - (UINT8 *)(
> - (UINTN)BufferForMerge + DataSizeOfVariable (CacheVariable-
> >CurrPtr, AuthFormat)
> - ),
> - Data,
> - DataSize
> - );
> - MergedBufSize = DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat)
> +
> - DataSize;
> -
> - //
> - // BufferForMerge(from DataOffset of NextVariable) has included the
> merged existing and new data.
> - //
> - Data = BufferForMerge;
> - DataSize = MergedBufSize;
> - DataReady = TRUE;
> - }
> -
> - //
> - // Mark the old variable as in delete transition.
> - //
> - State = CacheVariable->CurrPtr->State;
> - State &= VAR_IN_DELETED_TRANSITION;
> -
> - Status = UpdateVariableStore (
> - &mVariableModuleGlobal->VariableGlobal,
> - Variable->Volatile,
> - FALSE,
> - Fvb,
> - (UINTN)&Variable->CurrPtr->State,
> - sizeof (UINT8),
> - &State
> - );
> - if (EFI_ERROR (Status)) {
> - goto Done;
> - }
> -
> - if (!Variable->Volatile) {
> - CacheVariable->CurrPtr->State = State;
> - }
> - }
> + VarSize = 0;
> } else {
> - //
> - // Not found existing variable. Create a new variable.
> - //
> + VarSize = SetVariableData (
> + NewVariable,
> + CacheVariable->CurrPtr,
> + VariableName,
> + VendorGuid,
> + Data,
> + DataSize,
> + Attributes,
> + KeyIndex,
> + MonotonicCount,
> + TimeStamp
> + );
>
> - if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
> - Status = EFI_SUCCESS;
> - goto Done;
> - }
> -
> - //
> - // Make sure we are trying to create a new variable.
> - // Setting a data variable with zero DataSize or no access attributes means to
> delete it.
> - //
> - if ((DataSize == 0) || ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS |
> EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {
> - Status = EFI_NOT_FOUND;
> - goto Done;
> - }
> -
> - //
> - // Only variable have NV|RT attribute can be created in Runtime.
> - //
> - if (AtRuntime () &&
> - (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes &
> EFI_VARIABLE_NON_VOLATILE) == 0)))
> - {
> - Status = EFI_INVALID_PARAMETER;
> - goto Done;
> - }
> - }
> -
> - //
> - // Function part - create a new variable and copy the data.
> - // Both update a variable and create a variable will come here.
> - //
> - NextVariable->StartId = VARIABLE_DATA;
> - //
> - // NextVariable->State = VAR_ADDED;
> - //
> - NextVariable->Reserved = 0;
> - if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
> - AuthVariable = (AUTHENTICATED_VARIABLE_HEADER
> *)NextVariable;
> - AuthVariable->PubKeyIndex = KeyIndex;
> - AuthVariable->MonotonicCount = MonotonicCount;
> - ZeroMem (&AuthVariable->TimeStamp, sizeof (EFI_TIME));
> -
> - if (((Attributes &
> EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
> - (TimeStamp != NULL))
> - {
> - if ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) {
> - CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
> - } else {
> - //
> - // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set,
> only
> - // when the new TimeStamp value is later than the current timestamp
> associated
> - // with the variable, we need associate the new timestamp with the
> updated value.
> - //
> - if (Variable->CurrPtr != NULL) {
> - if (VariableCompareTimeStampInternal
> (&(((AUTHENTICATED_VARIABLE_HEADER *)CacheVariable->CurrPtr)-
> >TimeStamp), TimeStamp)) {
> - CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
> - } else {
> - CopyMem (&AuthVariable->TimeStamp,
> &(((AUTHENTICATED_VARIABLE_HEADER *)CacheVariable->CurrPtr)-
> >TimeStamp), sizeof (EFI_TIME));
> - }
> - }
> - }
> - }
> - }
> -
> - //
> - // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the
> returned
> - // Attributes bitmask parameter of a GetVariable() call.
> - //
> - NextVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);
> -
> - VarNameOffset = GetVariableHeaderSize (AuthFormat);
> - VarNameSize = StrSize (VariableName);
> - CopyMem (
> - (UINT8 *)((UINTN)NextVariable + VarNameOffset),
> - VariableName,
> - VarNameSize
> - );
> - VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE
> (VarNameSize);
> -
> - //
> - // If DataReady is TRUE, it means the variable data has been saved into
> - // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
> - //
> - if (!DataReady) {
> - CopyMem (
> - (UINT8 *)((UINTN)NextVariable + VarDataOffset),
> - Data,
> - DataSize
> - );
> - }
> -
> - CopyMem (
> - GetVendorGuidPtr (NextVariable, AuthFormat),
> - VendorGuid,
> - sizeof (EFI_GUID)
> - );
> - //
> - // There will be pad bytes after Data, the NextVariable->NameSize and
> - // NextVariable->DataSize should not include pad size so that variable
> - // service can get actual size in GetVariable.
> - //
> - SetNameSizeOfVariable (NextVariable, VarNameSize, AuthFormat);
> - SetDataSizeOfVariable (NextVariable, DataSize, AuthFormat);
> -
> - //
> - // The actual size of the variable that stores in storage should
> - // include pad size.
> - //
> - VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
> - if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
> - //
> - // Create a nonvolatile variable.
> - //
> - Volatile = FALSE;
> -
> - IsCommonVariable = FALSE;
> - IsCommonUserVariable = FALSE;
> if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {
> IsCommonVariable = TRUE;
> - IsCommonUserVariable = IsUserVariable (NextVariable);
> + IsCommonUserVariable = IsUserVariable (NewVariable);
> }
> + }
>
> - if ( ( ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
> - && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) >
> PcdGet32 (PcdHwErrStorageSize)))
> - || (IsCommonVariable && ((VarSize + mVariableModuleGlobal-
> >CommonVariableTotalSize) > mVariableModuleGlobal-
> >CommonVariableSpace))
> - || (IsCommonVariable && AtRuntime () && ((VarSize +
> mVariableModuleGlobal->CommonVariableTotalSize) >
> mVariableModuleGlobal->CommonRuntimeVariableSpace))
> - || (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal-
> >CommonUserVariableTotalSize) > mVariableModuleGlobal-
> >CommonMaxUserVariableSpace)))
> - {
> - if (AtRuntime ()) {
> - if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal-
> >CommonUserVariableTotalSize) > mVariableModuleGlobal-
> >CommonMaxUserVariableSpace)) {
> - RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName,
> VendorGuid, Attributes, VarSize);
> - }
> -
> - if (IsCommonVariable && ((VarSize + mVariableModuleGlobal-
> >CommonVariableTotalSize) > mVariableModuleGlobal-
> >CommonRuntimeVariableSpace)) {
> - RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName,
> VendorGuid, Attributes, VarSize);
> - }
> -
> - Status = EFI_OUT_OF_RESOURCES;
> - goto Done;
> - }
> -
> - //
> - // Perform garbage collection & reclaim operation, and integrate the new
> variable at the same time.
> - //
> - Status = Reclaim (
> - mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
> - &mVariableModuleGlobal->NonVolatileLastVariableOffset,
> - FALSE,
> - Variable,
> - NextVariable,
> - HEADER_ALIGN (VarSize)
> - );
> - if (!EFI_ERROR (Status)) {
> - //
> - // The new variable has been integrated successfully during reclaiming.
> - //
> - if (Variable->CurrPtr != NULL) {
> - CacheVariable->CurrPtr = (VARIABLE_HEADER
> *)((UINTN)CacheVariable->StartPtr + ((UINTN)Variable->CurrPtr -
> (UINTN)Variable->StartPtr));
> - CacheVariable->InDeletedTransitionPtr = NULL;
> - }
> -
> - UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE,
> FALSE, FALSE, &gVariableInfo);
> - FlushHobVariableToFlash (VariableName, VendorGuid);
> - } else {
> - if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal-
> >CommonUserVariableTotalSize) > mVariableModuleGlobal-
> >CommonMaxUserVariableSpace)) {
> - RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName,
> VendorGuid, Attributes, VarSize);
> - }
> + //
> + // We might need to do protection for non-volatile variable before flushing
> + // the data to storage. A null version (meaning no protection) of following
> + // APIs should simply return EFI_SUCCESS or EFI_UNSUPPORTED without any
> + // changes to original data.
> + //
> + if (!VolatileFlag) {
> + Status = ProtectedVariableLibUpdate (
> + Variable->CurrPtr,
> + Variable->InDeletedTransitionPtr,
> + NewVariable,
> + &VarSize
> + );
> + if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
> + return Status;
> + }
>
> - if (IsCommonVariable && ((VarSize + mVariableModuleGlobal-
> >CommonVariableTotalSize) > mVariableModuleGlobal-
> >CommonVariableSpace)) {
> - RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName,
> VendorGuid, Attributes, VarSize);
> - }
> - }
> + Status = EFI_SUCCESS;
> + }
>
> + //
> + // Mark the old variable as in delete transition first. There's no such need
> + // for deleting a variable, even if variable protection is employed.
> + //
> + if ( !DeleteFlag
> + && (CacheVariable->CurrPtr != NULL)
> + && ( (CacheVariable->CurrPtr->State == VAR_ADDED)
> + || (CacheVariable->CurrPtr->State == (VAR_ADDED &
> VAR_IN_DELETED_TRANSITION))))
> + {
> + Status = UpdateVariableState (
> + Variable->CurrPtr,
> + CacheVariable->CurrPtr,
> + CacheVariable->CurrPtr->State & VAR_IN_DELETED_TRANSITION,
> + Variable->Volatile
> + );
> + if (EFI_ERROR (Status)) {
> goto Done;
> }
> -
> - if (!mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
> - //
> - // Four steps
> - // 1. Write variable header
> - // 2. Set variable state to header valid
> - // 3. Write variable data
> - // 4. Set variable state to valid
> - //
> - //
> - // Step 1:
> - //
> - Status = UpdateVariableStore (
> - &mVariableModuleGlobal->VariableGlobal,
> - FALSE,
> - TRUE,
> - Fvb,
> - mVariableModuleGlobal->NonVolatileLastVariableOffset,
> - (UINT32)GetVariableHeaderSize (AuthFormat),
> - (UINT8 *)NextVariable
> - );
> -
> - if (EFI_ERROR (Status)) {
> - goto Done;
> - }
> -
> - //
> - // Step 2:
> - //
> - NextVariable->State = VAR_HEADER_VALID_ONLY;
> - Status = UpdateVariableStore (
> - &mVariableModuleGlobal->VariableGlobal,
> - FALSE,
> - TRUE,
> - Fvb,
> - mVariableModuleGlobal->NonVolatileLastVariableOffset +
> OFFSET_OF (VARIABLE_HEADER, State),
> - sizeof (UINT8),
> - &NextVariable->State
> - );
> -
> - if (EFI_ERROR (Status)) {
> - goto Done;
> - }
> -
> - //
> - // Step 3:
> - //
> - Status = UpdateVariableStore (
> - &mVariableModuleGlobal->VariableGlobal,
> - FALSE,
> - TRUE,
> - Fvb,
> - mVariableModuleGlobal->NonVolatileLastVariableOffset +
> GetVariableHeaderSize (AuthFormat),
> - (UINT32)(VarSize - GetVariableHeaderSize (AuthFormat)),
> - (UINT8 *)NextVariable + GetVariableHeaderSize (AuthFormat)
> + }
> +
> + //
> + // Have enough space to store the variable?
> + //
> + Status = CheckVariableStoreSpace (
> + NewVariable,
> + VarSize,
> + VariableName,
> + VendorGuid,
> + Attributes,
> + VolatileFlag
> + );
> + if (Status == EFI_OUT_OF_RESOURCES) {
> + //
> + // Not a chance.
> + //
> + goto Done;
> + }
> +
> + //
> + // Maybe not...
> + //
> + VarStoreBase = (VolatileFlag) ? VarGlobal->VolatileVariableBase
> + : VarGlobal->NonVolatileVariableBase;
> + LastVariableOffset = (VolatileFlag)
> + ? &mVariableModuleGlobal->VolatileLastVariableOffset
> + : &mVariableModuleGlobal->NonVolatileLastVariableOffset;
> + if (!EFI_ERROR (Status)) {
> + //
> + // There's enough free space at the tail of variable storage.
> + //
> +
> + //
> + // If non-volatile variable is protected, a separate variable
> (MetaDataHmacVar)
> + // is always updated along with current updating variable. The buffer pointed
> + // by NewVariable must have two variables. They should be written at this
> + // time orderly.
> + //
> + NextVariable = NewVariable;
> + UpdatingVariable = NULL;
> + UpdateSize = 0;
> + while ( !EFI_ERROR (Status)
> + && ((UINTN)NextVariable - (UINTN)NewVariable) < VarSize)
> + {
> + UpdatingVariable = NextVariable;
> + NextVariable = GetNextVariablePtr (UpdatingVariable, VarGlobal-
> >AuthFormat);
> + UpdateSize = (UINTN)NextVariable - (UINTN)UpdatingVariable;
> +
> + Status = WriteVariable (
> + VarStoreBase,
> + LastVariableOffset,
> + &UpdatingVariable,
> + (UINT32)UpdateSize,
> + VolatileFlag,
> + VarGlobal->AuthFormat
> );
> -
> - if (EFI_ERROR (Status)) {
> - goto Done;
> - }
> -
> - //
> - // Step 4:
> - //
> - NextVariable->State = VAR_ADDED;
> - Status = UpdateVariableStore (
> - &mVariableModuleGlobal->VariableGlobal,
> - FALSE,
> - TRUE,
> - Fvb,
> - mVariableModuleGlobal->NonVolatileLastVariableOffset +
> OFFSET_OF (VARIABLE_HEADER, State),
> - sizeof (UINT8),
> - &NextVariable->State
> - );
> -
> - if (EFI_ERROR (Status)) {
> - goto Done;
> - }
> -
> - //
> - // Update the memory copy of Flash region.
> - //
> - CopyMem ((UINT8 *)mNvVariableCache + mVariableModuleGlobal-
> >NonVolatileLastVariableOffset, (UINT8 *)NextVariable, VarSize);
> - } else {
> - //
> - // Emulated non-volatile variable mode.
> - //
> - NextVariable->State = VAR_ADDED;
> - Status = UpdateVariableStore (
> - &mVariableModuleGlobal->VariableGlobal,
> - FALSE,
> - TRUE,
> - Fvb,
> - mVariableModuleGlobal->NonVolatileLastVariableOffset,
> - (UINT32)VarSize,
> - (UINT8 *)NextVariable
> - );
> -
> - if (EFI_ERROR (Status)) {
> - goto Done;
> - }
> }
>
> - mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN
> (VarSize);
> -
> + //
> + // UpdatingVariable must point to the last written variable. Restore it to
> + // the first one so that we can calculate the offset in variable storage.
> + //
> + UpdatingVariable = (VARIABLE_HEADER *)((UINTN)UpdatingVariable +
> UpdateSize
> + - VarSize);
> if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
> - mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN
> (VarSize);
> + mVariableModuleGlobal->HwErrVariableTotalSize += VarSize;
> } else {
> - mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN
> (VarSize);
> + mVariableModuleGlobal->CommonVariableTotalSize += VarSize;
> if (IsCommonUserVariable) {
> - mVariableModuleGlobal->CommonUserVariableTotalSize +=
> HEADER_ALIGN (VarSize);
> + mVariableModuleGlobal->CommonUserVariableTotalSize += VarSize;
> }
> }
> - } else {
> - //
> - // Create a volatile variable.
> - //
> - Volatile = TRUE;
>
> - if ((UINT32)(VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >
> - ((VARIABLE_STORE_HEADER *)((UINTN)(mVariableModuleGlobal-
> >VariableGlobal.VolatileVariableBase)))->Size)
> - {
> - //
> - // Perform garbage collection & reclaim operation, and integrate the new
> variable at the same time.
> - //
> - Status = Reclaim (
> - mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,
> - &mVariableModuleGlobal->VolatileLastVariableOffset,
> - TRUE,
> + //
> + // Mark the old variable(s) as deleted.
> + //
> + if (!EFI_ERROR (Status) && (Variable->CurrPtr != NULL)) {
> + Status = DeleteVariable (
> + VariableName,
> + VendorGuid,
> Variable,
> - NextVariable,
> - HEADER_ALIGN (VarSize)
> + CacheVariable,
> + VolatileFlag
> );
> - if (!EFI_ERROR (Status)) {
> - //
> - // The new variable has been integrated successfully during reclaiming.
> - //
> - if (Variable->CurrPtr != NULL) {
> - CacheVariable->CurrPtr = (VARIABLE_HEADER
> *)((UINTN)CacheVariable->StartPtr + ((UINTN)Variable->CurrPtr -
> (UINTN)Variable->StartPtr));
> - CacheVariable->InDeletedTransitionPtr = NULL;
> - }
> -
> - UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE,
> FALSE, FALSE, &gVariableInfo);
> - }
> -
> - goto Done;
> }
> -
> - NextVariable->State = VAR_ADDED;
> - Status = UpdateVariableStore (
> - &mVariableModuleGlobal->VariableGlobal,
> - TRUE,
> - TRUE,
> - Fvb,
> - mVariableModuleGlobal->VolatileLastVariableOffset,
> - (UINT32)VarSize,
> - (UINT8 *)NextVariable
> - );
> -
> - if (EFI_ERROR (Status)) {
> - goto Done;
> - }
> -
> - mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN
> (VarSize);
> - }
> -
> - //
> - // Mark the old variable as deleted.
> - //
> - if (!EFI_ERROR (Status) && (Variable->CurrPtr != NULL)) {
> - if (Variable->InDeletedTransitionPtr != NULL) {
> - //
> - // Both ADDED and IN_DELETED_TRANSITION old variable are present,
> - // set IN_DELETED_TRANSITION one to DELETED state first.
> - //
> - ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
> - State = CacheVariable->InDeletedTransitionPtr->State;
> - State &= VAR_DELETED;
> - Status = UpdateVariableStore (
> - &mVariableModuleGlobal->VariableGlobal,
> - Variable->Volatile,
> - FALSE,
> - Fvb,
> - (UINTN)&Variable->InDeletedTransitionPtr->State,
> - sizeof (UINT8),
> - &State
> - );
> - if (!EFI_ERROR (Status)) {
> - if (!Variable->Volatile) {
> - CacheVariable->InDeletedTransitionPtr->State = State;
> - }
> - } else {
> - goto Done;
> - }
> - }
> -
> - State = CacheVariable->CurrPtr->State;
> - State &= VAR_DELETED;
> -
> - Status = UpdateVariableStore (
> - &mVariableModuleGlobal->VariableGlobal,
> - Variable->Volatile,
> - FALSE,
> - Fvb,
> - (UINTN)&Variable->CurrPtr->State,
> - sizeof (UINT8),
> - &State
> + } else {
> + //
> + // There's not enough space at the tail of variable storage but there's
> + // enough free space holes in the whole storage. Perform garbage collection
> + // & reclaim operation, and integrate the new variable at the same time.
> + //
> + Status = Reclaim (
> + VarStoreBase,
> + LastVariableOffset,
> + VolatileFlag,
> + Variable,
> + NewVariable,
> + VarSize
> );
> - if (!EFI_ERROR (Status) && !Variable->Volatile) {
> - CacheVariable->CurrPtr->State = State;
> - }
> - }
> + UpdatingVariable = Variable->CurrPtr;
>
> - if (!EFI_ERROR (Status)) {
> - UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE,
> FALSE, FALSE, &gVariableInfo);
> - if (!Volatile) {
> - FlushHobVariableToFlash (VariableName, VendorGuid);
> + if (EFI_ERROR (Status) &&
> + ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0))
> + {
> + //
> + // Out of space.
> + //
> + IsCommonUserVariable = IsUserVariable (NewVariable);
> + IsCommonVariable = TRUE;
> +
> + if (IsCommonUserVariable &&
> + ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize)
> + > mVariableModuleGlobal->CommonMaxUserVariableSpace))
> + {
> + RecordVarErrorFlag (
> + VAR_ERROR_FLAG_USER_ERROR,
> + VariableName,
> + VendorGuid,
> + Attributes,
> + VarSize
> + );
> + }
> +
> + if (IsCommonVariable &&
> + ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize)
> + > mVariableModuleGlobal->CommonVariableSpace))
> + {
> + RecordVarErrorFlag (
> + VAR_ERROR_FLAG_SYSTEM_ERROR,
> + VariableName,
> + VendorGuid,
> + Attributes,
> + VarSize
> + );
> + }
> }
> }
>
> Done:
> if (!EFI_ERROR (Status)) {
> - if (((Variable->CurrPtr != NULL) && !Variable->Volatile) || ((Attributes &
> EFI_VARIABLE_NON_VOLATILE) != 0)) {
> - VolatileCacheInstance = &(mVariableModuleGlobal-
> >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache);
> + if (!VolatileFlag) {
> + Offset = (UpdatingVariable != NULL) ? (UINTN)UpdatingVariable -
> (UINTN)VarStoreBase
> + : 0;
> + Status = ProtectedVariableLibWriteFinal (
> + NewVariable,
> + VarSize,
> + Offset
> + );
> + if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
> + return Status;
> + }
> +
> + Status = EFI_SUCCESS;
> + }
> +
> + UpdateVariableInfo (
> + VariableName,
> + VendorGuid,
> + VolatileFlag,
> + FALSE,
> + TRUE,
> + FALSE,
> + FALSE,
> + &gVariableInfo
> + );
> + //
> + // HOB copy of the same variable is no longer needed, no matter it has
> + // been deleted, updated or added from/to real variable storage.
> + //
> + if (HobVarOnlyFlag || !VolatileFlag) {
> + FlushHobVariableToFlash (VariableName, VendorGuid);
> + }
> +
> + if (!VolatileFlag) {
> + VolatileCacheInstance = &(VarGlobal-
> >VariableRuntimeCacheContext.VariableRuntimeNvCache);
> } else {
> - VolatileCacheInstance = &(mVariableModuleGlobal-
> >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache);
> + VolatileCacheInstance = &(VarGlobal-
> >VariableRuntimeCacheContext.VariableRuntimeVolatileCache);
> }
>
> if (VolatileCacheInstance->Store != NULL) {
> @@ -2401,6 +2525,11 @@ Done:
> );
> ASSERT_EFI_ERROR (Status);
> }
> + } else if (Status == EFI_ALREADY_STARTED) {
> + //
> + // Meaning nothing needs to be done. Just return success.
> + //
> + Status = EFI_SUCCESS;
> }
>
> return Status;
> @@ -2440,7 +2569,6 @@ VariableServiceGetVariable (
> {
> EFI_STATUS Status;
> VARIABLE_POINTER_TRACK Variable;
> - UINTN VarDataSize;
>
> if ((VariableName == NULL) || (VendorGuid == NULL) || (DataSize == NULL)) {
> return EFI_INVALID_PARAMETER;
> @@ -2458,28 +2586,26 @@ VariableServiceGetVariable (
> }
>
> //
> - // Get data size
> + // Get data and its size
> //
> - VarDataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal-
> >VariableGlobal.AuthFormat);
> - ASSERT (VarDataSize != 0);
> + if (!Variable.Volatile) {
> + //
> + // Currently only non-volatile variable needs protection.
> + //
> + Status = ProtectedVariableLibGetByBuffer (
> + Variable.CurrPtr,
> + Data,
> + (UINT32 *)DataSize,
> + mVariableModuleGlobal->VariableGlobal.AuthFormat
> + );
> + }
>
> - if (*DataSize >= VarDataSize) {
> - if (Data == NULL) {
> - Status = EFI_INVALID_PARAMETER;
> - goto Done;
> - }
> + if (Variable.Volatile || (Status == EFI_UNSUPPORTED)) {
> + Status = GetVariableData (Variable.CurrPtr, Data, (UINT32 *)DataSize,
> mVariableModuleGlobal->VariableGlobal.AuthFormat);
> + }
>
> - CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr,
> mVariableModuleGlobal->VariableGlobal.AuthFormat), VarDataSize);
> -
> - *DataSize = VarDataSize;
> + if (!EFI_ERROR (Status)) {
> UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE,
> FALSE, FALSE, FALSE, &gVariableInfo);
> -
> - Status = EFI_SUCCESS;
> - goto Done;
> - } else {
> - *DataSize = VarDataSize;
> - Status = EFI_BUFFER_TOO_SMALL;
> - goto Done;
> }
>
> Done:
> @@ -2860,7 +2986,7 @@ VariableServiceSetVariable (
> // Parse non-volatile variable data and get last variable offset.
> //
> NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point);
> - while (IsValidVariableHeader (NextVariable, GetEndPointer
> ((VARIABLE_STORE_HEADER *)(UINTN)Point))) {
> + while (IsValidVariableHeader (NextVariable, GetEndPointer
> ((VARIABLE_STORE_HEADER *)(UINTN)Point), AuthFormat)) {
> NextVariable = GetNextVariablePtr (NextVariable, AuthFormat);
> }
>
> @@ -3022,7 +3148,12 @@ VariableServiceQueryVariableInfoInternal (
> //
> // Now walk through the related variable store.
> //
> - while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader)))
> {
> + while (IsValidVariableHeader (
> + Variable,
> + GetEndPointer (VariableStoreHeader),
> + mVariableModuleGlobal->VariableGlobal.AuthFormat
> + ))
> + {
> NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal-
> >VariableGlobal.AuthFormat);
> VariableSize = (UINT64)(UINTN)NextVariable - (UINT64)(UINTN)Variable;
>
> @@ -3315,7 +3446,7 @@ FlushHobVariableToFlash (
> //
> mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
> for ( Variable = GetStartPointer (VariableStoreHeader)
> - ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))
> + ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader),
> AuthFormat)
> ; Variable = GetNextVariablePtr (Variable, AuthFormat)
> )
> {
> @@ -3525,11 +3656,11 @@ ConvertNormalVarStorageToAuthVarStorage (
> VARIABLE_HEADER *StartPtr;
> UINT8 *NextPtr;
> VARIABLE_HEADER *EndPtr;
> - UINTN AuthVarStroageSize;
> + UINTN AuthVarStorageSize;
> AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr;
> VARIABLE_STORE_HEADER *AuthVarStorage;
>
> - AuthVarStroageSize = sizeof (VARIABLE_STORE_HEADER);
> + AuthVarStorageSize = sizeof (VARIABLE_STORE_HEADER);
> //
> // Set AuthFormat as FALSE for normal variable storage
> //
> @@ -3542,10 +3673,10 @@ ConvertNormalVarStorageToAuthVarStorage (
> EndPtr = GetEndPointer (NormalVarStorage);
> while (StartPtr < EndPtr) {
> if (StartPtr->State == VAR_ADDED) {
> - AuthVarStroageSize = HEADER_ALIGN (AuthVarStroageSize);
> - AuthVarStroageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);
> - AuthVarStroageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr-
> >NameSize);
> - AuthVarStroageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr-
> >DataSize);
> + AuthVarStorageSize = HEADER_ALIGN (AuthVarStorageSize);
> + AuthVarStorageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);
> + AuthVarStorageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr-
> >NameSize);
> + AuthVarStorageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr-
> >DataSize);
> }
>
> StartPtr = GetNextVariablePtr (StartPtr, mVariableModuleGlobal-
> >VariableGlobal.AuthFormat);
> @@ -3554,7 +3685,7 @@ ConvertNormalVarStorageToAuthVarStorage (
> //
> // Allocate Runtime memory for Auth Variable Storage
> //
> - AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStroageSize);
> + AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStorageSize);
> ASSERT (AuthVarStorage != NULL);
> if (AuthVarStorage == NULL) {
> return NULL;
> @@ -3608,7 +3739,7 @@ ConvertNormalVarStorageToAuthVarStorage (
> AuthVarStorage->State = NormalVarStorage->State;
> AuthVarStorage->Size = (UINT32)((UINTN)AuthStartPtr -
> (UINTN)AuthVarStorage);
> CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid);
> - ASSERT (AuthVarStorage->Size <= AuthVarStroageSize);
> + ASSERT (AuthVarStorage->Size <= AuthVarStorageSize);
>
> //
> // Restore AuthFormat
> @@ -3774,7 +3905,7 @@ VariableCommonInitialize (
> //
> // Allocate memory for volatile variable store, note that there is a scratch
> space to store scratch data.
> //
> - ScratchSize = GetMaxVariableSize ();
> + ScratchSize = GetMaxVariableSize () * 2;
> mVariableModuleGlobal->ScratchBufferSize = ScratchSize;
> VolatileVariableStore = AllocateRuntimePool (PcdGet32
> (PcdVariableStoreSize) + ScratchSize);
> if (VolatileVariableStore == NULL) {
> diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> index 03fec3048dc4..52bf29ec4c5c 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> @@ -3,7 +3,7 @@
> and volatile storage space and install variable architecture protocol.
>
> Copyright (C) 2013, Red Hat, Inc.
> -Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
> Copyright (c) Microsoft Corporation.
> SPDX-License-Identifier: BSD-2-Clause-Patent
> @@ -14,6 +14,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>
> #include <Protocol/VariablePolicy.h>
> #include <Library/VariablePolicyLib.h>
> +#include "VariableParsing.h"
>
> EFI_STATUS
> EFIAPI
> @@ -534,6 +535,29 @@ VariableServiceInitialize (
> EFI_EVENT ReadyToBootEvent;
> EFI_EVENT EndOfDxeEvent;
>
> + PROTECTED_VARIABLE_CONTEXT_IN ContextIn;
> +
> + //
> + // Initialze protected variable service, if enabled.
> + //
> + ContextIn.StructSize = sizeof (ContextIn);
> + ContextIn.StructVersion =
> PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
> +
> + ContextIn.FindVariableSmm = NULL;
> + ContextIn.GetVariableInfo = GetVariableInfo;
> + ContextIn.GetNextVariableInfo = GetNextVariableInfo;
> + ContextIn.UpdateVariableStore = VariableExLibUpdateNvVariable;
> + ContextIn.UpdateVariable = VariableExLibUpdateVariable;
> +
> + ContextIn.MaxVariableSize = (UINT32)GetMaxVariableSize ();
> + ContextIn.VariableServiceUser = FromSmmModule;
> +
> + Status = ProtectedVariableLibInitialize (&ContextIn);
> + if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
> + ASSERT_EFI_ERROR (Status);
> + return Status;
> + }
> +
> Status = VariableCommonInitialize ();
> ASSERT_EFI_ERROR (Status);
>
> diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
> index 62cde0335512..5904bcbff78a 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
> @@ -1,13 +1,14 @@
> /** @file
> Provides variable driver extended services.
>
> -Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> **/
>
> #include "Variable.h"
> #include "VariableParsing.h"
> +#include "VariableRuntimeCache.h"
>
> /**
> Finds variable in storage blocks of volatile and non-volatile storage areas.
> @@ -38,6 +39,7 @@ VariableExLibFindVariable (
> EFI_STATUS Status;
> VARIABLE_POINTER_TRACK Variable;
> AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
> + PROTECTED_VARIABLE_INFO VarInfo;
>
> Status = FindVariable (
> VariableName,
> @@ -56,9 +58,12 @@ VariableExLibFindVariable (
> return Status;
> }
>
> - AuthVariableInfo->DataSize = DataSizeOfVariable (Variable.CurrPtr,
> mVariableModuleGlobal->VariableGlobal.AuthFormat);
> - AuthVariableInfo->Data = GetVariableDataPtr (Variable.CurrPtr,
> mVariableModuleGlobal->VariableGlobal.AuthFormat);
> - AuthVariableInfo->Attributes = Variable.CurrPtr->Attributes;
> + AuthVariableInfo->NameSize = NameSizeOfVariable (Variable.CurrPtr,
> mVariableModuleGlobal->VariableGlobal.AuthFormat);
> + AuthVariableInfo->VariableName = GetVariableNamePtr (Variable.CurrPtr,
> mVariableModuleGlobal->VariableGlobal.AuthFormat);
> + AuthVariableInfo->VendorGuid = GetVendorGuidPtr (Variable.CurrPtr,
> mVariableModuleGlobal->VariableGlobal.AuthFormat);
> + AuthVariableInfo->DataSize = DataSizeOfVariable (Variable.CurrPtr,
> mVariableModuleGlobal->VariableGlobal.AuthFormat);
> + AuthVariableInfo->Data = GetVariableDataPtr (Variable.CurrPtr,
> mVariableModuleGlobal->VariableGlobal.AuthFormat);
> + AuthVariableInfo->Attributes = Variable.CurrPtr->Attributes;
> if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
> AuthVariable = (AUTHENTICATED_VARIABLE_HEADER
> *)Variable.CurrPtr;
> AuthVariableInfo->PubKeyIndex = AuthVariable->PubKeyIndex;
> @@ -66,6 +71,24 @@ VariableExLibFindVariable (
> AuthVariableInfo->TimeStamp = &AuthVariable->TimeStamp;
> }
>
> + CopyMem (&VarInfo.Header, AuthVariableInfo, sizeof (VarInfo.Header));
> +
> + VarInfo.Buffer = Variable.CurrPtr;
> + VarInfo.PlainData = NULL;
> + VarInfo.PlainDataSize = 0;
> + VarInfo.Flags.Auth = mVariableModuleGlobal->VariableGlobal.AuthFormat;
> +
> + //
> + // In case the variable is encrypted.
> + //
> + Status = ProtectedVariableLibGetByInfo (&VarInfo);
> + if (!EFI_ERROR (Status)) {
> + if (VarInfo.PlainData != NULL) {
> + AuthVariableInfo->Data = VarInfo.PlainData;
> + AuthVariableInfo->DataSize = VarInfo.PlainDataSize;
> + }
> + }
> +
> return EFI_SUCCESS;
> }
>
> @@ -99,6 +122,7 @@ VariableExLibFindNextVariable (
> VARIABLE_HEADER *VariablePtr;
> AUTHENTICATED_VARIABLE_HEADER *AuthVariablePtr;
> VARIABLE_STORE_HEADER
> *VariableStoreHeader[VariableStoreTypeMax];
> + PROTECTED_VARIABLE_INFO VarInfo;
>
> VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER
> *)(UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
> VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER
> *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase;
> @@ -123,6 +147,7 @@ VariableExLibFindNextVariable (
> return Status;
> }
>
> + AuthVariableInfo->NameSize = NameSizeOfVariable (VariablePtr,
> mVariableModuleGlobal->VariableGlobal.AuthFormat);
> AuthVariableInfo->VariableName = GetVariableNamePtr (VariablePtr,
> mVariableModuleGlobal->VariableGlobal.AuthFormat);
> AuthVariableInfo->VendorGuid = GetVendorGuidPtr (VariablePtr,
> mVariableModuleGlobal->VariableGlobal.AuthFormat);
> AuthVariableInfo->DataSize = DataSizeOfVariable (VariablePtr,
> mVariableModuleGlobal->VariableGlobal.AuthFormat);
> @@ -135,6 +160,20 @@ VariableExLibFindNextVariable (
> AuthVariableInfo->TimeStamp = &AuthVariablePtr->TimeStamp;
> }
>
> + CopyMem (&VarInfo.Header, AuthVariableInfo, sizeof (VarInfo.Header));
> +
> + VarInfo.Buffer = VariablePtr;
> + VarInfo.PlainData = NULL;
> + VarInfo.PlainDataSize = 0;
> +
> + Status = ProtectedVariableLibGetByInfo (&VarInfo);
> + if (!EFI_ERROR (Status)) {
> + if (VarInfo.PlainData != NULL) {
> + AuthVariableInfo->Data = VarInfo.PlainData;
> + AuthVariableInfo->DataSize = VarInfo.PlainDataSize;
> + }
> + }
> +
> return EFI_SUCCESS;
> }
>
> @@ -256,3 +295,123 @@ VariableExLibAtRuntime (
> {
> return AtRuntime ();
> }
> +
> +/**
> + Update partial data of a variable on NV storage and/or cached copy.
> +
> + @param[in] VariableInfo Pointer to a variable with detailed information.
> + @param[in] Offset Offset to write from.
> + @param[in] Size Size of data Buffer to update.
> + @param[in] Buffer Pointer to data buffer to update.
> +
> + @retval EFI_SUCCESS The variable data was updated successfully.
> + @retval EFI_UNSUPPORTED If this function is called directly in runtime.
> + @retval EFI_INVALID_PARAMETER If VariableInfo, Buffer or Size are not
> valid.
> + @retval Others Failed to update NV storage or variable cache.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +VariableExLibUpdateNvVariable (
> + IN PROTECTED_VARIABLE_INFO *VariableInfo,
> + IN UINTN Offset,
> + IN UINT32 Size,
> + IN UINT8 *Buffer
> + )
> +{
> + EFI_STATUS Status;
> + VARIABLE_GLOBAL *Global;
> + VARIABLE_RUNTIME_CACHE *CacheInstance;
> + VARIABLE_HEADER *VariableCache;
> +
> + if ((mVariableModuleGlobal == NULL) || (mNvVariableCache == NULL)) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + //
> + // Flush the cache to store.
> + //
> + if (Size == (UINT32)-1) {
> + Status = FtwVariableSpace (
> + mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
> + mNvVariableCache
> + );
> + if ( !EFI_ERROR (Status)
> + && (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0))
> + {
> + FlushHobVariableToFlash (NULL, NULL);
> + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
> + FreePool ((VOID *)(UINTN)mVariableModuleGlobal-
> >VariableGlobal.HobVariableBase);
> + mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
> + }
> + }
> +
> + return Status;
> + }
> +
> + if ( (VariableInfo == NULL)
> + || (VariableInfo->StoreIndex == VAR_INDEX_INVALID)
> + || (Buffer == NULL)
> + || (Size == 0))
> + {
> + ASSERT (VariableInfo != NULL);
> + ASSERT (VariableInfo->StoreIndex != VAR_INDEX_INVALID);
> + ASSERT (Buffer != NULL);
> + ASSERT (Size != 0);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Global = &mVariableModuleGlobal->VariableGlobal;
> +
> + VariableCache = (VARIABLE_HEADER *)((UINTN)mNvVariableCache +
> (UINTN)VariableInfo->StoreIndex);
> +
> + ASSERT (
> + StrCmp (
> + VariableInfo->Header.VariableName,
> + GetVariableNamePtr (VariableCache, Global->AuthFormat)
> + ) == 0
> + );
> + ASSERT (
> + CompareGuid (
> + VariableInfo->Header.VendorGuid,
> + GetVendorGuidPtr (VariableCache, Global->AuthFormat)
> + )
> + );
> +
> + //
> + // Forcibly update part data of flash copy of the variable ...
> + //
> + Status = UpdateVariableStore (
> + Global,
> + FALSE,
> + FALSE,
> + mVariableModuleGlobal->FvbInstance,
> + (UINTN)(Global->NonVolatileVariableBase + VariableInfo->StoreIndex +
> Offset),
> + Size,
> + Buffer
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT_EFI_ERROR (Status);
> + return Status;
> + }
> +
> + //
> + // ... as well as the local cached copy.
> + //
> + CopyMem ((VOID *)((UINTN)VariableCache + Offset), Buffer, Size);
> +
> + //
> + // Sync remote cached copy.
> + //
> + CacheInstance = &Global-
> >VariableRuntimeCacheContext.VariableRuntimeNvCache;
> + if (CacheInstance->Store != NULL) {
> + Status = SynchronizeRuntimeVariableCache (
> + CacheInstance,
> + (UINTN)VariableInfo->StoreIndex + Offset,
> + Size
> + );
> + ASSERT_EFI_ERROR (Status);
> + }
> +
> + return EFI_SUCCESS;
> +}
> diff --git
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
> index 5e9d40b67ac2..e8b8f0b7f705 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
> @@ -1,7 +1,7 @@
> /** @file
> Common variable non-volatile store routines.
>
> -Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> **/
> @@ -120,6 +120,181 @@ InitEmuNonVolatileVariableStore (
> return EFI_SUCCESS;
> }
>
> +/**
> +
> + Create a dummy variable used to fill the gap in NV variable storage caused by
> + the invalid variables found in HMAC verification phase.
> +
> + @param[out] Variable Variable buffer.
> + @param[in] Name Variable Name.
> + @param[in] Guid Vendor GUID of the variable.
> + @param[in] Size Whole size of the variable requested.
> + @param[in] AuthFlag Variable format flag.
> +
> +**/
> +STATIC
> +VOID
> +CreateDummyVariable (
> + OUT VARIABLE_HEADER *Variable,
> + IN CHAR16 *Name,
> + IN EFI_GUID *Guid,
> + IN UINT32 Size,
> + IN BOOLEAN AuthFlag
> + )
> +{
> + AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
> +
> + ASSERT (Variable != NULL);
> +
> + if (Name == NULL) {
> + Name = L"Dummy";
> + }
> +
> + if (AuthFlag) {
> + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> +
> + AuthVariable->StartId = VARIABLE_DATA;
> + AuthVariable->State = VAR_ADDED & VAR_DELETED;
> + AuthVariable->Attributes = EFI_VARIABLE_NON_VOLATILE;
> + AuthVariable->NameSize = (UINT32)StrSize (Name);
> + AuthVariable->DataSize = Size - sizeof
> (AUTHENTICATED_VARIABLE_HEADER)
> + - AuthVariable->NameSize;
> + if (Guid != NULL) {
> + CopyMem ((VOID *)&AuthVariable->VendorGuid, (VOID *)Guid, sizeof
> (EFI_GUID));
> + }
> +
> + CopyMem (GetVariableNamePtr (Variable, AuthFlag), (VOID *)Name,
> AuthVariable->NameSize);
> + } else {
> + Variable->StartId = VARIABLE_DATA;
> + Variable->State = VAR_ADDED & VAR_DELETED;
> + Variable->Attributes = EFI_VARIABLE_NON_VOLATILE;
> + Variable->NameSize = (UINT32)StrSize (Name);
> + Variable->DataSize = Size - sizeof (VARIABLE_HEADER) - Variable-
> >NameSize;
> + if (Guid != NULL) {
> + CopyMem ((VOID *)&Variable->VendorGuid, (VOID *)Guid, sizeof
> (EFI_GUID));
> + }
> +
> + CopyMem (GetVariableNamePtr (Variable, AuthFlag), (VOID *)Name,
> Variable->NameSize);
> + }
> +}
> +
> +/**
> +
> + Init protected variable store.
> +
> + @param[in, out] VariableStore Pointer to real protected variable store base.
> +
> +**/
> +EFI_STATUS
> +InitProtectedVariableStore (
> + IN OUT VARIABLE_STORE_HEADER *VariableStore
> + )
> +{
> + EFI_STATUS Status;
> + PROTECTED_VARIABLE_INFO VarInfo;
> + UINTN Size;
> + UINTN Index;
> + BOOLEAN AuthFlag;
> + EFI_PHYSICAL_ADDRESS NextVariableStore;
> + EFI_PHYSICAL_ADDRESS *VarList;
> + UINTN NumVars;
> + UINTN CurrVar;
> +
> + SetMem (
> + (UINT8 *)VariableStore + sizeof (VARIABLE_STORE_HEADER),
> + VariableStore->Size - sizeof (VARIABLE_STORE_HEADER),
> + 0xFF
> + );
> + Index = sizeof (VARIABLE_STORE_HEADER);
> +
> + VarList = NULL;
> + NumVars = 0;
> + ProtectedVariableLibGetSortedList (&VarList, &NumVars);
> +
> + //
> + // Search variable in the order of StoreIndex
> + //
> + ZeroMem (&VarInfo, sizeof (VarInfo));
> +
> + for (CurrVar = 0; CurrVar < NumVars; CurrVar++) {
> + VarInfo.Buffer = NULL;
> + VarInfo.StoreIndex = VarList[CurrVar];
> + if (VarInfo.StoreIndex == VAR_INDEX_INVALID) {
> + break;
> + }
> +
> + Status = ProtectedVariableLibFind (&VarInfo);
> + if (EFI_ERROR (Status)) {
> + break;
> + }
> +
> + ASSERT (VarInfo.Buffer != NULL);
> +
> + AuthFlag = VarInfo.Flags.Auth;
> + if (VarInfo.StoreIndex == VAR_INDEX_INVALID) {
> + continue;
> + } else {
> + ASSERT (VarInfo.StoreIndex == HEADER_ALIGN (VarInfo.StoreIndex));
> + ASSERT (VarInfo.StoreIndex < (VariableStore->Size - sizeof
> (VARIABLE_STORE_HEADER)));
> + ASSERT ((VariableStore->Size - VarInfo.StoreIndex) > GetVariableHeaderSize
> (AuthFlag));
> + }
> +
> + //
> + // Fill gap caused by invalid variable.
> + //
> + if (VarInfo.StoreIndex > Index) {
> + Size = (UINTN)VarInfo.StoreIndex - Index;
> + CreateDummyVariable (
> + (VARIABLE_HEADER *)((UINT8 *)VariableStore + Index),
> + NULL,
> + NULL,
> + (UINT32)Size,
> + AuthFlag
> + );
> + Index += Size;
> + }
> +
> + Size = (UINTN)GetNextVariablePtr (VarInfo.Buffer, AuthFlag)
> + - (UINTN)VarInfo.Buffer;
> + CopyMem ((UINT8 *)VariableStore + VarInfo.StoreIndex, VarInfo.Buffer,
> Size);
> +
> + Index += Size;
> + Index = HEADER_ALIGN (Index);
> +
> + NextVariableStore = (EFI_PHYSICAL_ADDRESS)((UINTN)VariableStore +
> VarInfo.StoreIndex + Size);
> + }
> +
> + //
> + // Search variable in the order of StoreIndex
> + //
> + ZeroMem (&VarInfo, sizeof (VarInfo));
> + for ( ; CurrVar < NumVars; CurrVar++) {
> + VarInfo.Buffer = NULL;
> + VarInfo.StoreIndex = VarList[CurrVar];
> + Status = ProtectedVariableLibFind (&VarInfo);
> + if (EFI_ERROR (Status)) {
> + break;
> + }
> +
> + ASSERT (VarInfo.Buffer != NULL);
> +
> + AuthFlag = VarInfo.Flags.Auth;
> + if (VarInfo.StoreIndex == VAR_INDEX_INVALID) {
> + Size = (UINTN)GetNextVariablePtr (VarInfo.Buffer, AuthFlag)
> + - (UINTN)VarInfo.Buffer;
> + CopyMem ((UINT8 *)&NextVariableStore, VarInfo.Buffer, Size);
> + Status = ProtectedVariableLibRefresh (VarInfo.Buffer, 0,
> NextVariableStore - (UINTN)VariableStore, FALSE);
> + NextVariableStore = NextVariableStore + Size;
> + }
> + }
> +
> + if (Status == EFI_UNSUPPORTED) {
> + return Status;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> /**
> Init real non-volatile variable store.
>
> @@ -230,6 +405,16 @@ InitRealNonVolatileVariableStore (
> return EFI_VOLUME_CORRUPTED;
> }
>
> + //
> + // Overwrite the store with verified copy of protected variables, if enabled.
> + //
> + Status = InitProtectedVariableStore (VariableStore);
> + if ((Status != EFI_SUCCESS) && (Status != EFI_UNSUPPORTED)) {
> + FreePool (NvStorageData);
> + DEBUG ((DEBUG_ERROR, "Variable integrity might have been
> compromised\n"));
> + return Status;
> + }
> +
> mNvFvHeaderCache = FvHeader;
>
> *VariableStoreBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStore;
> @@ -323,7 +508,12 @@ InitNonVolatileVariableStore (
> // Parse non-volatile variable data and get last variable offset.
> //
> Variable = GetStartPointer (mNvVariableCache);
> - while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
> + while (IsValidVariableHeader (
> + Variable,
> + GetEndPointer (mNvVariableCache),
> + mVariableModuleGlobal->VariableGlobal.AuthFormat
> + ))
> + {
> NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal-
> >VariableGlobal.AuthFormat);
> VariableSize = (UINTN)NextVariable - (UINTN)Variable;
> if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE |
> EFI_VARIABLE_HARDWARE_ERROR_RECORD)) ==
> (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD))
> {
> diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
> index 39060ed405b8..000e4b546888 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
> @@ -2,11 +2,12 @@
> Functions in this module are associated with variable parsing operations and
> are intended to be usable across variable driver source files.
>
> -Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> **/
>
> +#include "Variable.h"
> #include "VariableParsing.h"
>
> /**
> @@ -15,6 +16,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>
> @param[in] Variable Pointer to the Variable Header.
> @param[in] VariableStoreEnd Pointer to the Variable Store End.
> + @param[in] AuthFormat TRUE indicates authenticated variables are used.
> + FALSE indicates authenticated variables are not used.
>
> @retval TRUE Variable header is valid.
> @retval FALSE Variable header is not valid.
> @@ -23,10 +26,14 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> BOOLEAN
> IsValidVariableHeader (
> IN VARIABLE_HEADER *Variable,
> - IN VARIABLE_HEADER *VariableStoreEnd
> + IN VARIABLE_HEADER *VariableStoreEnd,
> + IN BOOLEAN AuthFormat
> )
> {
> - if ((Variable == NULL) || (Variable >= VariableStoreEnd) || (Variable->StartId !=
> VARIABLE_DATA)) {
> + if ( (Variable == NULL)
> + || (((UINTN)Variable + GetVariableHeaderSize (AuthFormat)) >=
> (UINTN)VariableStoreEnd)
> + || (Variable->StartId != VARIABLE_DATA))
> + {
> //
> // Variable is NULL or has reached the end of variable store,
> // or the StartId is not correct.
> @@ -341,6 +348,52 @@ GetVariableDataOffset (
> return Value;
> }
>
> +/**
> + Get variable data payload.
> +
> + @param[in] Variable Pointer to the Variable Header.
> + @param[in,out] Data Pointer to buffer used to store the variable data.
> + @param[in,out] DataSize Size of buffer passed by Data.
> + Size of data copied into Data buffer.
> + @param[in] AuthFlag Auth-variable indicator.
> +
> + @return EFI_SUCCESS Data was fetched.
> + @return EFI_INVALID_PARAMETER DataSize is NULL.
> + @return EFI_BUFFER_TOO_SMALL DataSize is smaller than size of variable
> data.
> +
> +**/
> +EFI_STATUS
> +GetVariableData (
> + IN VARIABLE_HEADER *Variable,
> + IN OUT VOID *Data,
> + IN OUT UINT32 *DataSize,
> + IN BOOLEAN AuthFlag
> + )
> +{
> + UINT32 Size;
> +
> + if (DataSize == NULL) {
> + ASSERT (DataSize != NULL);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Size = (UINT32)DataSizeOfVariable (Variable, AuthFlag);
> + if (*DataSize < Size) {
> + *DataSize = Size;
> + return EFI_BUFFER_TOO_SMALL;
> + }
> +
> + if (Data == NULL) {
> + ASSERT (Data != NULL);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + CopyMem (Data, GetVariableDataPtr (Variable, AuthFlag), Size);
> + *DataSize = Size;
> +
> + return EFI_SUCCESS;
> +}
> +
> /**
>
> This code gets the pointer to the next variable header.
> @@ -479,7 +532,7 @@ FindVariableEx (
> InDeletedVariable = NULL;
>
> for ( PtrTrack->CurrPtr = PtrTrack->StartPtr
> - ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr)
> + ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr, AuthFormat)
> ; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr, AuthFormat)
> )
> {
> @@ -608,7 +661,7 @@ VariableServiceGetNextVariableInternal (
> //
> // Switch to the next variable store if needed
> //
> - while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr)) {
> + while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr,
> AuthFormat)) {
> //
> // Find current storage index
> //
> @@ -804,3 +857,260 @@ UpdateVariableInfo (
> }
> }
> }
> +
> +/**
> +
> + Retrieve details about a variable and return them in VariableInfo->Header.
> +
> + If VariableInfo->Address is given, this function will calculate its offset
> + relative to given variable storage via VariableStore; Otherwise, it will try
> + other internal variable storages or cached copies. It's assumed that, for all
> + copies of NV variable storage, all variables are stored in the same relative
> + position. If VariableInfo->Address is found in the range of any storage copies,
> + its offset relative to that storage should be the same in other copies.
> +
> + If VariableInfo->Offset is given (non-zero) but not VariableInfo->Address,
> + this function will return the variable memory address inside VariableStore,
> + if given, via VariableInfo->Address; Otherwise, the address of other storage
> + copies will be returned, if any.
> +
> + For a new variable whose offset has not been determined, a value of -1 as
> + VariableInfo->Offset should be passed to skip the offset calculation.
> +
> + @param[in,out] VariableInfo Pointer to variable information.
> +
> + @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo-
> >Address
> + and VariableInfo->Offset are NULL (0).
> + @retval EFI_NOT_FOUND If given Address or Offset is out of range of
> + any given or internal storage copies.
> + @retval EFI_SUCCESS Variable details are retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetVariableInfo (
> + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
> + )
> +{
> + VARIABLE_STORE_HEADER *Stores[2];
> + UINTN Index;
> + VARIABLE_HEADER *VariablePtr;
> + VARIABLE_HEADER *VariableBuffer;
> + AUTHENTICATED_VARIABLE_HEADER *AuthVariablePtr;
> + BOOLEAN AuthFlag;
> + UINTN NameSize;
> + UINTN DataSize;
> + UINTN VariableSize;
> +
> + if ((VariableInfo == NULL) || ( (VariableInfo->Buffer == NULL)
> + && (VariableInfo->StoreIndex == VAR_INDEX_INVALID)))
> + {
> + ASSERT (VariableInfo != NULL);
> + ASSERT (VariableInfo->Buffer != NULL || VariableInfo->StoreIndex !=
> VAR_INDEX_INVALID);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Stores[0] = mNvVariableCache;
> + Stores[1] = (mVariableModuleGlobal != NULL)
> + ? (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal-
> >VariableGlobal.NonVolatileVariableBase
> + : NULL;
> +
> + VariableBuffer = VariableInfo->Buffer;
> + VariablePtr = NULL;
> + if (VariableInfo->StoreIndex != VAR_INDEX_INVALID) {
> + for (Index = 0; Index < ARRAY_SIZE (Stores); ++Index) {
> + if (Stores[Index] == NULL) {
> + continue;
> + }
> +
> + if ((UINTN)VariableInfo->StoreIndex
> + < ((UINTN)GetEndPointer (Stores[Index]) - (UINTN)Stores[Index]))
> + {
> + VariablePtr = (VARIABLE_HEADER *)((UINTN)Stores[Index] +
> (UINTN)VariableInfo->StoreIndex);
> + VariableInfo->Buffer = VariablePtr;
> + break;
> + }
> + }
> + } else {
> + VariablePtr = VariableInfo->Buffer;
> + }
> +
> + if (VariablePtr == NULL) {
> + return EFI_NOT_FOUND;
> + }
> +
> + AuthFlag = VariableInfo->Flags.Auth;
> + ASSERT (AuthFlag == TRUE || AuthFlag == FALSE);
> +
> + //
> + // Make a copy of the whole variable if a buffer is passed in.
> + //
> + if ((VariableBuffer != NULL) && (VariableBuffer != VariablePtr)) {
> + VariableSize = (UINTN)GetNextVariablePtr (VariablePtr, AuthFlag)
> + - (UINTN)VariablePtr;
> + CopyMem (VariableBuffer, VariablePtr, VariableSize);
> + }
> +
> + //
> + // AuthVariable header
> + //
> + if (AuthFlag) {
> + AuthVariablePtr = (AUTHENTICATED_VARIABLE_HEADER *)VariablePtr;
> +
> + VariableInfo->Header.State = AuthVariablePtr->State;
> + VariableInfo->Header.Attributes = AuthVariablePtr->Attributes;
> + VariableInfo->Header.PubKeyIndex = AuthVariablePtr->PubKeyIndex;
> + VariableInfo->Header.MonotonicCount = ReadUnaligned64 (
> + &(AuthVariablePtr->MonotonicCount)
> + );
> + if (VariableInfo->Header.TimeStamp != NULL) {
> + CopyMem (
> + VariableInfo->Header.TimeStamp,
> + &AuthVariablePtr->TimeStamp,
> + sizeof (EFI_TIME)
> + );
> + } else if (VariableBuffer != NULL) {
> + AuthVariablePtr = (AUTHENTICATED_VARIABLE_HEADER
> *)VariableBuffer;
> + VariableInfo->Header.TimeStamp = &AuthVariablePtr->TimeStamp;
> + }
> + } else {
> + VariableInfo->Header.State = VariablePtr->State;
> + VariableInfo->Header.Attributes = VariablePtr->Attributes;
> + VariableInfo->Header.PubKeyIndex = 0;
> + VariableInfo->Header.MonotonicCount = 0;
> + VariableInfo->Header.TimeStamp = NULL;
> + }
> +
> + //
> + // VendorGuid
> + //
> + if (VariableInfo->Header.VendorGuid != NULL) {
> + CopyGuid (
> + VariableInfo->Header.VendorGuid,
> + GetVendorGuidPtr (VariablePtr, AuthFlag)
> + );
> + } else {
> + VariableInfo->Header.VendorGuid = GetVendorGuidPtr (VariablePtr,
> AuthFlag);
> + }
> +
> + //
> + // VariableName
> + //
> + NameSize = NameSizeOfVariable (VariablePtr, AuthFlag);
> + if ( (VariableInfo->Header.VariableName != NULL)
> + && (VariableInfo->Header.NameSize >= NameSize))
> + {
> + CopyMem (
> + VariableInfo->Header.VariableName,
> + GetVariableNamePtr (VariablePtr, AuthFlag),
> + NameSize
> + );
> + } else if (VariableInfo->Header.VariableName != NULL) {
> + return EFI_BUFFER_TOO_SMALL;
> + } else {
> + VariableInfo->Header.VariableName = GetVariableNamePtr (VariablePtr,
> AuthFlag);
> + }
> +
> + //
> + // Data
> + //
> + DataSize = DataSizeOfVariable (VariablePtr, AuthFlag);
> + if ( (VariableInfo->Header.Data != NULL)
> + && (VariableInfo->Header.DataSize >= DataSize))
> + {
> + CopyMem (
> + VariableInfo->Header.Data,
> + GetVariableDataPtr (VariablePtr, AuthFlag),
> + NameSize
> + );
> + } else if (VariableInfo->Header.Data != NULL) {
> + return EFI_BUFFER_TOO_SMALL;
> + } else {
> + VariableInfo->Header.Data = GetVariableDataPtr (VariablePtr, AuthFlag);
> + }
> +
> + //
> + // Update size information about name & data.
> + //
> + VariableInfo->Header.NameSize = NameSize;
> + VariableInfo->Header.DataSize = DataSize;
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> +
> + Retrieve details of the variable next to given variable within VariableStore.
> +
> + If VarInfo->Address is NULL, the first one in VariableStore is returned.
> +
> + VariableStart and/or VariableEnd can be given optionally for the situation
> + in which the valid storage space is smaller than the VariableStore->Size.
> + This usually happens when PEI variable services make a compact variable
> + cache to save memory, which cannot make use VariableStore->Size to
> determine
> + the correct variable storage range.
> +
> + @param[in,out] VariableInfo Pointer to variable information.
> +
> + @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL.
> + @retval EFI_NOT_FOUND If the end of VariableStore is reached.
> + @retval EFI_SUCCESS The next variable is retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetNextVariableInfo (
> + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo
> + )
> +{
> + VARIABLE_STORE_HEADER *VarStore;
> + VARIABLE_HEADER *VariablePtr;
> + VARIABLE_HEADER *VariableStart;
> + VARIABLE_HEADER *VariableEnd;
> + BOOLEAN AuthFlag;
> +
> + if (VariableInfo == NULL) {
> + ASSERT (VariableInfo != NULL);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (mNvVariableCache != NULL) {
> + VarStore = mNvVariableCache;
> + } else if (mVariableModuleGlobal != NULL) {
> + VarStore = (VARIABLE_STORE_HEADER *)(UINTN)
> + mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
> + } else {
> + return EFI_NOT_FOUND;
> + }
> +
> + VariableStart = GetStartPointer (VarStore);
> + VariableEnd = GetEndPointer (VarStore);
> +
> + if ((VariableInfo->Flags.Auth != TRUE) && (VariableInfo->Flags.Auth != FALSE))
> {
> + VariableInfo->Flags.Auth = CompareGuid (
> + &VarStore->Signature,
> + &gEfiAuthenticatedVariableGuid
> + );
> + }
> +
> + AuthFlag = VariableInfo->Flags.Auth;
> +
> + if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
> + VariablePtr = VariableStart;
> + } else {
> + VariablePtr = (VARIABLE_HEADER *)
> + ((UINTN)VarStore + (UINTN)VariableInfo->StoreIndex);
> + if (VariablePtr >= VariableEnd) {
> + return EFI_NOT_FOUND;
> + }
> +
> + VariablePtr = GetNextVariablePtr (VariablePtr, AuthFlag);
> + }
> +
> + if (!IsValidVariableHeader (VariablePtr, VariableEnd, AuthFlag)) {
> + return EFI_NOT_FOUND;
> + }
> +
> + VariableInfo->StoreIndex = (UINTN)VariablePtr - (UINTN)VarStore;
> + return GetVariableInfo (VariableInfo);
> +}
> diff --git
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
> index 9bb30bc1e804..dc319feee727 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
> @@ -7,7 +7,7 @@
> This external input must be validated carefully to avoid security issue like
> buffer overflow, integer overflow.
>
> -Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
[JianJW]
It looks that there's no other changes in this file. No need to update the year.
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> **/
> diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
> index 517cae7b00f8..c2b689f6202d 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
> @@ -14,7 +14,7 @@
> VariableServiceSetVariable(), VariableServiceQueryVariableInfo(),
> ReclaimForOS(),
> SmmVariableGetStatistics() should also do validation based on its own
> knowledge.
>
> -Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
> Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> @@ -1045,6 +1045,13 @@ VariableWriteServiceInitializeSmm (
> {
> EFI_STATUS Status;
>
> + Status = ProtectedVariableLibWriteInit ();
> + if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
> + DEBUG ((DEBUG_ERROR, "Variable protection service: write-init failed.
> Status = %r\n", Status));
> + ASSERT_EFI_ERROR (Status);
> + return;
> + }
> +
> Status = VariableWriteServiceInitialize ();
> if (EFI_ERROR (Status)) {
> DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. Status
> = %r\n", Status));
> @@ -1143,10 +1150,32 @@ MmVariableServiceInitialize (
> VOID
> )
> {
> - EFI_STATUS Status;
> - EFI_HANDLE VariableHandle;
> - VOID *SmmFtwRegistration;
> - VOID *SmmEndOfDxeRegistration;
> + EFI_STATUS Status;
> + EFI_HANDLE VariableHandle;
> + VOID *SmmFtwRegistration;
> + VOID *SmmEndOfDxeRegistration;
> + PROTECTED_VARIABLE_CONTEXT_IN ContextIn;
> +
> + //
> + // Initialize protected variable service, if enabled.
> + //
> + ContextIn.StructSize = sizeof (ContextIn);
> + ContextIn.StructVersion =
> PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
> +
> + ContextIn.FindVariableSmm = NULL;
> + ContextIn.GetVariableInfo = GetVariableInfo;
> + ContextIn.GetNextVariableInfo = GetNextVariableInfo;
> + ContextIn.UpdateVariableStore = VariableExLibUpdateNvVariable;
> + ContextIn.UpdateVariable = VariableExLibUpdateVariable;
> +
> + ContextIn.MaxVariableSize = (UINT32)GetMaxVariableSize ();
> + ContextIn.VariableServiceUser = FromSmmModule;
> +
> + Status = ProtectedVariableLibInitialize (&ContextIn);
> + if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
> + ASSERT_EFI_ERROR (Status);
> + return Status;
> + }
>
> //
> // Variable initialize.
> diff --git
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
> index 4aaeb5ba8806..8fb8679671ad 100644
> ---
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
> +++
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
> @@ -13,7 +13,7 @@
>
> InitCommunicateBuffer() is really function to check the variable data size.
>
> -Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
> Copyright (c) Microsoft Corporation.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> @@ -36,11 +36,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> #include <Library/UefiLib.h>
> #include <Library/BaseLib.h>
> #include <Library/MmUnblockMemoryLib.h>
> +#include <Library/IoLib.h>
[JianJW]
I didn't find any interface from IoLib.h used this file.
>
> #include <Guid/EventGroup.h>
> #include <Guid/SmmVariableCommon.h>
>
> #include "PrivilegePolymorphic.h"
> +#include "Variable.h"
> #include "VariableParsing.h"
>
> EFI_HANDLE mHandle = NULL;
> @@ -53,6 +55,8 @@ VARIABLE_INFO_ENTRY *mVariableInfo
> = NULL;
> VARIABLE_STORE_HEADER *mVariableRuntimeHobCacheBuffer = NULL;
> VARIABLE_STORE_HEADER *mVariableRuntimeNvCacheBuffer = NULL;
> VARIABLE_STORE_HEADER *mVariableRuntimeVolatileCacheBuffer =
> NULL;
> +VARIABLE_STORE_HEADER *mNvVariableCache = NULL;
> +VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal = NULL;
> UINTN mVariableBufferSize;
> UINTN mVariableRuntimeHobCacheBufferSize;
> UINTN mVariableRuntimeNvCacheBufferSize;
> @@ -616,7 +620,6 @@ FindVariableInRuntimeCache (
> )
> {
> EFI_STATUS Status;
> - UINTN TempDataSize;
> VARIABLE_POINTER_TRACK RtPtrTrack;
> VARIABLE_STORE_TYPE StoreType;
> VARIABLE_STORE_HEADER *VariableStoreList[VariableStoreTypeMax];
> @@ -669,31 +672,23 @@ FindVariableInRuntimeCache (
> //
> // Get data size
> //
> - TempDataSize = DataSizeOfVariable (RtPtrTrack.CurrPtr,
> mVariableAuthFormat);
> - ASSERT (TempDataSize != 0);
> -
> - if (*DataSize >= TempDataSize) {
> - if (Data == NULL) {
> - Status = EFI_INVALID_PARAMETER;
> - goto Done;
> - }
> -
> - CopyMem (Data, GetVariableDataPtr (RtPtrTrack.CurrPtr,
> mVariableAuthFormat), TempDataSize);
> - *DataSize = TempDataSize;
> -
> - UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE,
> FALSE, FALSE, TRUE, &mVariableInfo);
> -
> - Status = EFI_SUCCESS;
> - goto Done;
> - } else {
> - *DataSize = TempDataSize;
> - Status = EFI_BUFFER_TOO_SMALL;
> - goto Done;
> + if (!RtPtrTrack.Volatile) {
> + //
> + // Currently only non-volatile variable needs protection.
> + //
> + Status = ProtectedVariableLibGetByBuffer (RtPtrTrack.CurrPtr, Data,
> (UINT32 *)DataSize, mVariableAuthFormat);
> + }
> +
> + if (RtPtrTrack.Volatile || (Status == EFI_UNSUPPORTED)) {
> + Status = GetVariableData (RtPtrTrack.CurrPtr, Data, (UINT32 *)DataSize,
> mVariableAuthFormat);
> + }
> +
> + if (!EFI_ERROR (Status)) {
> + UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile,
> TRUE, FALSE, FALSE, FALSE, &mVariableInfo);
> }
> }
> }
>
> -Done:
> if ((Status == EFI_SUCCESS) || (Status == EFI_BUFFER_TOO_SMALL)) {
> if ((Attributes != NULL) && (RtPtrTrack.CurrPtr != NULL)) {
> *Attributes = RtPtrTrack.CurrPtr->Attributes;
> --
> 2.35.1.windows.2
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [Patch v2 10/28] SecurityPkg: Add new KeyService types and defines
2022-04-29 18:04 ` [Patch v2 10/28] SecurityPkg: Add new KeyService types and defines Judah Vang
@ 2022-05-22 14:06 ` Wang, Jian J
0 siblings, 0 replies; 49+ messages in thread
From: Wang, Jian J @ 2022-05-22 14:06 UTC (permalink / raw)
To: Vang, Judah, devel@edk2.groups.io; +Cc: Yao, Jiewen, Mistry, Nishant C
Judah,
> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Saturday, April 30, 2022 2:04 AM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [Patch v2 10/28] SecurityPkg: Add new KeyService types and defines
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> Add new KeyService types and defines.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> SecurityPkg/Include/Ppi/KeyServicePpi.h | 57 ++++++++++++++++++++
> 1 file changed, 57 insertions(+)
>
> diff --git a/SecurityPkg/Include/Ppi/KeyServicePpi.h
> b/SecurityPkg/Include/Ppi/KeyServicePpi.h
> new file mode 100644
> index 000000000000..f126913d2d81
> --- /dev/null
> +++ b/SecurityPkg/Include/Ppi/KeyServicePpi.h
> @@ -0,0 +1,57 @@
> +/** @file
> + Provides Key Services.
> +
> +Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
[JianJW]
2018 -> 2022
Regards,
Jian
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +@par Specification Reference:
> +**/
> +
> +#ifndef PEI_KEY_SERVICE_PPI_H_
> +#define PEI_KEY_SERVICE_PPI_H_
> +///
> +/// KEY SERVICE PPI GUID
> +///
> +extern EFI_GUID gKeyServicePpiGuid;
> +
> +/**
> + Generate a new key from root key.
> +
> + @param[in] Salt Pointer to the salt(non-secret) value.
> + @param[in] SaltSize Salt size in bytes.
> + @param[out] NewKey Pointer to buffer to receive new key.
> + @param[in] NewKeySize Size of new key bytes to generate.
> +
> + @retval EFI_SUCCESS The function completed successfully
> + @retval OTHER The function completed with failure.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *KEY_SERVICE_GEN_KEY)(
> + IN UINT8 *Salt,
> + IN UINTN SaltSize,
> + OUT UINT8 *NewKey,
> + IN UINTN NewKeySize
> + );
> +
> +#define KEY_SERVICE_PPI_REVISION 1
> +#define ROOT_KEY_LEN 64
> +#define SALT_SIZE_MIN_LEN 64
> +#define KEY_SERVICE_KEY_NAME L"KEY_SERVICE_KEY"
> +
> +typedef struct {
> + UINT8 RootKey[ROOT_KEY_LEN];
> + UINT8 PreviousRootKey[ROOT_KEY_LEN];
> +} KEY_SERVICE_DATA;
> +
> +typedef struct _KEY_SERVICE_PPI KEY_SERVICE_PPI;
> +
> +///
> +/// KEY SERVICE PPI
> +/// The interface functions are for Key Service in PEI Phase
> +///
> +struct _KEY_SERVICE_PPI {
> + KEY_SERVICE_GEN_KEY GenerateKey; /// Generate Key
> +};
> +
> +#endif
> --
> 2.35.1.windows.2
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [Patch v2 11/28] SecurityPkg: Update RPMC APIs with index
2022-04-29 18:04 ` [Patch v2 11/28] SecurityPkg: Update RPMC APIs with index Judah Vang
@ 2022-05-22 14:07 ` Wang, Jian J
0 siblings, 0 replies; 49+ messages in thread
From: Wang, Jian J @ 2022-05-22 14:07 UTC (permalink / raw)
To: Vang, Judah, devel@edk2.groups.io; +Cc: Yao, Jiewen, Mistry, Nishant C
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
Regards,
Jian
> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Saturday, April 30, 2022 2:04 AM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [Patch v2 11/28] SecurityPkg: Update RPMC APIs with index
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> Update RPMC APIs with index parameter because sometimes
> there are more than 1 RPMC counter on the platform.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c
> b/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c
> index 792e48250e5d..557aeb6abf09 100644
> --- a/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c
> +++ b/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c
> @@ -1,7 +1,7 @@
> /** @file
> NULL RpmcLib instance for build purpose.
>
> -Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> **/
> @@ -12,6 +12,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> /**
> Requests the monotonic counter from the designated RPMC counter.
>
> + @param[in] CounterIndex The RPMC index
> @param[out] CounterValue A pointer to a buffer to store the RPMC
> value.
>
> @retval EFI_SUCCESS The operation completed successfully.
> @@ -21,6 +22,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> EFI_STATUS
> EFIAPI
> RequestMonotonicCounter (
> + IN UINT8 CounterIndex,
> OUT UINT32 *CounterValue
> )
> {
> @@ -31,6 +33,8 @@ RequestMonotonicCounter (
> /**
> Increments the monotonic counter in the SPI flash device by 1.
>
> + @param[in] CounterIndex The RPMC index
> +
> @retval EFI_SUCCESS The operation completed successfully.
> @retval EFI_DEVICE_ERROR A device error occurred while attempting
> to update the counter.
> @retval EFI_UNSUPPORTED The operation is un-supported.
> @@ -38,7 +42,7 @@ RequestMonotonicCounter (
> EFI_STATUS
> EFIAPI
> IncrementMonotonicCounter (
> - VOID
> + IN UINT8 CounterIndex
> )
> {
> ASSERT (FALSE);
> --
> 2.35.1.windows.2
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [Patch v2 12/28] SecurityPkg: Add new variable types and functions
2022-04-29 18:04 ` [Patch v2 12/28] SecurityPkg: Add new variable types and functions Judah Vang
@ 2022-05-22 14:12 ` Wang, Jian J
0 siblings, 0 replies; 49+ messages in thread
From: Wang, Jian J @ 2022-05-22 14:12 UTC (permalink / raw)
To: Vang, Judah, devel@edk2.groups.io; +Cc: Yao, Jiewen, Mistry, Nishant C
Judah,
Patch 11 is a library instance of RpmcLib which relies on changes introduced in this patch (12).
You need to put this patch before patch 11.
Regards,
Jian
> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Saturday, April 30, 2022 2:04 AM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [Patch v2 12/28] SecurityPkg: Add new variable types and functions
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> Add new variable encryption/decryption function prototypes.
> Add new variable digest structure. Add new Protected
> variable function prototypes. Update RPMC APIs to Add
> an index because there is could more than one counter.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> SecurityPkg/Include/Library/RpmcLib.h | 15 +++++---
> SecurityPkg/Include/Library/VariableKeyLib.h | 37 +++-----------------
> 2 files changed, 16 insertions(+), 36 deletions(-)
>
> diff --git a/SecurityPkg/Include/Library/RpmcLib.h
> b/SecurityPkg/Include/Library/RpmcLib.h
> index df4ba34ba8cf..cb71dfcd7e4d 100644
> --- a/SecurityPkg/Include/Library/RpmcLib.h
> +++ b/SecurityPkg/Include/Library/RpmcLib.h
> @@ -1,19 +1,23 @@
> /** @file
> Public definitions for the Replay Protected Monotonic Counter (RPMC) Library.
>
> -Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> **/
>
> -#ifndef _RPMC_LIB_H_
> -#define _RPMC_LIB_H_
> +#ifndef RPMC_LIB_H_
> +#define RPMC_LIB_H_
>
> #include <Uefi/UefiBaseType.h>
>
> +#define RPMC_COUNTER_1 0
> +#define RPMC_COUNTER_2 1
> +
> /**
> Requests the monotonic counter from the designated RPMC counter.
>
> + @param[in] CounterIndex The RPMC index
> @param[out] CounterValue A pointer to a buffer to store the RPMC
> value.
>
> @retval EFI_SUCCESS The operation completed successfully.
> @@ -23,12 +27,15 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> EFI_STATUS
> EFIAPI
> RequestMonotonicCounter (
> + IN UINT8 CounterIndex,
> OUT UINT32 *CounterValue
> );
>
> /**
> Increments the monotonic counter in the SPI flash device by 1.
>
> + @param[in] CounterIndex The RPMC index
> +
> @retval EFI_SUCCESS The operation completed successfully.
> @retval EFI_DEVICE_ERROR A device error occurred while attempting
> to update the counter.
> @retval EFI_UNSUPPORTED The operation is un-supported.
> @@ -36,7 +43,7 @@ RequestMonotonicCounter (
> EFI_STATUS
> EFIAPI
> IncrementMonotonicCounter (
> - VOID
> + IN UINT8 CounterIndex
> );
>
> #endif
> diff --git a/SecurityPkg/Include/Library/VariableKeyLib.h
> b/SecurityPkg/Include/Library/VariableKeyLib.h
> index 561ebad09da2..6076c4d4731b 100644
> --- a/SecurityPkg/Include/Library/VariableKeyLib.h
> +++ b/SecurityPkg/Include/Library/VariableKeyLib.h
> @@ -1,13 +1,13 @@
> /** @file
> Public definitions for Variable Key Library.
>
> -Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> **/
>
> -#ifndef _VARIABLE_KEY_LIB_H_
> -#define _VARIABLE_KEY_LIB_H_
> +#ifndef VARIABLE_KEY_LIB_H_
> +#define VARIABLE_KEY_LIB_H_
>
> #include <Uefi/UefiBaseType.h>
>
> @@ -25,35 +25,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> EFI_STATUS
> EFIAPI
> GetVariableKey (
> - OUT VOID **VariableKey,
> - IN OUT UINTN *VariableKeySize
> - );
> -
> -/**
> - Regenerates the variable key.
> -
> - @retval EFI_SUCCESS The variable key was regenerated successfully.
> - @retval EFI_DEVICE_ERROR An error occurred while attempting to
> regenerate the key.
> - @retval EFI_ACCESS_DENIED The function was invoked after locking
> the key interface.
> - @retval EFI_UNSUPPORTED Key regeneration is not supported in the
> current boot configuration.
> -**/
> -EFI_STATUS
> -EFIAPI
> -RegenerateVariableKey (
> - VOID
> - );
> -
> -/**
> - Locks the regenerate key interface.
> -
> - @retval EFI_SUCCESS The key interface was locked successfully.
> - @retval EFI_UNSUPPORTED Locking the key interface is not supported
> in the current boot configuration.
> - @retval Others An error occurred while attempting to lock the
> key interface.
> -**/
> -EFI_STATUS
> -EFIAPI
> -LockVariableKeyInterface (
> - VOID
> + OUT VOID *VariableKey,
> + IN UINTN VariableKeySize
> );
>
> #endif
> --
> 2.35.1.windows.2
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [Patch v2 13/28] SecurityPkg: Fix GetVariableKey API
2022-04-29 18:04 ` [Patch v2 13/28] SecurityPkg: Fix GetVariableKey API Judah Vang
@ 2022-05-22 14:15 ` Wang, Jian J
0 siblings, 0 replies; 49+ messages in thread
From: Wang, Jian J @ 2022-05-22 14:15 UTC (permalink / raw)
To: Vang, Judah, devel@edk2.groups.io; +Cc: Yao, Jiewen, Mistry, Nishant C
Judah,
My comments below
> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Saturday, April 30, 2022 2:04 AM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [Patch v2 13/28] SecurityPkg: Fix GetVariableKey API
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> Fix GetVariableKey API to match changes in header files.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c
> b/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c
> index a08def767b5f..cfbad54ba106 100644
> --- a/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c
> +++ b/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c
> @@ -1,7 +1,7 @@
> /** @file
> Null version of VariableKeyLib for build purpose. Don't use it in real product.
>
> -Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
> SPDX-License-Identifier: BSD-2-Clause-Patent
>
> **/
> @@ -22,8 +22,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> EFI_STATUS
> EFIAPI
> GetVariableKey (
> - OUT VOID **VariableKey,
> - IN OUT UINTN *VariableKeySize
> + OUT VOID *VariableKey,
> + IN UINTN VariableKeySize
[JianJW]
'OUT' is removed here but the parameter description in function comments
still declared as [in,out]. Please update the function comments in patch 12
as well.
Regards,
Jian
> )
> {
> ASSERT (FALSE);
> --
> 2.35.1.windows.2
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [Patch v2 14/28] SecurityPkg: Add null encryption variable libs
2022-04-29 18:04 ` [Patch v2 14/28] SecurityPkg: Add null encryption variable libs Judah Vang
@ 2022-05-22 14:20 ` Wang, Jian J
0 siblings, 0 replies; 49+ messages in thread
From: Wang, Jian J @ 2022-05-22 14:20 UTC (permalink / raw)
To: Vang, Judah, devel@edk2.groups.io; +Cc: Yao, Jiewen, Mistry, Nishant C
Judah,
My comments below
> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Saturday, April 30, 2022 2:04 AM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [Patch v2 14/28] SecurityPkg: Add null encryption variable libs
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
>
> Provide null ecryption variable libraries.
> These will be used by default for platforms that don't
> support protected variable encryption.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf |
> 38 +++++++
> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c | 107
> ++++++++++++++++++++
> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni |
> 16 +++
> 3 files changed, 161 insertions(+)
>
> diff --git
> a/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
> b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
> new file mode 100644
> index 000000000000..ff5631b336eb
> --- /dev/null
> +++
> b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
> @@ -0,0 +1,38 @@
> +## @file
> +# Provides NULL version of encryption variable services.
> +#
> +# Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = EncryptionVariableLibNull
> + MODULE_UNI_FILE = EncryptionVariableLib.uni
> + FILE_GUID = 3972E6FE-74D5-45C3-A9FB-DB9E5E5C9C17
> + MODULE_TYPE = BASE
> + VERSION_STRING = 1.0
> + LIBRARY_CLASS = EncryptionVariableLib
> +
> +#
> +# The following information is for reference only and not required by the build
> tools.
> +#
> +# VALID_ARCHITECTURES = IA32 X64
> +#
> +
> +[Sources]
> + EncryptionVariable.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> + SecurityPkg/SecurityPkg.dec
> +
> +[LibraryClasses]
> + BaseLib
> + DebugLib
> +
> +[Guids]
[JianJW]
No GUID consumed here. Suggest removing this section.
> +
> diff --git a/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
> b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
> new file mode 100644
> index 000000000000..58a4ae9f4282
> --- /dev/null
> +++ b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
> @@ -0,0 +1,107 @@
> +/** @file
> + The common variable operation routines shared by DXE_RUNTIME variable
> + module and DXE_SMM variable module.
> +
> + Caution: This module requires additional review when modified.
> + This driver will have external input - variable data. They may be input in SMM
> mode.
> + This external input must be validated carefully to avoid security issue like
> + buffer overflow, integer overflow.
> +
> + VariableServiceGetNextVariableName () and
> VariableServiceQueryVariableInfo() are external API.
> + They need check input parameter.
> +
> + VariableServiceGetVariable() and VariableServiceSetVariable() are external API
> + to receive datasize and data buffer. The size should be checked carefully.
> +
> + VariableServiceSetVariable() should also check authenticate data to avoid
> buffer overflow,
> + integer overflow. It should also check attribute to avoid authentication bypass.
> +
[JianJW]
The file header comment seems irrelevant.
> +Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Uefi.h>
> +
> +#include <Library/EncryptionVariableLib.h>
> +#include <Library/DebugLib.h>
> +
> +/**
> + Encrypt variable data.
> +
> + Null version.
> +
> + @param[in, out] VarEncInfo Pointer to structure containing detailed
> + information about a variable.
> +
> + @retval EFI_UNSUPPORTED Unsupported to encrypt variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +EncryptVariable (
> + IN OUT VARIABLE_ENCRYPTION_INFO *VarEncInfo
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> + Decrypt variable data.
> +
> + Null version.
> +
> + @param[in, out] VarEncInfo Pointer to structure containing detailed
> + information about a variable.
> +
> + @retval EFI_UNSUPPORTED Unsupported to encrypt variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DecryptVariable (
> + IN OUT VARIABLE_ENCRYPTION_INFO *VarEncInfo
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> + Get cipher information.
> +
> + Null version.
> +
> + @param[in] VarEncInfo Pointer to structure containing detailed
> + information about a variable.
> +
> + @retval EFI_UNSUPPORTED Unsupported interface.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetCipherDataInfo (
> + IN VARIABLE_ENCRYPTION_INFO *VarEncInfo
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> + Set cipher information for a variable.
> +
> + Null version.
> +
> + @param[in] VarEncInfo Pointer to structure containing detailed
> + information about a variable.
> +
> + @retval EFI_UNSUPPORTED If this method is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetCipherDataInfo (
> + IN VARIABLE_ENCRYPTION_INFO *VarEncInfo
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> diff --git
> a/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni
> b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni
> new file mode 100644
> index 000000000000..856fa201b8df
> --- /dev/null
> +++
> b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni
> @@ -0,0 +1,16 @@
> +// /** @file
> +// Provides authenticated variable services.
> +//
> +// Provides authenticated variable services.
> +//
[JianJW]
The file header is irrelevant.
Regards,
Jian
> +// Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT #language en-US "Provides
> authenticated variable services"
> +
> +#string STR_MODULE_DESCRIPTION #language en-US "Provides
> authenticated variable services."
> +
> --
> 2.35.1.windows.2
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [edk2-devel] [Patch v2 00/28] UEFI variable protection
[not found] ` <16EFC4965F71DFB8.20068@groups.io>
@ 2022-06-16 19:13 ` Michael Kubacki
2022-08-23 3:35 ` Michael Kubacki
0 siblings, 1 reply; 49+ messages in thread
From: Michael Kubacki @ 2022-06-16 19:13 UTC (permalink / raw)
To: devel, judah.vang
Do you have the data below?
This is important for platform adoption and would be useful to include
in the following section.
https://github.com/judahvang/edk2/tree/rpmc-update#platform-integration-considerations
Thanks,
Michael
On 5/16/2022 10:48 PM, Michael Kubacki wrote:
> Hi Judah,
>
> Do you have reference information for the following?
>
> 1. Overall boot time impact for a sample variable store?
>
> - In particular:
> - Initial HMAC calculation/verification time.
> - Non-volatile write impact time to caluclate new store HMAC value
> and update MetaDataHmacVar.
> - Variable reclaim before and after time.
>
> 2. Overall non-volatile store size overhead impact with AES-CBC
> encrypted variables?
>
> I understand these will vary based on system properties like SPI flash
> parameters, cryptographic processor details, etc. I'm trying to get an
> idea of the impact from sample data or averages on a particular system
> configuration. Also to learn whether the native encryption instruction
> (AES-NI) was used and if that could provide any benefit given the
> potential number of encryption/decryption operations introduced.
>
> For the code design, I feel the ProtectedVariableLib interface is a bit
> too coupled against internal implementation details of the variable
> driver. I generally understand why the code is split out to wrap
> operations around the new functionality and it follows the AuthVarLib
> pattern but changing the library or driver will continue to require
> large changes across both like this due to the coupling.
>
> Small things I noticed:
> 1. VariableKeyLib.inf should not be "BASE", it directly depends on PEI
> services
> 2. Typo "varabile" in some files
> 3. Does ProtectedVariableLibNull actually need to depend on BaseMemoryLib?
>
> Thanks,
> Michael
>
> On 4/29/2022 2:04 PM, Judah Vang wrote:
>> For a more detail description of the UEFI variable protected feature
>> you can
>> view the Readme.md located at the following location:
>> https://github.com/judahvang/edk2/tree/rpmc-update
>>
>>
>> Judah Vang (28):
>> MdeModulePkg: Add new GUID for Variable Store Info
>> SecurityPkg: Add new GUIDs for
>> MdeModulePkg: Update AUTH_VARIABLE_INFO struct
>> MdeModulePkg: Add reference to new Ppi Guid
>> MdeModulePkg: Add new ProtectedVariable GUIDs
>> MdeModulePkg: Add new include files
>> MdeModulePkg: Add Null ProtectedVariable Library
>> MdeModulePkg: Add new Variable functionality
>> MdeModulePkg: Add support for Protected Variables
>> SecurityPkg: Add new KeyService types and defines
>> SecurityPkg: Update RPMC APIs with index
>> SecurityPkg: Add new variable types and functions
>> SecurityPkg: Fix GetVariableKey API
>> SecurityPkg: Add null encryption variable libs
>> SecurityPkg: Add VariableKey library function
>> SecurityPkg: Add EncryptionVariable lib with AES
>> SecurityPkg: Add Protected Variable Services
>> MdeModulePkg: Reference Null ProtectedVariableLib
>> SecurityPkg: Add references to new *.inf files
>> ArmVirtPkg: Add reference to ProtectedVariableNull
>> UefiPayloadPkg: Add ProtectedVariable reference
>> EmulatorPkg: Add ProtectedVariable reference
>> OvmfPkg: Add ProtectedVariable reference
>> OvmfPkg: Add ProtectedVariableLib reference
>> OvmfPkg: Add ProtectedVariableLib reference
>> OvmfPkg: Add ProtectedVariableLib reference
>> OvmfPkg: Add ProtectedVariable reference
>> CryptoPkg: Enable cypto HMAC KDF library
>>
>>
>> MdeModulePkg/MdeModulePkg.dec
>> | 13 +-
>>
>> SecurityPkg/SecurityPkg.dec
>> | 43 +-
>>
>> ArmVirtPkg/ArmVirtQemu.dsc
>> | 3 +-
>>
>> EmulatorPkg/EmulatorPkg.dsc
>> | 3 +-
>>
>> MdeModulePkg/MdeModulePkg.dsc
>> | 4 +-
>>
>> OvmfPkg/AmdSev/AmdSevX64.dsc
>> | 3 +-
>>
>> OvmfPkg/Bhyve/BhyveX64.dsc
>> | 3 +-
>>
>> OvmfPkg/CloudHv/CloudHvX64.dsc
>> | 1 +
>>
>> OvmfPkg/Microvm/MicrovmX64.dsc
>> | 3 +-
>>
>> OvmfPkg/OvmfPkgIa32.dsc
>> | 1 +
>>
>> OvmfPkg/OvmfPkgIa32X64.dsc
>> | 1 +
>>
>> OvmfPkg/OvmfPkgX64.dsc
>> | 1 +
>>
>> OvmfPkg/OvmfXen.dsc
>> | 3 +-
>>
>> SecurityPkg/SecurityPkg.dsc
>> | 13 +-
>>
>> UefiPayloadPkg/UefiPayloadPkg.dsc
>> | 2 +
>>
>> CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
>> | 2 +-
>>
>> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
>> | 34 +
>>
>> MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
>> | 10 +-
>>
>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
>> | 3 +-
>>
>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
>> | 3 +-
>>
>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>> | 4 +-
>>
>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
>> | 3 +-
>>
>> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
>> | 43 +
>>
>> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
>> | 38 +
>>
>> SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
>> | 64 +
>>
>> SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
>> | 68 +
>>
>> SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
>> | 67 +
>>
>> SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf
>> | 62 +
>>
>> SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
>> | 36 +
>>
>> MdeModulePkg/Include/Guid/ProtectedVariable.h
>> | 22 +
>>
>> MdeModulePkg/Include/Library/AuthVariableLib.h
>> | 4 +-
>>
>> MdeModulePkg/Include/Library/EncryptionVariableLib.h
>> | 165 ++
>>
>> MdeModulePkg/Include/Library/ProtectedVariableLib.h
>> | 700 +++++++
>>
>> MdeModulePkg/Universal/Variable/Pei/Variable.h
>> | 80 +-
>>
>> MdeModulePkg/Universal/Variable/Pei/VariableParsing.h
>> | 309 +++
>>
>> MdeModulePkg/Universal/Variable/Pei/VariableStore.h
>> | 116 ++
>>
>> MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
>> | 126 +-
>>
>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
>> | 91 +-
>>
>> MdePkg/Include/Ppi/ReadOnlyVariable2.h
>> | 4 +-
>>
>> SecurityPkg/Include/Library/RpmcLib.h
>> | 15 +-
>>
>> SecurityPkg/Include/Library/VariableKeyLib.h
>> | 37 +-
>>
>> SecurityPkg/Include/Ppi/KeyServicePpi.h
>> | 57 +
>>
>> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
>> | 49 +
>>
>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
>> | 611 ++++++
>>
>> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
>> | 449 ++++
>>
>> MdeModulePkg/Universal/Variable/Pei/Variable.c
>> | 886 ++------
>>
>> MdeModulePkg/Universal/Variable/Pei/VariableParsing.c
>> | 941 +++++++++
>>
>> MdeModulePkg/Universal/Variable/Pei/VariableStore.c
>> | 305 +++
>>
>> MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
>> | 349 +++-
>>
>> MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
>> | 2139 +++++++++++---------
>>
>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
>> | 26 +-
>>
>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
>> | 167 +-
>>
>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
>> | 194 +-
>>
>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
>> | 320 ++-
>>
>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
>> | 2 +-
>>
>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
>> | 39 +-
>>
>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
>> | 41 +-
>>
>> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
>> | 728 +++++++
>>
>> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
>> | 107 +
>>
>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
>> | 2095 +++++++++++++++++++
>>
>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
>> | 163 ++
>>
>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
>> | 1331 ++++++++++++
>>
>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
>> | 209 ++
>>
>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c
>> | 975 +++++++++
>>
>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
>> | 233 +++
>>
>> SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c
>> | 8 +-
>>
>> SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c
>> | 59 +
>>
>> SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c
>> | 6 +-
>>
>> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni
>> | 16 +
>> 69 files changed, 12845 insertions(+), 1863 deletions(-)
>> create mode 100644
>> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
>>
>> create mode 100644
>> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
>> create mode 100644
>> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
>>
>> create mode 100644
>> SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
>> create mode 100644
>> SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
>> create mode 100644
>> SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
>> create mode 100644
>> SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf
>>
>> create mode 100644
>> SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
>> create mode 100644 MdeModulePkg/Include/Guid/ProtectedVariable.h
>> create mode 100644 MdeModulePkg/Include/Library/EncryptionVariableLib.h
>> create mode 100644 MdeModulePkg/Include/Library/ProtectedVariableLib.h
>> create mode 100644
>> MdeModulePkg/Universal/Variable/Pei/VariableParsing.h
>> create mode 100644 MdeModulePkg/Universal/Variable/Pei/VariableStore.h
>> create mode 100644 SecurityPkg/Include/Ppi/KeyServicePpi.h
>> create mode 100644
>> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
>> create mode 100644
>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
>> create mode 100644
>> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
>> create mode 100644
>> MdeModulePkg/Universal/Variable/Pei/VariableParsing.c
>> create mode 100644 MdeModulePkg/Universal/Variable/Pei/VariableStore.c
>> create mode 100644
>> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
>> create mode 100644
>> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
>> create mode 100644
>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
>> create mode 100644
>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
>> create mode 100644
>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
>> create mode 100644
>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
>> create mode 100644
>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c
>> create mode 100644
>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
>> create mode 100644 SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c
>> create mode 100644
>> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni
>>
>>
>
>
>
>
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [edk2-devel] [Patch v2 00/28] UEFI variable protection
2022-06-16 19:13 ` Michael Kubacki
@ 2022-08-23 3:35 ` Michael Kubacki
0 siblings, 0 replies; 49+ messages in thread
From: Michael Kubacki @ 2022-08-23 3:35 UTC (permalink / raw)
To: devel, judah.vang
Hi Judah,
Just wanted to send a reminder to see if you have this data from your
testing.
Thanks,
Michael
On 6/16/2022 3:13 PM, Michael Kubacki wrote:
> Do you have the data below?
>
> This is important for platform adoption and would be useful to include
> in the following section.
>
> https://github.com/judahvang/edk2/tree/rpmc-update#platform-integration-considerations
>
>
> Thanks,
> Michael
>
> On 5/16/2022 10:48 PM, Michael Kubacki wrote:
>> Hi Judah,
>>
>> Do you have reference information for the following?
>>
>> 1. Overall boot time impact for a sample variable store?
>>
>> - In particular:
>> - Initial HMAC calculation/verification time.
>> - Non-volatile write impact time to caluclate new store HMAC value
>> and update MetaDataHmacVar.
>> - Variable reclaim before and after time.
>>
>> 2. Overall non-volatile store size overhead impact with AES-CBC
>> encrypted variables?
>>
>> I understand these will vary based on system properties like SPI flash
>> parameters, cryptographic processor details, etc. I'm trying to get an
>> idea of the impact from sample data or averages on a particular system
>> configuration. Also to learn whether the native encryption instruction
>> (AES-NI) was used and if that could provide any benefit given the
>> potential number of encryption/decryption operations introduced.
>>
>> For the code design, I feel the ProtectedVariableLib interface is a
>> bit too coupled against internal implementation details of the
>> variable driver. I generally understand why the code is split out to
>> wrap operations around the new functionality and it follows the
>> AuthVarLib pattern but changing the library or driver will continue to
>> require large changes across both like this due to the coupling.
>>
>> Small things I noticed:
>> 1. VariableKeyLib.inf should not be "BASE", it directly depends on PEI
>> services
>> 2. Typo "varabile" in some files
>> 3. Does ProtectedVariableLibNull actually need to depend on
>> BaseMemoryLib?
>>
>> Thanks,
>> Michael
>>
>> On 4/29/2022 2:04 PM, Judah Vang wrote:
>>> For a more detail description of the UEFI variable protected feature
>>> you can
>>> view the Readme.md located at the following location:
>>> https://github.com/judahvang/edk2/tree/rpmc-update
>>>
>>>
>>> Judah Vang (28):
>>> MdeModulePkg: Add new GUID for Variable Store Info
>>> SecurityPkg: Add new GUIDs for
>>> MdeModulePkg: Update AUTH_VARIABLE_INFO struct
>>> MdeModulePkg: Add reference to new Ppi Guid
>>> MdeModulePkg: Add new ProtectedVariable GUIDs
>>> MdeModulePkg: Add new include files
>>> MdeModulePkg: Add Null ProtectedVariable Library
>>> MdeModulePkg: Add new Variable functionality
>>> MdeModulePkg: Add support for Protected Variables
>>> SecurityPkg: Add new KeyService types and defines
>>> SecurityPkg: Update RPMC APIs with index
>>> SecurityPkg: Add new variable types and functions
>>> SecurityPkg: Fix GetVariableKey API
>>> SecurityPkg: Add null encryption variable libs
>>> SecurityPkg: Add VariableKey library function
>>> SecurityPkg: Add EncryptionVariable lib with AES
>>> SecurityPkg: Add Protected Variable Services
>>> MdeModulePkg: Reference Null ProtectedVariableLib
>>> SecurityPkg: Add references to new *.inf files
>>> ArmVirtPkg: Add reference to ProtectedVariableNull
>>> UefiPayloadPkg: Add ProtectedVariable reference
>>> EmulatorPkg: Add ProtectedVariable reference
>>> OvmfPkg: Add ProtectedVariable reference
>>> OvmfPkg: Add ProtectedVariableLib reference
>>> OvmfPkg: Add ProtectedVariableLib reference
>>> OvmfPkg: Add ProtectedVariableLib reference
>>> OvmfPkg: Add ProtectedVariable reference
>>> CryptoPkg: Enable cypto HMAC KDF library
>>>
>>> MdeModulePkg/MdeModulePkg.dec | 13 +-
>>> SecurityPkg/SecurityPkg.dec | 43 +-
>>> ArmVirtPkg/ArmVirtQemu.dsc | 3 +-
>>> EmulatorPkg/EmulatorPkg.dsc | 3 +-
>>> MdeModulePkg/MdeModulePkg.dsc | 4 +-
>>> OvmfPkg/AmdSev/AmdSevX64.dsc | 3 +-
>>> OvmfPkg/Bhyve/BhyveX64.dsc | 3 +-
>>> OvmfPkg/CloudHv/CloudHvX64.dsc | 1 +
>>> OvmfPkg/Microvm/MicrovmX64.dsc | 3 +-
>>> OvmfPkg/OvmfPkgIa32.dsc | 1 +
>>> OvmfPkg/OvmfPkgIa32X64.dsc | 1 +
>>> OvmfPkg/OvmfPkgX64.dsc | 1 +
>>> OvmfPkg/OvmfXen.dsc | 3 +-
>>> SecurityPkg/SecurityPkg.dsc | 13 +-
>>> UefiPayloadPkg/UefiPayloadPkg.dsc | 2 +
>>> CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf | 2 +-
>>> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
>>> | 34 +
>>> MdeModulePkg/Universal/Variable/Pei/VariablePei.inf | 10 +-
>>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
>>> | 3 +-
>>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf | 3 +-
>>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>>> | 4 +-
>>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
>>> | 3 +-
>>> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
>>> | 43 +
>>> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
>>> | 38 +
>>> SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
>>> | 64 +
>>> SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
>>> | 68 +
>>> SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
>>> | 67 +
>>> SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf
>>> | 62 +
>>> SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf | 36 +
>>> MdeModulePkg/Include/Guid/ProtectedVariable.h | 22 +
>>> MdeModulePkg/Include/Library/AuthVariableLib.h | 4 +-
>>> MdeModulePkg/Include/Library/EncryptionVariableLib.h | 165 ++
>>> MdeModulePkg/Include/Library/ProtectedVariableLib.h | 700 +++++++
>>> MdeModulePkg/Universal/Variable/Pei/Variable.h | 80 +-
>>> MdeModulePkg/Universal/Variable/Pei/VariableParsing.h | 309 +++
>>> MdeModulePkg/Universal/Variable/Pei/VariableStore.h | 116 ++
>>> MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h | 126 +-
>>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h | 91 +-
>>> MdePkg/Include/Ppi/ReadOnlyVariable2.h | 4 +-
>>> SecurityPkg/Include/Library/RpmcLib.h | 15 +-
>>> SecurityPkg/Include/Library/VariableKeyLib.h | 37 +-
>>> SecurityPkg/Include/Ppi/KeyServicePpi.h | 57 +
>>> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h | 49 +
>>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
>>> | 611 ++++++
>>> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c |
>>> 449 ++++
>>> MdeModulePkg/Universal/Variable/Pei/Variable.c | 886 ++------
>>> MdeModulePkg/Universal/Variable/Pei/VariableParsing.c | 941 +++++++++
>>> MdeModulePkg/Universal/Variable/Pei/VariableStore.c | 305 +++
>>> MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c | 349 +++-
>>> MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c | 2139
>>> +++++++++++---------
>>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c | 26 +-
>>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c | 167 +-
>>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c |
>>> 194 +-
>>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c | 320 ++-
>>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
>>> | 2 +-
>>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c | 39 +-
>>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
>>> | 41 +-
>>> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c | 728
>>> +++++++
>>> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c |
>>> 107 +
>>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c |
>>> 2095 +++++++++++++++++++
>>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c |
>>> 163 ++
>>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c |
>>> 1331 ++++++++++++
>>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c |
>>> 209 ++
>>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c
>>> | 975 +++++++++
>>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c |
>>> 233 +++
>>> SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c | 8 +-
>>> SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c | 59 +
>>> SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c | 6 +-
>>> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni
>>> | 16 +
>>> 69 files changed, 12845 insertions(+), 1863 deletions(-)
>>> create mode 100644
>>> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
>>>
>>> create mode 100644
>>> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
>>> create mode 100644
>>> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
>>>
>>> create mode 100644
>>> SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
>>> create mode 100644
>>> SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
>>> create mode 100644
>>> SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
>>> create mode 100644
>>> SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf
>>>
>>> create mode 100644
>>> SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
>>> create mode 100644 MdeModulePkg/Include/Guid/ProtectedVariable.h
>>> create mode 100644
>>> MdeModulePkg/Include/Library/EncryptionVariableLib.h
>>> create mode 100644 MdeModulePkg/Include/Library/ProtectedVariableLib.h
>>> create mode 100644
>>> MdeModulePkg/Universal/Variable/Pei/VariableParsing.h
>>> create mode 100644 MdeModulePkg/Universal/Variable/Pei/VariableStore.h
>>> create mode 100644 SecurityPkg/Include/Ppi/KeyServicePpi.h
>>> create mode 100644
>>> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
>>> create mode 100644
>>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
>>> create mode 100644
>>> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
>>> create mode 100644
>>> MdeModulePkg/Universal/Variable/Pei/VariableParsing.c
>>> create mode 100644 MdeModulePkg/Universal/Variable/Pei/VariableStore.c
>>> create mode 100644
>>> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
>>> create mode 100644
>>> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
>>> create mode 100644
>>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
>>> create mode 100644
>>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
>>> create mode 100644
>>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
>>> create mode 100644
>>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
>>> create mode 100644
>>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c
>>> create mode 100644
>>> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
>>> create mode 100644 SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c
>>> create mode 100644
>>> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.uni
>>>
>>>
>>
>>
>>
>>
^ permalink raw reply [flat|nested] 49+ messages in thread
end of thread, other threads:[~2022-08-23 3:35 UTC | newest]
Thread overview: 49+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-04-29 18:04 [Patch v2 00/28] UEFI variable protection Judah Vang
2022-04-29 18:04 ` [Patch v2 01/28] MdeModulePkg: Add new GUID for Variable Store Info Judah Vang
2022-05-12 9:32 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 02/28] SecurityPkg: Add new GUIDs for Judah Vang
2022-05-12 9:33 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 03/28] MdeModulePkg: Update AUTH_VARIABLE_INFO struct Judah Vang
2022-05-12 9:33 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 04/28] MdeModulePkg: Add reference to new Ppi Guid Judah Vang
2022-05-12 9:32 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 05/28] MdeModulePkg: Add new ProtectedVariable GUIDs Judah Vang
2022-05-12 9:32 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 06/28] MdeModulePkg: Add new include files Judah Vang
2022-05-12 9:31 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 07/28] MdeModulePkg: Add Null ProtectedVariable Library Judah Vang
2022-05-22 8:38 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 08/28] MdeModulePkg: Add new Variable functionality Judah Vang
2022-05-22 10:24 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 09/28] MdeModulePkg: Add support for Protected Variables Judah Vang
2022-05-22 14:03 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 10/28] SecurityPkg: Add new KeyService types and defines Judah Vang
2022-05-22 14:06 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 11/28] SecurityPkg: Update RPMC APIs with index Judah Vang
2022-05-22 14:07 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 12/28] SecurityPkg: Add new variable types and functions Judah Vang
2022-05-22 14:12 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 13/28] SecurityPkg: Fix GetVariableKey API Judah Vang
2022-05-22 14:15 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 14/28] SecurityPkg: Add null encryption variable libs Judah Vang
2022-05-22 14:20 ` Wang, Jian J
2022-04-29 18:04 ` [Patch v2 15/28] SecurityPkg: Add VariableKey library function Judah Vang
2022-04-29 18:04 ` [Patch v2 16/28] SecurityPkg: Add EncryptionVariable lib with AES Judah Vang
2022-04-29 18:04 ` [Patch v2 17/28] SecurityPkg: Add Protected Variable Services Judah Vang
2022-04-29 18:04 ` [Patch v2 18/28] MdeModulePkg: Reference Null ProtectedVariableLib Judah Vang
2022-04-29 18:04 ` [Patch v2 19/28] SecurityPkg: Add references to new *.inf files Judah Vang
2022-04-29 18:04 ` [Patch v2 20/28] ArmVirtPkg: Add reference to ProtectedVariableNull Judah Vang
2022-05-03 7:29 ` Ard Biesheuvel
2022-04-29 18:04 ` [Patch v2 21/28] UefiPayloadPkg: Add ProtectedVariable reference Judah Vang
2022-04-29 21:03 ` Guo Dong
2022-04-29 18:04 ` [Patch v2 22/28] EmulatorPkg: " Judah Vang
2022-04-29 18:04 ` [Patch v2 23/28] OvmfPkg: " Judah Vang
2022-04-29 18:04 ` [Patch v2 24/28] OvmfPkg: Add ProtectedVariableLib reference Judah Vang
2022-04-29 18:04 ` [Patch v2 25/28] " Judah Vang
2022-04-29 18:04 ` [Patch v2 26/28] " Judah Vang
2022-04-29 18:04 ` [Patch v2 27/28] OvmfPkg: Add ProtectedVariable reference Judah Vang
2022-05-03 7:30 ` [edk2-devel] " Ard Biesheuvel
2022-04-29 18:04 ` [Patch v2 28/28] CryptoPkg: Enable cypto HMAC KDF library Judah Vang
2022-05-17 2:48 ` [edk2-devel] [Patch v2 00/28] UEFI variable protection Michael Kubacki
[not found] ` <16EFC4965F71DFB8.20068@groups.io>
2022-06-16 19:13 ` Michael Kubacki
2022-08-23 3:35 ` Michael Kubacki
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox