From fa0737a839d070be2a53016a16abba29502b2510 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Wed, 1 Jul 2015 03:08:29 +0000 Subject: [PATCH] MdeModulePkg Variable: Merge from Auth Variable driver in SecurityPkg What to do: 1. Merge from Auth Variable driver in SecurityPkg to Variable drive in MdeModulePkg. Then the merged Variable driver in MdeModulePkg will link to AuthVariableLib and TpmMeasurementLib. AuthVariableLibNull and TpmMeasurementLibNull in MdeModulePkg could be used for non auth variable support. AuthVariableLib and DxeTpmMeasurementLib in SecurityPkg may be used for auth variable support. Why to do: 1. Remove code duplication and reduce maintenance effort. After auth variable service separated from Auth Variable driver in SecurityPkg to AuthVariableLib. The remaining code logic of Auth Variable driver in SecurityPkg will be almost same with Variable driver in MdeModulePkg. Now it is to merge them. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17765 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Include/Guid/SmmVariableCommon.h | 36 +- .../Variable/RuntimeDxe/Measurement.c | 255 ++++ .../Universal/Variable/RuntimeDxe/Reclaim.c | 5 +- .../Universal/Variable/RuntimeDxe/VarCheck.c | 246 ++-- .../Universal/Variable/RuntimeDxe/Variable.c | 1162 +++++++++++++---- .../Universal/Variable/RuntimeDxe/Variable.h | 473 +++++-- .../Variable/RuntimeDxe/VariableDxe.c | 83 +- .../Variable/RuntimeDxe/VariableExLib.c | 256 ++++ .../RuntimeDxe/VariableRuntimeDxe.inf | 48 +- .../RuntimeDxe/VariableRuntimeDxe.uni | Bin 2588 -> 3148 bytes .../Variable/RuntimeDxe/VariableSmm.c | 147 ++- .../Variable/RuntimeDxe/VariableSmm.inf | 65 +- .../Variable/RuntimeDxe/VariableSmm.uni | Bin 3746 -> 4452 bytes .../Variable/RuntimeDxe/VariableSmmExtra.uni | Bin 1348 -> 1332 bytes .../RuntimeDxe/VariableSmmRuntimeDxe.c | 214 ++- .../RuntimeDxe/VariableSmmRuntimeDxe.inf | 43 +- 16 files changed, 2347 insertions(+), 686 deletions(-) create mode 100644 MdeModulePkg/Universal/Variable/RuntimeDxe/Measurement.c create mode 100644 MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c diff --git a/MdeModulePkg/Include/Guid/SmmVariableCommon.h b/MdeModulePkg/Include/Guid/SmmVariableCommon.h index e92ab7fe79..734eb19681 100644 --- a/MdeModulePkg/Include/Guid/SmmVariableCommon.h +++ b/MdeModulePkg/Include/Guid/SmmVariableCommon.h @@ -2,12 +2,12 @@ The file defined some common structures used for communicating between SMM variable module and SMM variable wrapper module. Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-This program and the accompanying materials are licensed and made available under -the terms and conditions of the BSD License that accompanies this distribution. +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php. +http://opensource.org/licenses/bsd-license.php. -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ @@ -23,8 +23,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. extern EFI_GUID gSmmVariableWriteGuid; // -// This structure is used for SMM variable. the collected statistics data is saved in SMRAM. It can be got from -// SMI handler. The communication buffer should be: +// This structure is used for SMM variable. the collected statistics data is saved in SMRAM. It can be got from +// SMI handler. The communication buffer should be: // EFI_SMM_COMMUNICATE_HEADER + SMM_VARIABLE_COMMUNICATE_HEADER + payload. // typedef struct { @@ -39,26 +39,26 @@ typedef struct { #define SMM_VARIABLE_FUNCTION_GET_VARIABLE 1 // // The payload for this function is SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME. -// +// #define SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME 2 // // The payload for this function is SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE. -// +// #define SMM_VARIABLE_FUNCTION_SET_VARIABLE 3 // // The payload for this function is SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO. -// +// #define SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO 4 // // It is a notify event, no extra payload for this function. -// +// #define SMM_VARIABLE_FUNCTION_READY_TO_BOOT 5 // // It is a notify event, no extra payload for this function. -// +// #define SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE 6 // -// The payload for this function is VARIABLE_INFO_ENTRY. The GUID in EFI_SMM_COMMUNICATE_HEADER +// The payload for this function is VARIABLE_INFO_ENTRY. The GUID in EFI_SMM_COMMUNICATE_HEADER // is gEfiSmmVariableProtocolGuid. // #define SMM_VARIABLE_FUNCTION_GET_STATISTICS 7 @@ -71,6 +71,8 @@ typedef struct { #define SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET 10 +#define SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE 11 + /// /// Size of SMM communicate header, without including the payload. /// @@ -88,7 +90,7 @@ typedef struct { EFI_GUID Guid; UINTN DataSize; UINTN NameSize; - UINT32 Attributes; + UINT32 Attributes; CHAR16 Name[1]; } SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE; @@ -108,7 +110,7 @@ typedef struct { UINT64 MaximumVariableStorageSize; UINT64 RemainingVariableStorageSize; UINT64 MaximumVariableSize; - UINT32 Attributes; + UINT32 Attributes; } SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO; typedef SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE; @@ -120,4 +122,8 @@ typedef struct { CHAR16 Name[1]; } SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY; -#endif // _SMM_VARIABLE_COMMON_H_ \ No newline at end of file +typedef struct { + UINTN VariablePayloadSize; +} SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE; + +#endif // _SMM_VARIABLE_COMMON_H_ diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Measurement.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Measurement.c new file mode 100644 index 0000000000..2f92fae310 --- /dev/null +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Measurement.c @@ -0,0 +1,255 @@ +/** @file + Measure TrEE required variable. + +Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + CHAR16 *VariableName; + EFI_GUID *VendorGuid; +} VARIABLE_TYPE; + +VARIABLE_TYPE mVariableType[] = { + {EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid}, + {EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid}, + {EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid}, + {EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid}, + {EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid}, +}; + +/** + This function will return if this variable is SecureBootPolicy Variable. + + @param[in] VariableName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + + @retval TRUE This is SecureBootPolicy Variable + @retval FALSE This is not SecureBootPolicy Variable +**/ +BOOLEAN +IsSecureBootPolicyVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid + ) +{ + UINTN Index; + + for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) { + if ((StrCmp (VariableName, mVariableType[Index].VariableName) == 0) && + (CompareGuid (VendorGuid, mVariableType[Index].VendorGuid))) { + return TRUE; + } + } + return FALSE; +} + +/** + Measure and log an EFI variable, and extend the measurement result into a specific PCR. + + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[in] VarData The content of the variable data. + @param[in] VarSize The size of the variable data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +MeasureVariable ( + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + IN VOID *VarData, + IN UINTN VarSize + ) +{ + EFI_STATUS Status; + UINTN VarNameLength; + EFI_VARIABLE_DATA_TREE *VarLog; + UINT32 VarLogSize; + + ASSERT ((VarSize == 0 && VarData == NULL) || (VarSize != 0 && VarData != NULL)); + + VarNameLength = StrLen (VarName); + VarLogSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize + - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData)); + + VarLog = (EFI_VARIABLE_DATA_TREE *) AllocateZeroPool (VarLogSize); + if (VarLog == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (&VarLog->VariableName, VendorGuid, sizeof(VarLog->VariableName)); + VarLog->UnicodeNameLength = VarNameLength; + VarLog->VariableDataLength = VarSize; + CopyMem ( + VarLog->UnicodeName, + VarName, + VarNameLength * sizeof (*VarName) + ); + if (VarSize != 0) { + CopyMem ( + (CHAR16 *)VarLog->UnicodeName + VarNameLength, + VarData, + VarSize + ); + } + + DEBUG ((EFI_D_INFO, "AuthVariableDxe: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)7, (UINTN)EV_EFI_VARIABLE_AUTHORITY)); + DEBUG ((EFI_D_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid)); + + Status = TpmMeasureAndLogData ( + 7, + EV_EFI_VARIABLE_DRIVER_CONFIG, + VarLog, + VarLogSize, + VarLog, + VarLogSize + ); + FreePool (VarLog); + return Status; +} + +/** + Returns the status whether get the variable success. The function retrieves + variable through the UEFI Runtime Service GetVariable(). The + returned buffer is allocated using AllocatePool(). The caller is responsible + for freeing this buffer with FreePool(). + + This API is only invoked in boot time. It may NOT be invoked at runtime. + + @param[in] Name The pointer to a Null-terminated Unicode string. + @param[in] Guid The pointer to an EFI_GUID structure + @param[out] Value The buffer point saved the variable info. + @param[out] Size The buffer size of the variable. + + @return EFI_OUT_OF_RESOURCES Allocate buffer failed. + @return EFI_SUCCESS Find the specified variable. + @return Others Errors Return errors from call to gRT->GetVariable. + +**/ +EFI_STATUS +InternalGetVariable ( + IN CONST CHAR16 *Name, + IN CONST EFI_GUID *Guid, + OUT VOID **Value, + OUT UINTN *Size + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + + // + // Try to get the variable size. + // + BufferSize = 0; + *Value = NULL; + if (Size != NULL) { + *Size = 0; + } + + Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value); + if (Status != EFI_BUFFER_TOO_SMALL) { + return Status; + } + + // + // Allocate buffer to get the variable. + // + *Value = AllocatePool (BufferSize); + ASSERT (*Value != NULL); + if (*Value == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Get the variable data. + // + Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value); + if (EFI_ERROR (Status)) { + FreePool(*Value); + *Value = NULL; + } + + if (Size != NULL) { + *Size = BufferSize; + } + + return Status; +} + +/** + SecureBoot Hook for SetVariable. + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + +**/ +VOID +EFIAPI +SecureBootHook ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid + ) +{ + EFI_STATUS Status; + UINTN VariableDataSize; + VOID *VariableData; + + if (!IsSecureBootPolicyVariable (VariableName, VendorGuid)) { + return ; + } + + // + // We should NOT use Data and DataSize here,because it may include signature, + // or is just partial with append attributes, or is deleted. + // We should GetVariable again, to get full variable content. + // + Status = InternalGetVariable ( + VariableName, + VendorGuid, + &VariableData, + &VariableDataSize + ); + if (EFI_ERROR (Status)) { + VariableData = NULL; + VariableDataSize = 0; + } + + Status = MeasureVariable ( + VariableName, + VendorGuid, + VariableData, + VariableDataSize + ); + DEBUG ((EFI_D_INFO, "MeasureBootPolicyVariable - %r\n", Status)); + + if (VariableData != NULL) { + FreePool (VariableData); + } + + return ; +} diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c index 44c56e232f..616812ccd8 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c @@ -1,9 +1,8 @@ /** @file - Handles non-volatile variable store garbage collection, using FTW (Fault Tolerant Write) protocol. -Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -50,7 +49,7 @@ GetLbaAndOffsetByAddress ( Fvb = NULL; *Lba = (EFI_LBA) (-1); *Offset = 0; - + // // Get the proper FVB protocol. // diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VarCheck.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VarCheck.c index b2f5572327..ab0c1d6324 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VarCheck.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VarCheck.c @@ -2,12 +2,12 @@ Implementation functions and structures for var check protocol. Copyright (c) 2015, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ @@ -616,30 +616,49 @@ UEFI_DEFINED_VARIABLE_ENTRY mGlobalVariableList2[] = { }, }; -typedef struct { - EFI_GUID *Guid; - CHAR16 *Name; - VAR_CHECK_VARIABLE_PROPERTY VariableProperty; -} VARIABLE_DRIVER_VARIABLE_ENTRY; - -VARIABLE_DRIVER_VARIABLE_ENTRY mVariableDriverVariableList[] = { +// +// EFI_IMAGE_SECURITY_DATABASE_GUID +// +UEFI_DEFINED_VARIABLE_ENTRY mImageSecurityVariableList[] = { { - &gEdkiiVarErrorFlagGuid, - VAR_ERROR_FLAG_NAME, + EFI_IMAGE_SECURITY_DATABASE, { VAR_CHECK_VARIABLE_PROPERTY_REVISION, - VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY, - VARIABLE_ATTRIBUTE_NV_BS_RT, - sizeof (VAR_ERROR_FLAG), - sizeof (VAR_ERROR_FLAG), - } + 0, + VARIABLE_ATTRIBUTE_NV_BS_RT_AT, + 1, + MAX_UINTN + }, + NULL + }, + { + EFI_IMAGE_SECURITY_DATABASE1, + { + VAR_CHECK_VARIABLE_PROPERTY_REVISION, + 0, + VARIABLE_ATTRIBUTE_NV_BS_RT_AT, + 1, + MAX_UINTN + }, + NULL + }, + { + EFI_IMAGE_SECURITY_DATABASE2, + { + VAR_CHECK_VARIABLE_PROPERTY_REVISION, + 0, + VARIABLE_ATTRIBUTE_NV_BS_RT_AT, + 1, + MAX_UINTN + }, + NULL }, }; /** - Get UEFI defined global variable property. - The code will check if variable guid is global variable guid first. - If yes, further check if variable name is in mGlobalVariableList or mGlobalVariableList2. + Get UEFI defined global variable or image security database variable property. + The code will check if variable guid is global variable or image security database guid first. + If yes, further check if variable name is in mGlobalVariableList, mGlobalVariableList2 or mImageSecurityVariableList. @param[in] VariableName Pointer to variable name. @param[in] VendorGuid Variable Vendor Guid. @@ -647,8 +666,8 @@ VARIABLE_DRIVER_VARIABLE_ENTRY mVariableDriverVariableList[] = { @param[out] VariableProperty Pointer to variable property. @param[out] VarCheckFunction Pointer to check function. - @retval EFI_SUCCESS Variable is not global variable. - @retval EFI_INVALID_PARAMETER Variable is global variable, but variable name is not in the lists. + @retval EFI_SUCCESS Variable is not global variable or image security database variable. + @retval EFI_INVALID_PARAMETER Variable is global variable or image security database variable, but variable name is not in the lists. **/ EFI_STATUS @@ -711,36 +730,24 @@ GetUefiDefinedVariableProperty ( return EFI_INVALID_PARAMETER; } - // - // It is not global variable. - // - return EFI_SUCCESS; -} - -/** - Get variable property for variables managed by Varaible driver. - - @param[in] VariableName Pointer to variable name. - @param[in] VendorGuid Variable Vendor Guid. - - @return Pointer to variable property. - -**/ -VAR_CHECK_VARIABLE_PROPERTY * -GetVariableDriverVariableProperty ( - IN CHAR16 *VariableName, - IN EFI_GUID *VendorGuid - ) -{ - UINTN Index; - - for (Index = 0; Index < sizeof (mVariableDriverVariableList)/sizeof (mVariableDriverVariableList[0]); Index++) { - if ((CompareGuid (mVariableDriverVariableList[Index].Guid, VendorGuid)) && (StrCmp (mVariableDriverVariableList[Index].Name, VariableName) == 0)) { - return &mVariableDriverVariableList[Index].VariableProperty; + if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid)) { + for (Index = 0; Index < sizeof (mImageSecurityVariableList)/sizeof (mImageSecurityVariableList[0]); Index++) { + if (StrCmp (mImageSecurityVariableList[Index].Name, VariableName) == 0) { + if (VarCheckFunction != NULL) { + *VarCheckFunction = mImageSecurityVariableList[Index].CheckFunction; + } + *VariableProperty = &mImageSecurityVariableList[Index].VariableProperty; + return EFI_SUCCESS; + } } + + return EFI_INVALID_PARAMETER; } - return NULL; + // + // It is not global variable, image security database variable. + // + return EFI_SUCCESS; } /** @@ -799,13 +806,18 @@ InternalVarCheckSetVariableCheck ( break; } } - if (Property == NULL) { - Property = GetVariableDriverVariableProperty (VariableName, VendorGuid); - } if (Property == NULL) { Status = GetUefiDefinedVariableProperty (VariableName, VendorGuid, TRUE, &Property, &VarCheckFunction); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_INFO, "[Variable]: Var Check UEFI defined variable fail %r - %g:%s\n", Status, VendorGuid, VariableName)); + // + // To prevent name collisions with possible future globally defined variables, + // other internal firmware data variables that are not defined here must be + // saved with a unique VendorGuid other than EFI_GLOBAL_VARIABLE or + // any other GUID defined by the UEFI Specification. Implementations must + // only permit the creation of variables with a UEFI Specification-defined + // VendorGuid when these variables are documented in the UEFI Specification. + // + DEBUG ((EFI_D_INFO, "Variable Check UEFI defined variable fail %r - %s not in %g namespace\n", Status, VariableName, VendorGuid)); return Status; } } @@ -814,27 +826,29 @@ InternalVarCheckSetVariableCheck ( DEBUG ((EFI_D_INFO, "[Variable]: Var Check ReadOnly variable fail %r - %g:%s\n", EFI_WRITE_PROTECTED, VendorGuid, VariableName)); return EFI_WRITE_PROTECTED; } - if (!((DataSize == 0) || (Attributes == 0))) { + if (!((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0))) { // // Not to delete variable. // - if (Attributes != Property->Attributes) { - DEBUG ((EFI_D_INFO, "[Variable]: Var Check Attributes(0x%08x to 0x%08x) fail %r - %g:%s\n", Property->Attributes, Attributes, EFI_INVALID_PARAMETER, VendorGuid, VariableName)); + if ((Attributes != 0) && ((Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Property->Attributes)) { + DEBUG ((EFI_D_INFO, "Variable Check Attributes(0x%08x to 0x%08x) fail %r - %g:%s\n", Property->Attributes, Attributes, EFI_INVALID_PARAMETER, VendorGuid, VariableName)); return EFI_INVALID_PARAMETER; } - if ((DataSize < Property->MinSize) || (DataSize > Property->MaxSize)) { - DEBUG ((EFI_D_INFO, "[Variable]: Var Check DataSize fail(0x%x not in 0x%x - 0x%x) %r - %g:%s\n", DataSize, Property->MinSize, Property->MaxSize, EFI_INVALID_PARAMETER, VendorGuid, VariableName)); - return EFI_INVALID_PARAMETER; - } - if (VarCheckFunction != NULL) { - Status = VarCheckFunction ( - Property, - DataSize, - Data - ); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_INFO, "[Variable]: Internal Var Check function fail %r - %g:%s\n", Status, VendorGuid, VariableName)); - return Status; + if (DataSize != 0) { + if ((DataSize < Property->MinSize) || (DataSize > Property->MaxSize)) { + DEBUG ((EFI_D_INFO, "Variable Check DataSize fail(0x%x not in 0x%x - 0x%x) %r - %g:%s\n", DataSize, Property->MinSize, Property->MaxSize, EFI_INVALID_PARAMETER, VendorGuid, VariableName)); + return EFI_INVALID_PARAMETER; + } + if (VarCheckFunction != NULL) { + Status = VarCheckFunction ( + Property, + DataSize, + Data + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "Internal Variable Check function fail %r - %g:%s\n", Status, VendorGuid, VariableName)); + return Status; + } } } } @@ -849,7 +863,7 @@ InternalVarCheckSetVariableCheck ( Data ); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_INFO, "[Variable]: Var Check handler fail %r - %g:%s\n", Status, VendorGuid, VariableName)); + DEBUG ((EFI_D_INFO, "Variable Check handler fail %r - %g:%s\n", Status, VendorGuid, VariableName)); return Status; } } @@ -875,8 +889,8 @@ ReallocateHandlerTable ( // Reallocate memory for check handler table. // HandlerTable = ReallocateRuntimePool ( - mMaxNumberOfHandler * sizeof (VAR_CHECK_SET_VARIABLE_CHECK_HANDLER), - (mMaxNumberOfHandler + VAR_CHECK_HANDLER_TABLE_SIZE) * sizeof (VAR_CHECK_SET_VARIABLE_CHECK_HANDLER), + mMaxNumberOfHandler * sizeof (VAR_CHECK_SET_VARIABLE_CHECK_HANDLER), + (mMaxNumberOfHandler + VAR_CHECK_HANDLER_TABLE_SIZE) * sizeof (VAR_CHECK_SET_VARIABLE_CHECK_HANDLER), mHandlerTable ); @@ -927,6 +941,10 @@ VarCheckRegisterSetVariableCheckHandler ( DEBUG ((EFI_D_INFO, "RegisterSetVariableCheckHandler - 0x%x\n", Handler)); + Status = EFI_SUCCESS; + + AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + // // Check whether the handler list is enough to store new handler. // @@ -936,7 +954,7 @@ VarCheckRegisterSetVariableCheckHandler ( // Status = ReallocateHandlerTable(); if (EFI_ERROR (Status)) { - return Status; + goto Done; } } @@ -946,7 +964,10 @@ VarCheckRegisterSetVariableCheckHandler ( mHandlerTable[mNumberOfHandler] = Handler; mNumberOfHandler++; - return EFI_SUCCESS; +Done: + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + + return Status; } /** @@ -971,6 +992,8 @@ VariablePropertyGetFunction ( CHAR16 *VariableName; VAR_CHECK_VARIABLE_PROPERTY *Property; + Property = NULL; + for ( Link = GetFirstNode (&mVarCheckVariableList) ; !IsNull (&mVarCheckVariableList, Link) ; Link = GetNextNode (&mVarCheckVariableList, Link) @@ -982,14 +1005,57 @@ VariablePropertyGetFunction ( } } - Property = GetVariableDriverVariableProperty (Name, Guid); - if (Property == NULL) { - GetUefiDefinedVariableProperty (Name, Guid, WildcardMatch, &Property, NULL); - } + GetUefiDefinedVariableProperty (Name, Guid, WildcardMatch, &Property, NULL); return Property; } +/** + Internal variable property set. + + @param[in] Name Pointer to the variable name. + @param[in] Guid Pointer to the vendor GUID. + @param[in] VariableProperty Pointer to the input variable property. + + @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully. + @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request. + +**/ +EFI_STATUS +EFIAPI +InternalVarCheckVariablePropertySet ( + IN CHAR16 *Name, + IN EFI_GUID *Guid, + IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty + ) +{ + EFI_STATUS Status; + VAR_CHECK_VARIABLE_ENTRY *Entry; + CHAR16 *VariableName; + VAR_CHECK_VARIABLE_PROPERTY *Property; + + Status = EFI_SUCCESS; + + Property = VariablePropertyGetFunction (Name, Guid, FALSE); + if (Property != NULL) { + CopyMem (Property, VariableProperty, sizeof (*VariableProperty)); + } else { + Entry = AllocateRuntimeZeroPool (sizeof (*Entry) + StrSize (Name)); + if (Entry == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + VariableName = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry)); + StrnCpy (VariableName, Name, StrLen (Name)); + CopyGuid (&Entry->Guid, Guid); + CopyMem (&Entry->VariableProperty, VariableProperty, sizeof (*VariableProperty)); + InsertTailList (&mVarCheckVariableList, &Entry->Link); + } + +Done: + return Status; +} + /** Variable property set. @@ -1014,9 +1080,6 @@ VarCheckVariablePropertySet ( ) { EFI_STATUS Status; - VAR_CHECK_VARIABLE_ENTRY *Entry; - CHAR16 *VariableName; - VAR_CHECK_VARIABLE_PROPERTY *Property; if (Name == NULL || Name[0] == 0 || Guid == NULL) { return EFI_INVALID_PARAMETER; @@ -1034,27 +1097,10 @@ VarCheckVariablePropertySet ( return EFI_ACCESS_DENIED; } - Status = EFI_SUCCESS; - AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); - Property = VariablePropertyGetFunction (Name, Guid, FALSE); - if (Property != NULL) { - CopyMem (Property, VariableProperty, sizeof (*VariableProperty)); - } else { - Entry = AllocateRuntimeZeroPool (sizeof (*Entry) + StrSize (Name)); - if (Entry == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Done; - } - VariableName = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry)); - StrnCpy (VariableName, Name, StrLen (Name)); - CopyGuid (&Entry->Guid, Guid); - CopyMem (&Entry->VariableProperty, VariableProperty, sizeof (*VariableProperty)); - InsertTailList (&mVarCheckVariableList, &Entry->Link); - } + Status = InternalVarCheckVariablePropertySet (Name, Guid, VariableProperty); -Done: ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); return Status; diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c index a4104cc228..70be71e7c7 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c @@ -1,8 +1,7 @@ /** @file - - The common variable operation routines shared by DXE_RUNTIME variable + 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 @@ -14,14 +13,17 @@ 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) 2006 - 2015, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ @@ -60,14 +62,59 @@ BOOLEAN mEnableLocking = TRUE; // VAR_ERROR_FLAG mCurrentBootVarErrFlag = VAR_ERROR_FLAG_NO_ERROR; +VARIABLE_ENTRY_PROPERTY mVariableEntryProperty[] = { + { + &gEdkiiVarErrorFlagGuid, + VAR_ERROR_FLAG_NAME, + { + VAR_CHECK_VARIABLE_PROPERTY_REVISION, + VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY, + VARIABLE_ATTRIBUTE_NV_BS_RT, + sizeof (VAR_ERROR_FLAG), + sizeof (VAR_ERROR_FLAG) + } + }, +}; + +AUTH_VAR_LIB_CONTEXT_IN mContextIn = { + AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION, + sizeof (AUTH_VAR_LIB_CONTEXT_IN), + // + // MaxAuthVariableSize, TO BE FILLED + // + 0, + VariableExLibFindVariable, + VariableExLibFindNextVariable, + VariableExLibUpdateVariable, + VariableExLibGetScratchBuffer, + VariableExLibCheckRemainingSpaceForConsistency, + VariableExLibAtRuntime, +}; + +AUTH_VAR_LIB_CONTEXT_OUT mContextOut; + /** - Routine used to track statistical information about variable usage. + + SecureBoot Hook for auth variable update. + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. +**/ +VOID +EFIAPI +SecureBootHook ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid + ); + +/** + Routine used to track statistical information about variable usage. The data is stored in the EFI system table so it can be accessed later. - VariableInfo.efi can dump out the table. Only Boot Services variable + VariableInfo.efi can dump out the table. Only Boot Services variable accesses are tracked by this code. The PcdVariableCollectStatistics - build flag controls if this feature is enabled. + build flag controls if this feature is enabled. - A read that hits in the cache will have Read and Cache true for + A read that hits in the cache will have Read and Cache true for the transaction. Data is allocated by this routine, but never freed. @@ -115,7 +162,7 @@ UpdateVariableInfo ( gVariableInfo->Volatile = Volatile; } - + for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) { if (CompareGuid (VendorGuid, &Entry->VendorGuid)) { if (StrCmp (VariableName, Entry->Name) == 0) { @@ -236,7 +283,9 @@ UpdateVariableStore ( // Check if the Data is Volatile. // if (!Volatile) { - ASSERT (Fvb != NULL); + if (Fvb == NULL) { + return EFI_INVALID_PARAMETER; + } Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr); ASSERT_EFI_ERROR (Status); @@ -265,14 +314,14 @@ UpdateVariableStore ( if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) { return EFI_INVALID_PARAMETER; } - + // // If Volatile Variable just do a simple mem copy. - // + // CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize); return EFI_SUCCESS; } - + // // If we are here we are dealing with Non-Volatile Variables. // @@ -346,7 +395,8 @@ GetVariableStoreStatus ( IN VARIABLE_STORE_HEADER *VarStoreHeader ) { - if (CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid) && + if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) || + CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) && VarStoreHeader->Format == VARIABLE_STORE_FORMATTED && VarStoreHeader->State == VARIABLE_STORE_HEALTHY ) { @@ -367,6 +417,27 @@ GetVariableStoreStatus ( } } +/** + This code gets the size of variable header. + + @return Size of variable header in bytes in type UINTN. + +**/ +UINTN +GetVariableHeaderSize ( + VOID + ) +{ + UINTN Value; + + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { + Value = sizeof (AUTHENTICATED_VARIABLE_HEADER); + } else { + Value = sizeof (VARIABLE_HEADER); + } + + return Value; +} /** @@ -382,13 +453,49 @@ NameSizeOfVariable ( IN VARIABLE_HEADER *Variable ) { - if (Variable->State == (UINT8) (-1) || - Variable->DataSize == (UINT32) (-1) || - Variable->NameSize == (UINT32) (-1) || - Variable->Attributes == (UINT32) (-1)) { - return 0; + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { + 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 sets the size of name of variable. + + @param[in] Variable Pointer to the Variable Header. + @param[in] NameSize Name size to set. + +**/ +VOID +SetNameSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN UINTN NameSize + ) +{ + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { + AuthVariable->NameSize = (UINT32) NameSize; + } else { + Variable->NameSize = (UINT32) NameSize; } - return (UINTN) Variable->NameSize; } /** @@ -405,13 +512,49 @@ DataSizeOfVariable ( IN VARIABLE_HEADER *Variable ) { - if (Variable->State == (UINT8) (-1) || - Variable->DataSize == (UINT32) (-1) || - Variable->NameSize == (UINT32) (-1) || - Variable->Attributes == (UINT32) (-1)) { - return 0; + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { + 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 sets the size of variable data. + + @param[in] Variable Pointer to the Variable Header. + @param[in] DataSize Data size to set. + +**/ +VOID +SetDataSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN UINTN DataSize + ) +{ + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { + AuthVariable->DataSize = (UINT32) DataSize; + } else { + Variable->DataSize = (UINT32) DataSize; } - return (UINTN) Variable->DataSize; } /** @@ -428,8 +571,30 @@ GetVariableNamePtr ( IN VARIABLE_HEADER *Variable ) { + return (CHAR16 *) ((UINTN) Variable + GetVariableHeaderSize ()); +} - return (CHAR16 *) (Variable + 1); +/** + This code gets the pointer to the variable guid. + + @param Variable Pointer to the Variable Header. + + @return A EFI_GUID* pointer to Vendor Guid. + +**/ +EFI_GUID * +GetVendorGuidPtr ( + IN VARIABLE_HEADER *Variable + ) +{ + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { + return &AuthVariable->VendorGuid; + } else { + return &Variable->VendorGuid; + } } /** @@ -447,7 +612,7 @@ GetVariableDataPtr ( ) { UINTN Value; - + // // Be careful about pad size for alignment. // @@ -458,6 +623,30 @@ GetVariableDataPtr ( return (UINT8 *) Value; } +/** + This code gets the variable data offset related to variable header. + + @param Variable Pointer to the Variable Header. + + @return Variable Data offset. + +**/ +UINTN +GetVariableDataOffset ( + IN VARIABLE_HEADER *Variable + ) +{ + UINTN Value; + + // + // Be careful about pad size for alignment + // + Value = GetVariableHeaderSize (); + Value += NameSizeOfVariable (Variable); + Value += GET_PAD_SIZE (NameSizeOfVariable (Variable)); + + return Value; +} /** @@ -514,7 +703,7 @@ GetStartPointer ( @param VarStoreHeader Pointer to the Variable Store Header. - @return Pointer to the end of the variable storage area. + @return Pointer to the end of the variable storage area. **/ VARIABLE_HEADER * @@ -657,7 +846,10 @@ InitializeVarErrorFlag ( &Flag, sizeof (Flag), VARIABLE_ATTRIBUTE_NV_BS_RT, - &Variable + 0, + 0, + &Variable, + NULL ); } @@ -683,7 +875,7 @@ IsUserVariable ( // then no need to check if the variable is user variable or not specially. // if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) { - if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable), &Variable->VendorGuid, &Property) == EFI_NOT_FOUND) { + if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) { return TRUE; } } @@ -715,7 +907,7 @@ CalculateCommonUserVariableTotalSize ( NextVariable = GetNextVariablePtr (Variable); VariableSize = (UINTN) NextVariable - (UINTN) Variable; if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) { - if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable), &Variable->VendorGuid, &Property) == EFI_NOT_FOUND) { + if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) { // // No property, it is user variable. // @@ -752,27 +944,27 @@ InitializeVariableQuota ( Variable store garbage collection and reclaim operation. - @param VariableBase Base address of variable store. - @param LastVariableOffset Offset of last variable. - @param IsVolatile The variable store is volatile or not; - if it is non-volatile, need FTW. - @param UpdatingPtrTrack Pointer to updating variable pointer track structure. - @param NewVariable Pointer to new variable. - @param NewVariableSize New variable size. + @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_OUT_OF_RESOURCES - @return EFI_SUCCESS - @return Others + @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 + 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; @@ -863,7 +1055,7 @@ Reclaim ( // // 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); @@ -885,24 +1077,24 @@ Reclaim ( // // Reinstall all in delete transition variables. - // + // Variable = GetStartPointer (VariableStoreHeader); while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) { NextVariable = GetNextVariablePtr (Variable); if (Variable != UpdatingVariable && Variable != UpdatingInDeletedTransition && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { // - // Buffer has cached all ADDED variable. + // Buffer has cached all ADDED variable. // Per IN_DELETED variable, we have to guarantee that - // no ADDED one in previous buffer. - // - + // 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); NameSize = NameSizeOfVariable (AddedVariable); - if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) && + if (CompareGuid (GetVendorGuidPtr (AddedVariable), GetVendorGuidPtr (Variable)) && NameSize == NameSizeOfVariable (Variable) ) { Point0 = (VOID *) GetVariableNamePtr (AddedVariable); @@ -1033,14 +1225,14 @@ Done: /** Find the variable in the specified variable store. - @param VariableName Name of the variable to be found - @param VendorGuid Vendor GUID to be found. - @param IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute - check at runtime when searching variable. - @param PtrTrack Variable Track Pointer structure that contains Variable Information. + @param[in] VariableName Name of the variable to be found + @param[in] VendorGuid Vendor GUID to be found. + @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute + check at runtime when searching variable. + @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information. - @retval EFI_SUCCESS Variable found successfully - @retval EFI_NOT_FOUND Variable not found + @retval EFI_SUCCESS Variable found successfully + @retval EFI_NOT_FOUND Variable not found **/ EFI_STATUS FindVariableEx ( @@ -1064,7 +1256,7 @@ FindVariableEx ( ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr) ; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr) ) { - if (PtrTrack->CurrPtr->State == VAR_ADDED || + if (PtrTrack->CurrPtr->State == VAR_ADDED || PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED) ) { if (IgnoreRtCheck || !AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) { @@ -1076,7 +1268,7 @@ FindVariableEx ( return EFI_SUCCESS; } } else { - if (CompareGuid (VendorGuid, &PtrTrack->CurrPtr->VendorGuid)) { + if (CompareGuid (VendorGuid, GetVendorGuidPtr (PtrTrack->CurrPtr))) { Point = (VOID *) GetVariableNamePtr (PtrTrack->CurrPtr); ASSERT (NameSizeOfVariable (PtrTrack->CurrPtr) != 0); @@ -1109,14 +1301,14 @@ FindVariableEx ( at runtime when searching existing variable, only VariableName and VendorGuid are compared. Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime. - @param VariableName Name of the variable to be found. - @param VendorGuid Vendor GUID to be found. - @param PtrTrack VARIABLE_POINTER_TRACK structure for output, + @param[in] VariableName Name of the variable to be found. + @param[in] VendorGuid Vendor GUID to be found. + @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output, including the range searched and the target position. - @param Global Pointer to VARIABLE_GLOBAL structure, including + @param[in] Global Pointer to VARIABLE_GLOBAL structure, including base of volatile variable storage area, base of NV variable storage area, and a lock. - @param IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute + @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute check at runtime when searching variable. @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while @@ -1202,7 +1394,7 @@ GetIndexFromSupportedLangCodes( IN CHAR8 *SupportedLang, IN CHAR8 *Lang, IN BOOLEAN Iso639Language - ) + ) { UINTN Index; UINTN CompareLength; @@ -1237,8 +1429,8 @@ GetIndexFromSupportedLangCodes( // Determine the length of the next language code in SupportedLang // for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++); - - if ((CompareLength == LanguageLength) && + + if ((CompareLength == LanguageLength) && (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) { // // Successfully find the index of Lang string in SupportedLang string. @@ -1336,10 +1528,10 @@ GetLangFromSupportedLangCodes ( } /** - Returns a pointer to an allocated buffer that contains the best matching language - from a set of supported languages. - - This function supports both ISO 639-2 and RFC 4646 language codes, but language + Returns a pointer to an allocated buffer that contains the best matching language + from a set of supported languages. + + This function supports both ISO 639-2 and RFC 4646 language codes, but language code types may not be mixed in a single call to this function. This function supports a variable argument list that allows the caller to pass in a prioritized list of language codes to test against all the language codes in SupportedLanguages. @@ -1347,37 +1539,37 @@ GetLangFromSupportedLangCodes ( If SupportedLanguages is NULL, then ASSERT(). @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that - contains a set of language codes in the format + contains a set of language codes in the format specified by Iso639Language. @param[in] Iso639Language If TRUE, then all language codes are assumed to be in ISO 639-2 format. If FALSE, then all language codes are assumed to be in RFC 4646 language format - @param[in] ... A variable argument list that contains pointers to + @param[in] ... A variable argument list that contains pointers to Null-terminated ASCII strings that contain one or more language codes in the format specified by Iso639Language. The first language code from each of these language code lists is used to determine if it is an exact or - close match to any of the language codes in + close match to any of the language codes in SupportedLanguages. Close matches only apply to RFC 4646 language codes, and the matching algorithm from RFC 4647 - is used to determine if a close match is present. If + is used to determine if a close match is present. If an exact or close match is found, then the matching language code from SupportedLanguages is returned. If no matches are found, then the next variable argument - parameter is evaluated. The variable argument list + parameter is evaluated. The variable argument list is terminated by a NULL. @retval NULL The best matching language could not be found in SupportedLanguages. - @retval NULL There are not enough resources available to return the best matching + @retval NULL There are not enough resources available to return the best matching language. - @retval Other A pointer to a Null-terminated ASCII string that is the best matching + @retval Other A pointer to a Null-terminated ASCII string that is the best matching language in SupportedLanguages. **/ CHAR8 * EFIAPI VariableGetBestLanguage ( - IN CONST CHAR8 *SupportedLanguages, + IN CONST CHAR8 *SupportedLanguages, IN BOOLEAN Iso639Language, ... ) @@ -1389,7 +1581,9 @@ VariableGetBestLanguage ( CONST CHAR8 *Supported; CHAR8 *Buffer; - ASSERT (SupportedLanguages != NULL); + if (SupportedLanguages == NULL) { + return NULL; + } VA_START (Args, Iso639Language); while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) { @@ -1452,7 +1646,7 @@ VariableGetBestLanguage ( LanguageLength = 0; } else { // - // If RFC 4646 mode, then trim Language from the right to the next '-' character + // If RFC 4646 mode, then trim Language from the right to the next '-' character // for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--); } @@ -1461,7 +1655,7 @@ VariableGetBestLanguage ( VA_END (Args); // - // No matches were found + // No matches were found // return NULL; } @@ -1476,8 +1670,9 @@ VariableGetBestLanguage ( so follow the argument sequence to check the Variables. @param[in] Attributes Variable attributes for Variable entries. - @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *. - A NULL terminates the list. The VariableSize of + @param[in] Marker VA_LIST style variable argument list. + The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *. + A NULL terminates the list. The VariableSize of VARIABLE_ENTRY_CONSISTENCY is the variable data size as input. It will be changed to variable total size as output. @@ -1487,9 +1682,9 @@ VariableGetBestLanguage ( **/ BOOLEAN EFIAPI -CheckRemainingSpaceForConsistency ( +CheckRemainingSpaceForConsistencyInternal ( IN UINT32 Attributes, - ... + IN VA_LIST Marker ) { EFI_STATUS Status; @@ -1520,7 +1715,7 @@ CheckRemainingSpaceForConsistency ( ASSERT_EFI_ERROR (Status); TotalNeededSize = 0; - VA_START (Args, Attributes); + Args = Marker; VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *); while (VariableEntry != NULL) { // @@ -1530,12 +1725,11 @@ CheckRemainingSpaceForConsistency ( VarNameSize += GET_PAD_SIZE (VarNameSize); VarDataSize = VariableEntry->VariableSize; VarDataSize += GET_PAD_SIZE (VarDataSize); - VariableEntry->VariableSize = HEADER_ALIGN (sizeof (VARIABLE_HEADER) + VarNameSize + VarDataSize); + VariableEntry->VariableSize = HEADER_ALIGN (GetVariableHeaderSize () + VarNameSize + VarDataSize); TotalNeededSize += VariableEntry->VariableSize; VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *); } - VA_END (Args); if (RemainingVariableStorageSize >= TotalNeededSize) { // @@ -1550,7 +1744,7 @@ CheckRemainingSpaceForConsistency ( return FALSE; } - VA_START (Args, Attributes); + Args = Marker; VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *); while (VariableEntry != NULL) { // @@ -1580,7 +1774,6 @@ CheckRemainingSpaceForConsistency ( // // No enough space for Variable[Index]. // - VA_END (Args); return FALSE; } // @@ -1589,11 +1782,48 @@ CheckRemainingSpaceForConsistency ( RemainingVariableStorageSize -= VariableEntry->VariableSize; VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *); } - VA_END (Args); return TRUE; } +/** + This function is to check if the remaining variable space is enough to set + all Variables from argument list successfully. The purpose of the check + is to keep the consistency of the Variables to be in variable storage. + + Note: Variables are assumed to be in same storage. + The set sequence of Variables will be same with the sequence of VariableEntry from argument list, + so follow the argument sequence to check the Variables. + + @param[in] Attributes Variable attributes for Variable entries. + @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *. + A NULL terminates the list. The VariableSize of + VARIABLE_ENTRY_CONSISTENCY is the variable data size as input. + It will be changed to variable total size as output. + + @retval TRUE Have enough variable space to set the Variables successfully. + @retval FALSE No enough variable space to set the Variables successfully. + +**/ +BOOLEAN +EFIAPI +CheckRemainingSpaceForConsistency ( + IN UINT32 Attributes, + ... + ) +{ + VA_LIST Marker; + BOOLEAN Return; + + VA_START (Marker, Attributes); + + Return = CheckRemainingSpaceForConsistencyInternal (Attributes, Marker); + + VA_END (Marker); + + return Return; +} + /** Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang. @@ -1660,7 +1890,7 @@ AutoUpdateLangVariable ( ASSERT (mVariableModuleGlobal->PlatformLangCodes != NULL); // - // PlatformLang holds a single language from PlatformLangCodes, + // PlatformLang holds a single language from PlatformLangCodes, // so the size of PlatformLangCodes is enough for the PlatformLang. // if (mVariableModuleGlobal->PlatformLang != NULL) { @@ -1690,7 +1920,7 @@ AutoUpdateLangVariable ( ASSERT (mVariableModuleGlobal->LangCodes != NULL); } - if (SetLanguageCodes + if (SetLanguageCodes && (mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) { // @@ -1704,7 +1934,7 @@ AutoUpdateLangVariable ( // VariableName = EFI_PLATFORM_LANG_VARIABLE_NAME; Data = GetVariableDataPtr (Variable.CurrPtr); - DataSize = Variable.CurrPtr->DataSize; + DataSize = DataSizeOfVariable (Variable.CurrPtr); } else { Status = FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE); if (!EFI_ERROR (Status)) { @@ -1713,7 +1943,7 @@ AutoUpdateLangVariable ( // VariableName = EFI_LANG_VARIABLE_NAME; Data = GetVariableDataPtr (Variable.CurrPtr); - DataSize = Variable.CurrPtr->DataSize; + DataSize = DataSizeOfVariable (Variable.CurrPtr); } else { // // Neither PlatformLang nor Lang is set, directly return @@ -1756,7 +1986,7 @@ AutoUpdateLangVariable ( VariableEntry[0].VariableSize = ISO_639_2_ENTRY_SIZE + 1; VariableEntry[0].Guid = &gEfiGlobalVariableGuid; VariableEntry[0].Name = EFI_LANG_VARIABLE_NAME; - + VariableEntry[1].VariableSize = AsciiStrSize (BestPlatformLang); VariableEntry[1].Guid = &gEfiGlobalVariableGuid; VariableEntry[1].Name = EFI_PLATFORM_LANG_VARIABLE_NAME; @@ -1772,7 +2002,7 @@ AutoUpdateLangVariable ( FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE); Status = UpdateVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestLang, - ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable); + ISO_639_2_ENTRY_SIZE + 1, Attributes, 0, 0, &Variable, NULL); } DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang, BestLang, Status)); @@ -1820,8 +2050,8 @@ AutoUpdateLangVariable ( // FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE); - Status = UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestPlatformLang, - AsciiStrSize (BestPlatformLang), Attributes, &Variable); + Status = UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestPlatformLang, + AsciiStrSize (BestPlatformLang), Attributes, 0, 0, &Variable, NULL); } DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang, BestPlatformLang, Status)); @@ -1840,16 +2070,51 @@ AutoUpdateLangVariable ( } /** - Update the variable region with Variable information. These are the same - arguments as the EFI Variable services. + Compare two EFI_TIME data. + + + @param FirstTime A pointer to the first EFI_TIME data. + @param SecondTime A pointer to the second EFI_TIME data. + + @retval TRUE The FirstTime is not later than the SecondTime. + @retval FALSE The FirstTime is later than the SecondTime. + +**/ +BOOLEAN +VariableCompareTimeStampInternal ( + IN EFI_TIME *FirstTime, + IN EFI_TIME *SecondTime + ) +{ + if (FirstTime->Year != SecondTime->Year) { + return (BOOLEAN) (FirstTime->Year < SecondTime->Year); + } else if (FirstTime->Month != SecondTime->Month) { + return (BOOLEAN) (FirstTime->Month < SecondTime->Month); + } else if (FirstTime->Day != SecondTime->Day) { + return (BOOLEAN) (FirstTime->Day < SecondTime->Day); + } else if (FirstTime->Hour != SecondTime->Hour) { + return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour); + } else if (FirstTime->Minute != SecondTime->Minute) { + return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute); + } + + return (BOOLEAN) (FirstTime->Second <= SecondTime->Second); +} + +/** + 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 Attribues 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, 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. @@ -1861,12 +2126,16 @@ UpdateVariable ( IN VOID *Data, IN UINTN DataSize, IN UINT32 Attributes OPTIONAL, - IN OUT VARIABLE_POINTER_TRACK *CacheVariable + IN UINT32 KeyIndex OPTIONAL, + IN UINT64 MonotonicCount OPTIONAL, + IN OUT VARIABLE_POINTER_TRACK *CacheVariable, + IN EFI_TIME *TimeStamp OPTIONAL ) { EFI_STATUS Status; VARIABLE_HEADER *NextVariable; UINTN ScratchSize; + UINTN MaxDataSize; UINTN VarNameOffset; UINTN VarDataOffset; UINTN VarNameSize; @@ -1878,15 +2147,32 @@ UpdateVariable ( VARIABLE_POINTER_TRACK NvVariable; VARIABLE_STORE_HEADER *VariableStoreHeader; UINTN CacheOffset; + UINT8 *BufferForMerge; + UINTN MergedBufSize; + BOOLEAN DataReady; + UINTN DataOffset; BOOLEAN IsCommonVariable; BOOLEAN IsCommonUserVariable; + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; - if ((mVariableModuleGlobal->FvbInstance == NULL) && ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)) { + if (mVariableModuleGlobal->FvbInstance == NULL) { // - // The FVB protocol is not ready. Trying to update NV variable prior to the installation - // of EFI_VARIABLE_WRITE_ARCH_PROTOCOL. + // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed. // - return EFI_NOT_AVAILABLE_YET; + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { + // + // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL + // + DEBUG ((EFI_D_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 ((EFI_D_ERROR, "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET)); + return EFI_NOT_AVAILABLE_YET; + } } if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) { @@ -1898,7 +2184,7 @@ UpdateVariable ( // Now let Variable points to the same variable in Flash area. // VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase); - Variable = &NvVariable; + Variable = &NvVariable; Variable->StartPtr = GetStartPointer (VariableStoreHeader); Variable->EndPtr = GetEndPointer (VariableStoreHeader); Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr)); @@ -1908,18 +2194,27 @@ UpdateVariable ( Variable->InDeletedTransitionPtr = NULL; } Variable->Volatile = FALSE; - } + } Fvb = mVariableModuleGlobal->FvbInstance; + // + // Tricky part: Use scratch data area at the end of volatile variable store + // as a temporary storage. + // + 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 ()) { // - // If AtRuntime and the variable is Volatile and Runtime Access, - // the volatile is ReadOnly, and SetVariable should be aborted and + // 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) { @@ -1927,19 +2222,29 @@ UpdateVariable ( goto Done; } // - // Only variable that have NV|RT attributes can be updated/deleted in Runtime. + // Only variable that have NV attributes can be updated/deleted in Runtime. + // + if ((Variable->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 (((Variable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) { + if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) { Status = EFI_INVALID_PARAMETER; - goto Done; + 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 (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { + 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, @@ -1977,7 +2282,7 @@ UpdateVariable ( (UINTN) &Variable->CurrPtr->State, sizeof (UINT8), &State - ); + ); if (!EFI_ERROR (Status)) { UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE); if (!Variable->Volatile) { @@ -1985,21 +2290,72 @@ UpdateVariable ( FlushHobVariableToFlash (VariableName, VendorGuid); } } - goto Done; + goto Done; } // // If the variable is marked valid, and the same data has been passed in, // then return to the caller immediately. // if (DataSizeOfVariable (Variable->CurrPtr) == DataSize && - (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0)) { - + (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), 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); Status = EFI_SUCCESS; goto Done; } else if ((Variable->CurrPtr->State == VAR_ADDED) || (Variable->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 (Variable->CurrPtr); + BufferForMerge = (UINT8 *) ((UINTN) NextVariable + DataOffset); + CopyMem (BufferForMerge, (UINT8 *) ((UINTN) Variable->CurrPtr + DataOffset), DataSizeOfVariable (Variable->CurrPtr)); + + // + // Set Max Common/Auth Variable Data Size as default MaxDataSize. + // + if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) { + MaxDataSize = mVariableModuleGlobal->MaxAuthVariableSize - DataOffset; + } else { + MaxDataSize = mVariableModuleGlobal->MaxVariableSize - 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 (Variable->CurrPtr) + DataSize > MaxDataSize) { + // + // Existing data size + new data size exceed maximum variable size limitation. + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } + CopyMem ((UINT8*) ((UINTN) BufferForMerge + DataSizeOfVariable (Variable->CurrPtr)), Data, DataSize); + MergedBufSize = DataSizeOfVariable (Variable->CurrPtr) + 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. // @@ -2014,28 +2370,33 @@ UpdateVariable ( (UINTN) &Variable->CurrPtr->State, sizeof (UINT8), &State - ); + ); if (EFI_ERROR (Status)) { - goto Done; - } + goto Done; + } if (!Variable->Volatile) { CacheVariable->CurrPtr->State = State; } - } + } } else { // // Not found existing variable. Create a new variable. - // - + // + + 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. + // 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. // @@ -2043,29 +2404,50 @@ UpdateVariable ( (((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. - - // - // Tricky part: Use scratch data area at the end of volatile variable store - // as a temporary storage. // - NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)); - ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)); - - SetMem (NextVariable, ScratchSize, 0xff); - NextVariable->StartId = VARIABLE_DATA; - NextVariable->Attributes = Attributes; // // NextVariable->State = VAR_ADDED; // NextVariable->Reserved = 0; - VarNameOffset = sizeof (VARIABLE_HEADER); + 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 *) Variable->CurrPtr)->TimeStamp), TimeStamp)) { + CopyMem (&AuthVariable->TimeStamp, 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 (); VarNameSize = StrSize (VariableName); CopyMem ( (UINT8 *) ((UINTN) NextVariable + VarNameOffset), @@ -2073,19 +2455,27 @@ UpdateVariable ( VarNameSize ); VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize); - CopyMem ( - (UINT8 *) ((UINTN) NextVariable + VarDataOffset), - Data, - DataSize - ); - CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID)); + + // + // 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), 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. // - NextVariable->NameSize = (UINT32)VarNameSize; - NextVariable->DataSize = (UINT32)DataSize; + SetNameSizeOfVariable (NextVariable, VarNameSize); + SetDataSizeOfVariable (NextVariable, DataSize); // // The actual size of the variable that stores in storage should @@ -2122,8 +2512,14 @@ UpdateVariable ( // // 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)); + 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. @@ -2147,7 +2543,7 @@ UpdateVariable ( // // Four steps // 1. Write variable header - // 2. Set variable state to header valid + // 2. Set variable state to header valid // 3. Write variable data // 4. Set variable state to valid // @@ -2161,7 +2557,7 @@ UpdateVariable ( TRUE, Fvb, mVariableModuleGlobal->NonVolatileLastVariableOffset, - sizeof (VARIABLE_HEADER), + (UINT32) GetVariableHeaderSize (), (UINT8 *) NextVariable ); @@ -2194,9 +2590,9 @@ UpdateVariable ( FALSE, TRUE, Fvb, - mVariableModuleGlobal->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER), - (UINT32) VarSize - sizeof (VARIABLE_HEADER), - (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER) + mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (), + (UINT32) (VarSize - GetVariableHeaderSize ()), + (UINT8 *) NextVariable + GetVariableHeaderSize () ); if (EFI_ERROR (Status)) { @@ -2237,7 +2633,7 @@ UpdateVariable ( } else { // // Create a volatile variable. - // + // Volatile = TRUE; if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) > @@ -2245,8 +2641,14 @@ UpdateVariable ( // // Perform garbage collection & reclaim operation, and integrate the new variable at the same time. // - Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, - &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable, NextVariable, HEADER_ALIGN (VarSize)); + Status = Reclaim ( + mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, + &mVariableModuleGlobal->VolatileLastVariableOffset, + TRUE, + Variable, + NextVariable, + HEADER_ALIGN (VarSize) + ); if (!EFI_ERROR (Status)) { // // The new variable has been integrated successfully during reclaiming. @@ -2320,7 +2722,7 @@ UpdateVariable ( sizeof (UINT8), &State ); - if (!EFI_ERROR (Status) && !Variable->Volatile) { + if (!EFI_ERROR (Status) && !Variable->Volatile) { CacheVariable->CurrPtr->State = State; } } @@ -2339,8 +2741,8 @@ Done: /** Check if a Unicode character is a hexadecimal character. - This function checks if a Unicode character is a - hexadecimal character. The valid hexadecimal character is + This function checks if a Unicode character is a + hexadecimal character. The valid hexadecimal character is L'0' to L'9', L'a' to L'f', or L'A' to L'F'. @@ -2396,6 +2798,7 @@ IsHwErrRecVariable ( /** Mark a variable that will become read-only after leaving the DXE phase of execution. + @param[in] This The VARIABLE_LOCK_PROTOCOL instance. @param[in] VariableName A pointer to the variable name that will be made read-only subsequently. @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently. @@ -2474,7 +2877,7 @@ Done: @param DataSize Size of Data found. If size is less than the data, this value contains the required size. @param Data Data pointer. - + @return EFI_INVALID_PARAMETER Invalid parameter. @return EFI_SUCCESS Find the specified variable. @return EFI_NOT_FOUND Not found. @@ -2500,7 +2903,7 @@ VariableServiceGetVariable ( } AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); - + Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE); if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { goto Done; @@ -2525,7 +2928,7 @@ VariableServiceGetVariable ( *DataSize = VarDataSize; UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE); - + Status = EFI_SUCCESS; goto Done; } else { @@ -2539,47 +2942,35 @@ Done: return Status; } - - /** - This code Finds the Next available variable. Caution: This function may receive untrusted input. This function may be invoked in SMM mode. This function will do basic validation, before parse the data. - @param VariableNameSize Size of the variable name. - @param VariableName Pointer to variable name. - @param VendorGuid Variable Vendor Guid. + @param[in] VariableName Pointer to variable name. + @param[in] VendorGuid Variable Vendor Guid. + @param[out] VariablePtr Pointer to variable header address. - @return EFI_INVALID_PARAMETER Invalid parameter. - @return EFI_SUCCESS Find the specified variable. - @return EFI_NOT_FOUND Not found. - @return EFI_BUFFER_TO_SMALL DataSize is too small for the result. + @return EFI_SUCCESS Find the specified variable. + @return EFI_NOT_FOUND Not found. **/ EFI_STATUS EFIAPI -VariableServiceGetNextVariableName ( - IN OUT UINTN *VariableNameSize, - IN OUT CHAR16 *VariableName, - IN OUT EFI_GUID *VendorGuid +VariableServiceGetNextVariableInternal ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VARIABLE_HEADER **VariablePtr ) { VARIABLE_STORE_TYPE Type; VARIABLE_POINTER_TRACK Variable; VARIABLE_POINTER_TRACK VariableInHob; VARIABLE_POINTER_TRACK VariablePtrTrack; - UINTN VarNameSize; EFI_STATUS Status; VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax]; - if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) { - return EFI_INVALID_PARAMETER; - } - - AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); - Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE); if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { goto Done; @@ -2624,7 +3015,7 @@ VariableServiceGetNextVariableName ( } } // - // Capture the case that + // Capture the case that // 1. current storage is the last one, or // 2. no further storage // @@ -2652,7 +3043,7 @@ VariableServiceGetNextVariableName ( VariablePtrTrack.EndPtr = Variable.EndPtr; Status = FindVariableEx ( GetVariableNamePtr (Variable.CurrPtr), - &Variable.CurrPtr->VendorGuid, + GetVendorGuidPtr (Variable.CurrPtr), FALSE, &VariablePtrTrack ); @@ -2665,14 +3056,14 @@ VariableServiceGetNextVariableName ( // // Don't return NV variable when HOB overrides it // - if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) && + if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv])) ) { VariableInHob.StartPtr = GetStartPointer (VariableStoreHeader[VariableStoreTypeHob]); VariableInHob.EndPtr = GetEndPointer (VariableStoreHeader[VariableStoreTypeHob]); Status = FindVariableEx ( GetVariableNamePtr (Variable.CurrPtr), - &Variable.CurrPtr->VendorGuid, + GetVendorGuidPtr (Variable.CurrPtr), FALSE, &VariableInHob ); @@ -2682,18 +3073,8 @@ VariableServiceGetNextVariableName ( } } - VarNameSize = NameSizeOfVariable (Variable.CurrPtr); - ASSERT (VarNameSize != 0); - - if (VarNameSize <= *VariableNameSize) { - CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize); - CopyMem (VendorGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID)); - Status = EFI_SUCCESS; - } else { - Status = EFI_BUFFER_TOO_SMALL; - } - - *VariableNameSize = VarNameSize; + *VariablePtr = Variable.CurrPtr; + Status = EFI_SUCCESS; goto Done; } } @@ -2702,6 +3083,59 @@ VariableServiceGetNextVariableName ( } Done: + return Status; +} + +/** + + This code Finds the Next available variable. + + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode. This function will do basic validation, before parse the data. + + @param VariableNameSize Size of the variable name. + @param VariableName Pointer to variable name. + @param VendorGuid Variable Vendor Guid. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_SUCCESS Find the specified variable. + @return EFI_NOT_FOUND Not found. + @return EFI_BUFFER_TO_SMALL DataSize is too small for the result. + +**/ +EFI_STATUS +EFIAPI +VariableServiceGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +{ + EFI_STATUS Status; + UINTN VarNameSize; + VARIABLE_HEADER *VariablePtr; + + if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + + Status = VariableServiceGetNextVariableInternal (VariableName, VendorGuid, &VariablePtr); + if (!EFI_ERROR (Status)) { + VarNameSize = NameSizeOfVariable (VariablePtr); + ASSERT (VarNameSize != 0); + if (VarNameSize <= *VariableNameSize) { + CopyMem (VariableName, GetVariableNamePtr (VariablePtr), VarNameSize); + CopyMem (VendorGuid, GetVendorGuidPtr (VariablePtr), sizeof (EFI_GUID)); + Status = EFI_SUCCESS; + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + + *VariableNameSize = VarNameSize; + } + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); return Status; } @@ -2713,6 +3147,9 @@ Done: Caution: This function may receive untrusted input. This function may be invoked in SMM mode, and datasize and data are external input. This function will do basic validation, before parse the data. + This function will parse the authentication carefully to avoid security issues, like + buffer overflow, integer overflow. + This function will check attribute carefully to avoid authentication bypass. @param VariableName Name of Variable to be found. @param VendorGuid Variable vendor GUID. @@ -2742,6 +3179,7 @@ VariableServiceSetVariable ( EFI_STATUS Status; VARIABLE_HEADER *NextVariable; EFI_PHYSICAL_ADDRESS Point; + UINTN PayloadSize; LIST_ENTRY *Link; VARIABLE_ENTRY *Entry; CHAR16 *Name; @@ -2751,16 +3189,16 @@ VariableServiceSetVariable ( // if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) { return EFI_INVALID_PARAMETER; - } + } if (DataSize != 0 && Data == NULL) { return EFI_INVALID_PARAMETER; } // - // Not support authenticated or append variable write yet. + // Check for reserverd bit in variable attribute. // - if ((Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_APPEND_WRITE)) != 0) { + if ((Attributes & (~EFI_VARIABLE_ATTRIBUTES_MASK)) != 0) { return EFI_INVALID_PARAMETER; } @@ -2769,22 +3207,67 @@ VariableServiceSetVariable ( // if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) { return EFI_INVALID_PARAMETER; + } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) { + if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) { + // + // Not support authenticated variable write. + // + return EFI_INVALID_PARAMETER; + } + } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) { + if (PcdGet32 (PcdHwErrStorageSize) == 0) { + // + // Not support harware error record variable variable. + // + return EFI_INVALID_PARAMETER; + } + } + + // + // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute + // cannot be set both. + // + if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) + && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) { + return EFI_INVALID_PARAMETER; } - if ((UINTN)(~0) - DataSize < StrSize(VariableName)){ + if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) { + if (DataSize < AUTHINFO_SIZE) { + // + // Try to write Authenticated Variable without AuthInfo. + // + return EFI_SECURITY_VIOLATION; + } + PayloadSize = DataSize - AUTHINFO_SIZE; + } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { + // + // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor. + // + if (DataSize < OFFSET_OF_AUTHINFO2_CERT_DATA || + ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength > DataSize - (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo)) || + ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength < OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) { + return EFI_SECURITY_VIOLATION; + } + PayloadSize = DataSize - AUTHINFO2_SIZE (Data); + } else { + PayloadSize = DataSize; + } + + if ((UINTN)(~0) - PayloadSize < StrSize(VariableName)){ + // + // Prevent whole variable size overflow // - // Prevent whole variable size overflow - // return EFI_INVALID_PARAMETER; } // // The size of the VariableName, including the Unicode Null in bytes plus // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize) - // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others. + // bytes for HwErrRec#### variable. // if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { - if ( StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER)) { + if (StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize ()) { return EFI_INVALID_PARAMETER; } if (!IsHwErrRecVariable(VariableName, VendorGuid)) { @@ -2793,13 +3276,24 @@ VariableServiceSetVariable ( } else { // // The size of the VariableName, including the Unicode Null in bytes plus - // the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes. + // the DataSize is limited to maximum size of Max(Auth)VariableSize bytes. // - if (StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER)) { - return EFI_INVALID_PARAMETER; + if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) { + if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ()) { + return EFI_INVALID_PARAMETER; + } + } else { + if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize ()) { + return EFI_INVALID_PARAMETER; + } } } + Status = InternalVarCheckSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize)); + if (EFI_ERROR (Status)) { + return Status; + } + AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); // @@ -2835,11 +3329,6 @@ VariableServiceSetVariable ( } } - Status = InternalVarCheckSetVariableCheck (VariableName, VendorGuid, Attributes, DataSize, Data); - if (EFI_ERROR (Status)) { - goto Done; - } - // // Check whether the input variable is already existed. // @@ -2849,7 +3338,7 @@ VariableServiceSetVariable ( Status = EFI_WRITE_PROTECTED; goto Done; } - if (Attributes != 0 && Attributes != Variable.CurrPtr->Attributes) { + if (Attributes != 0 && (Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Variable.CurrPtr->Attributes) { // // If a preexisting variable is rewritten with different attributes, SetVariable() shall not // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule: @@ -2875,12 +3364,25 @@ VariableServiceSetVariable ( } } - Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable); + if (mVariableModuleGlobal->VariableGlobal.AuthSupport) { + Status = AuthVariableLibProcessVariable (VariableName, VendorGuid, Data, DataSize, Attributes); + } else { + Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, &Variable, NULL); + } Done: InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState); ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + if (!AtRuntime ()) { + if (!EFI_ERROR (Status)) { + SecureBootHook ( + VariableName, + VendorGuid + ); + } + } + return Status; } @@ -2947,7 +3449,7 @@ VariableServiceQueryVariableInfoInternal ( // if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize); - *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER); + *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize (); } else { if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { if (AtRuntime ()) { @@ -2958,9 +3460,13 @@ VariableServiceQueryVariableInfoInternal ( } // - // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size. + // Let *MaximumVariableSize be Max(Auth)VariableSize with the exception of the variable header size. // - *MaximumVariableSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER); + if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) { + *MaximumVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize (); + } else { + *MaximumVariableSize = mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize (); + } } // @@ -3008,7 +3514,7 @@ VariableServiceQueryVariableInfoInternal ( VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader); Status = FindVariableEx ( GetVariableNamePtr (Variable), - &Variable->VendorGuid, + GetVendorGuidPtr (Variable), FALSE, &VariablePtrTrack ); @@ -3038,10 +3544,10 @@ VariableServiceQueryVariableInfoInternal ( } } - if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) { + if (*RemainingVariableStorageSize < GetVariableHeaderSize ()) { *MaximumVariableSize = 0; - } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) { - *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER); + } else if ((*RemainingVariableStorageSize - GetVariableHeaderSize ()) < *MaximumVariableSize) { + *MaximumVariableSize = *RemainingVariableStorageSize - GetVariableHeaderSize (); } return EFI_SUCCESS; @@ -3083,7 +3589,7 @@ VariableServiceQueryVariableInfo ( return EFI_INVALID_PARAMETER; } - if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) { + if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == 0) { // // Make sure the Attributes combination is supported by the platform. // @@ -3103,11 +3609,20 @@ VariableServiceQueryVariableInfo ( // Make sure Hw Attribute is set with NV. // return EFI_INVALID_PARAMETER; - } else if ((Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_APPEND_WRITE)) != 0) { - // - // Not support authenticated or append variable write yet. - // - return EFI_UNSUPPORTED; + } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) { + if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) { + // + // Not support authenticated variable write. + // + return EFI_UNSUPPORTED; + } + } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) { + if (PcdGet32 (PcdHwErrStorageSize) == 0) { + // + // Not support harware error record variable variable. + // + return EFI_UNSUPPORTED; + } } AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); @@ -3157,11 +3672,13 @@ ReclaimForOS( } RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize; + // // Check if the free area is below a threshold. // - if ((RemainingCommonRuntimeVariableSpace < PcdGet32 (PcdMaxVariableSize)) - || ((PcdGet32 (PcdHwErrStorageSize) != 0) && + if (((RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxVariableSize) || + (RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxAuthVariableSize)) || + ((PcdGet32 (PcdHwErrStorageSize) != 0) && (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){ Status = Reclaim ( mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, @@ -3175,9 +3692,30 @@ ReclaimForOS( } } +/** + Get non-volatile maximum variable size. + + @return Non-volatile maximum variable size. + +**/ +UINTN +GetNonVolatileMaxVariableSize ( + VOID + ) +{ + if (PcdGet32 (PcdHwErrStorageSize) != 0) { + return MAX (MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)), + PcdGet32 (PcdMaxHardwareErrorVariableSize)); + } else { + return MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)); + } +} + /** Init non-volatile variable store. + @param[out] NvFvHeader Output pointer to non-volatile FV header address. + @retval EFI_SUCCESS Function successfully executed. @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted. @@ -3185,7 +3723,7 @@ ReclaimForOS( **/ EFI_STATUS InitNonVolatileVariableStore ( - VOID + OUT EFI_FIRMWARE_VOLUME_HEADER **NvFvHeader ) { EFI_FIRMWARE_VOLUME_HEADER *FvHeader; @@ -3241,7 +3779,7 @@ InitNonVolatileVariableStore ( } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) { // - // Flash NV storage from the offset is backed up in spare block. + // Flash NV storage from the Offset is backed up in spare block. // BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase); BackUpSize = NvStorageSize - BackUpOffset; @@ -3276,9 +3814,10 @@ InitNonVolatileVariableStore ( } ASSERT(mNvVariableCache->Size == VariableStoreLength); - ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength); + mVariableModuleGlobal->VariableGlobal.AuthFormat = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid)); + HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize); MaxUserNvVariableSpaceSize = PcdGet32 (PcdMaxUserNvVariableSpaceSize); BoottimeReservedNvVariableSpaceSize = PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize); @@ -3287,17 +3826,17 @@ InitNonVolatileVariableStore ( // Note that in EdkII variable driver implementation, Hardware Error Record type variable // is stored with common variable in the same NV region. So the platform integrator should // ensure that the value of PcdHwErrStorageSize is less than the value of - // VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)). + // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)). // ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER))); // // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of - // VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize). + // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize). // ASSERT (MaxUserNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize)); // // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of - // VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize). + // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize). // ASSERT (BoottimeReservedNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize)); @@ -3308,9 +3847,12 @@ InitNonVolatileVariableStore ( DEBUG ((EFI_D_INFO, "Variable driver common space: 0x%x 0x%x 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonRuntimeVariableSpace)); // - // The max variable or hardware error variable size should be < variable store size. + // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)). // - ASSERT(MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) < VariableStoreLength); + ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER))); + + mVariableModuleGlobal->MaxVariableSize = PcdGet32 (PcdMaxVariableSize); + mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize); // // Parse non-volatile variable data and get last variable offset. @@ -3329,6 +3871,7 @@ InitNonVolatileVariableStore ( } mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) VariableStoreBase; + *NvFvHeader = FvHeader; return EFI_SUCCESS; } @@ -3374,17 +3917,17 @@ FlushHobVariableToFlash ( } ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0); if (VendorGuid == NULL || VariableName == NULL || - !CompareGuid (VendorGuid, &Variable->VendorGuid) || + !CompareGuid (VendorGuid, GetVendorGuidPtr (Variable)) || StrCmp (VariableName, GetVariableNamePtr (Variable)) != 0) { VariableData = GetVariableDataPtr (Variable); Status = VariableServiceSetVariable ( GetVariableNamePtr (Variable), - &Variable->VendorGuid, + GetVendorGuidPtr (Variable), Variable->Attributes, - Variable->DataSize, + DataSizeOfVariable (Variable), VariableData ); - DEBUG ((EFI_D_INFO, "Variable driver flush the HOB variable to flash: %g %s %r\n", &Variable->VendorGuid, GetVariableNamePtr (Variable), Status)); + DEBUG ((EFI_D_INFO, "Variable driver flush the HOB variable to flash: %g %s %r\n", GetVendorGuidPtr (Variable), GetVariableNamePtr (Variable), Status)); } else { // // The updated or deleted variable is matched with the HOB variable. @@ -3398,7 +3941,7 @@ FlushHobVariableToFlash ( // If set variable successful, or the updated or deleted variable is matched with the HOB variable, // set the HOB variable to DELETED state in local. // - DEBUG ((EFI_D_INFO, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", &Variable->VendorGuid, GetVariableNamePtr (Variable))); + DEBUG ((EFI_D_INFO, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", GetVendorGuidPtr (Variable), GetVariableNamePtr (Variable))); Variable->State &= VAR_DELETED; } else { ErrorFlag = TRUE; @@ -3440,6 +3983,7 @@ VariableWriteServiceInitialize ( UINT8 Data; EFI_PHYSICAL_ADDRESS VariableStoreBase; EFI_PHYSICAL_ADDRESS NvStorageBase; + VARIABLE_ENTRY_PROPERTY *VariableEntry; NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64); if (NvStorageBase == 0) { @@ -3452,7 +3996,7 @@ VariableWriteServiceInitialize ( // mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase; VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase; - + // // Check if the free area is really free. // @@ -3479,7 +4023,45 @@ VariableWriteServiceInitialize ( FlushHobVariableToFlash (NULL, NULL); - return EFI_SUCCESS; + Status = EFI_SUCCESS; + ZeroMem (&mContextOut, sizeof (mContextOut)); + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { + // + // Authenticated variable initialize. + // + mContextIn.MaxAuthVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize (); + Status = AuthVariableLibInitialize (&mContextIn, &mContextOut); + if (!EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "Variable driver will work with auth variable support!\n")); + mVariableModuleGlobal->VariableGlobal.AuthSupport = TRUE; + if (mContextOut.AuthVarEntry != NULL) { + for (Index = 0; Index < mContextOut.AuthVarEntryCount; Index++) { + VariableEntry = &mContextOut.AuthVarEntry[Index]; + Status = InternalVarCheckVariablePropertySet ( + VariableEntry->Name, + VariableEntry->Guid, + &VariableEntry->VariableProperty + ); + ASSERT_EFI_ERROR (Status); + } + } + } else if (Status == EFI_UNSUPPORTED) { + DEBUG ((EFI_D_INFO, "NOTICE - AuthVariableLibInitialize() returns %r!\n", Status)); + DEBUG ((EFI_D_INFO, "Variable driver will continue to work without auth variable support!\n")); + mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE; + Status = EFI_SUCCESS; + } + } + + if (!EFI_ERROR (Status)) { + for (Index = 0; Index < sizeof (mVariableEntryProperty) / sizeof (mVariableEntryProperty[0]); Index++) { + VariableEntry = &mVariableEntryProperty[Index]; + Status = InternalVarCheckVariablePropertySet (VariableEntry->Name, VariableEntry->Guid, &VariableEntry->VariableProperty); + ASSERT_EFI_ERROR (Status); + } + } + + return Status; } @@ -3501,6 +4083,8 @@ VariableCommonInitialize ( UINT64 VariableStoreLength; UINTN ScratchSize; EFI_HOB_GUID_TYPE *GuidHob; + EFI_GUID *VariableGuid; + EFI_FIRMWARE_VOLUME_HEADER *NvFvHeader; // // Allocate runtime memory for variable driver global structure. @@ -3512,16 +4096,43 @@ VariableCommonInitialize ( InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY); + // + // Init non-volatile variable store. + // + Status = InitNonVolatileVariableStore (&NvFvHeader); + if (EFI_ERROR (Status)) { + FreePool (mVariableModuleGlobal); + return Status; + } + + // + // mVariableModuleGlobal->VariableGlobal.AuthFormat + // has been initialized in InitNonVolatileVariableStore(). + // + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { + DEBUG ((EFI_D_INFO, "Variable driver will work with auth variable format!\n")); + // + // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() will initialize it. + // + mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE; + VariableGuid = &gEfiAuthenticatedVariableGuid; + } else { + DEBUG ((EFI_D_INFO, "Variable driver will work without auth variable support!\n")); + mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE; + VariableGuid = &gEfiVariableGuid; + } + // // Get HOB variable store. // - GuidHob = GetFirstGuidHob (&gEfiVariableGuid); + GuidHob = GetFirstGuidHob (VariableGuid); if (GuidHob != NULL) { VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob); VariableStoreLength = (UINT64) (GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE)); if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) { mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader); if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) { + FreePool (NvFvHeader); FreePool (mVariableModuleGlobal); return EFI_OUT_OF_RESOURCES; } @@ -3533,12 +4144,14 @@ VariableCommonInitialize ( // // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data. // - ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)); + ScratchSize = GetNonVolatileMaxVariableSize (); + mVariableModuleGlobal->ScratchBufferSize = ScratchSize; VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize); if (VolatileVariableStore == NULL) { if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) { FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase); } + FreePool (NvFvHeader); FreePool (mVariableModuleGlobal); return EFI_OUT_OF_RESOURCES; } @@ -3551,33 +4164,21 @@ VariableCommonInitialize ( mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore; mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore; - CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid); + CopyGuid (&VolatileVariableStore->Signature, VariableGuid); VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize); VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED; VolatileVariableStore->State = VARIABLE_STORE_HEALTHY; VolatileVariableStore->Reserved = 0; VolatileVariableStore->Reserved1 = 0; - // - // Init non-volatile variable store. - // - Status = InitNonVolatileVariableStore (); - if (EFI_ERROR (Status)) { - if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) { - FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase); - } - FreePool (mVariableModuleGlobal); - FreePool (VolatileVariableStore); - } - - return Status; + return EFI_SUCCESS; } /** Get the proper fvb handle and/or fvb protocol by the given Flash address. - @param[in] Address The Flash address. + @param[in] Address The Flash address. @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle. @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol. @@ -3600,7 +4201,6 @@ GetFvbInfoByAddress ( UINTN NumberOfBlocks; HandleBuffer = NULL; - // // Get all FVB handles. // @@ -3660,7 +4260,7 @@ GetFvbInfoByAddress ( if (Fvb == NULL) { Status = EFI_NOT_FOUND; } - - return Status; + + return Status; } diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h index f5ba486573..9928837fd8 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h @@ -1,5 +1,4 @@ /** @file - The internal header file includes the common header files, defines internal structure and functions used by Variable modules. @@ -36,14 +35,24 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include #include #include #include +#include #include #include #include #include +#define EFI_VARIABLE_ATTRIBUTES_MASK (EFI_VARIABLE_NON_VOLATILE | \ + EFI_VARIABLE_BOOTSERVICE_ACCESS | \ + EFI_VARIABLE_RUNTIME_ACCESS | \ + EFI_VARIABLE_HARDWARE_ERROR_RECORD | \ + EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | \ + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \ + EFI_VARIABLE_APPEND_WRITE) + /// /// The size of a 3 character ISO639 language code. /// @@ -76,6 +85,8 @@ typedef struct { EFI_PHYSICAL_ADDRESS NonVolatileVariableBase; EFI_LOCK VariableServicesLock; UINT32 ReentrantState; + BOOLEAN AuthFormat; + BOOLEAN AuthSupport; } VARIABLE_GLOBAL; typedef struct { @@ -88,6 +99,9 @@ typedef struct { UINTN CommonVariableTotalSize; UINTN CommonUserVariableTotalSize; UINTN HwErrVariableTotalSize; + UINTN MaxVariableSize; + UINTN MaxAuthVariableSize; + UINTN ScratchBufferSize; CHAR8 *PlatformLangCodes; CHAR8 *LangCodes; CHAR8 *PlatformLang; @@ -135,25 +149,167 @@ FtwVariableSpace ( IN VARIABLE_STORE_HEADER *VariableBuffer ); +/** + Finds variable in storage blocks of volatile and non-volatile storage areas. + + This code finds variable in storage blocks of volatile and non-volatile storage areas. + If VariableName is an empty string, then we just return the first + qualified variable without comparing VariableName and VendorGuid. + If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check + at runtime when searching existing variable, only VariableName and VendorGuid are compared. + Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime. + + @param[in] VariableName Name of the variable to be found. + @param[in] VendorGuid Vendor GUID to be found. + @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output, + including the range searched and the target position. + @param[in] Global Pointer to VARIABLE_GLOBAL structure, including + base of volatile variable storage area, base of + NV variable storage area, and a lock. + @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute + check at runtime when searching variable. + + @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while + VendorGuid is NULL. + @retval EFI_SUCCESS Variable successfully found. + @retval EFI_NOT_FOUND Variable not found + +**/ +EFI_STATUS +FindVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack, + IN VARIABLE_GLOBAL *Global, + IN BOOLEAN IgnoreRtCheck + ); /** - Update the variable region with Variable information. These are the same - arguments as the EFI Variable services. - @param[in] VariableName Name of variable. + Gets the pointer to the end of the variable storage area. - @param[in] VendorGuid Guid of variable. + This function gets pointer to the end of the variable storage + area, according to the input variable store header. - @param[in] Data Variable data. + @param VarStoreHeader Pointer to the Variable Store Header. - @param[in] DataSize Size of data. 0 means delete. + @return Pointer to the end of the variable storage area. + +**/ +VARIABLE_HEADER * +GetEndPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ); + +/** + This code gets the size of variable header. + + @return Size of variable header in bytes in type UINTN. + +**/ +UINTN +GetVariableHeaderSize ( + VOID + ); + +/** + + This code gets the pointer to the variable name. + + @param Variable Pointer to the Variable Header. + + @return Pointer to Variable Name which is Unicode encoding. + +**/ +CHAR16 * +GetVariableNamePtr ( + IN VARIABLE_HEADER *Variable + ); + +/** + This code gets the pointer to the variable guid. + + @param Variable Pointer to the Variable Header. + + @return A EFI_GUID* pointer to Vendor Guid. + +**/ +EFI_GUID * +GetVendorGuidPtr ( + IN VARIABLE_HEADER *Variable + ); + +/** + + This code gets the pointer to the variable data. + + @param Variable Pointer to the Variable Header. + + @return Pointer to Variable Data. + +**/ +UINT8 * +GetVariableDataPtr ( + IN VARIABLE_HEADER *Variable + ); + +/** + + This code gets the size of variable data. + + @param Variable Pointer to the Variable Header. + + @return Size of variable in bytes. + +**/ +UINTN +DataSizeOfVariable ( + IN VARIABLE_HEADER *Variable + ); + +/** + This function is to check if the remaining variable space is enough to set + all Variables from argument list successfully. The purpose of the check + is to keep the consistency of the Variables to be in variable storage. - @param[in] Attributes Attribues of the variable. + Note: Variables are assumed to be in same storage. + The set sequence of Variables will be same with the sequence of VariableEntry from argument list, + so follow the argument sequence to check the Variables. + + @param[in] Attributes Variable attributes for Variable entries. + @param[in] Marker VA_LIST style variable argument list. + The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *. + A NULL terminates the list. The VariableSize of + VARIABLE_ENTRY_CONSISTENCY is the variable data size as input. + It will be changed to variable total size as output. + + @retval TRUE Have enough variable space to set the Variables successfully. + @retval FALSE No enough variable space to set the Variables successfully. + +**/ +BOOLEAN +EFIAPI +CheckRemainingSpaceForConsistencyInternal ( + IN UINT32 Attributes, + IN VA_LIST Marker + ); + +/** + 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] Variable The variable information that is used to keep track of variable usage. - @retval EFI_SUCCESS The update operation is success. + @param[in] TimeStamp Value of associated TimeStamp. + @retval EFI_SUCCESS The update operation is success. @retval EFI_OUT_OF_RESOURCES Variable region is full, cannot write other data into this region. **/ @@ -164,13 +320,16 @@ UpdateVariable ( IN VOID *Data, IN UINTN DataSize, IN UINT32 Attributes OPTIONAL, - IN OUT VARIABLE_POINTER_TRACK *Variable + IN UINT32 KeyIndex OPTIONAL, + IN UINT64 MonotonicCount OPTIONAL, + IN OUT VARIABLE_POINTER_TRACK *Variable, + IN EFI_TIME *TimeStamp OPTIONAL ); /** Return TRUE if ExitBootServices () has been called. - + @retval TRUE If ExitBootServices () has been called. **/ BOOLEAN @@ -181,8 +340,8 @@ AtRuntime ( /** Initializes a basic mutual exclusion lock. - This function initializes a basic mutual exclusion lock to the released state - and returns the lock. Each lock provides mutual exclusion access at its task + This function initializes a basic mutual exclusion lock to the released state + and returns the lock. Each lock provides mutual exclusion access at its task priority level. Since there is no preemption or multiprocessor support in EFI, acquiring the lock only consists of raising to the locks TPL. If Lock is NULL, then ASSERT(). @@ -200,7 +359,7 @@ InitializeLock ( IN EFI_TPL Priority ); - + /** Acquires lock only at boot time. Simply returns at runtime. @@ -234,7 +393,7 @@ AcquireLockOnlyAtBootTime ( VOID ReleaseLockOnlyAtBootTime ( IN EFI_LOCK *Lock - ); + ); /** Retrive the FVB protocol interface by HANDLE. @@ -246,7 +405,7 @@ ReleaseLockOnlyAtBootTime ( @retval EFI_SUCCESS The interface information for the specified protocol was returned. @retval EFI_UNSUPPORTED The device does not support the FVB protocol. @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL. - + **/ EFI_STATUS GetFvbByHandle ( @@ -254,25 +413,9 @@ GetFvbByHandle ( OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock ); - -/** - Retrive the Swap Address Range protocol interface. - - @param[out] SarProtocol The interface of SAR protocol - - @retval EFI_SUCCESS The SAR protocol instance was found and returned in SarProtocol. - @retval EFI_NOT_FOUND The SAR protocol instance was not found. - @retval EFI_INVALID_PARAMETER SarProtocol is NULL. - -**/ -EFI_STATUS -GetSarProtocol ( - OUT VOID **SarProtocol - ); - /** Function returns an array of handles that support the FVB protocol - in a buffer allocated from pool. + in a buffer allocated from pool. @param[out] NumberHandles The number of handles returned in Buffer. @param[out] Buffer A pointer to the buffer to return the requested @@ -283,7 +426,7 @@ GetSarProtocol ( @retval EFI_NOT_FOUND No FVB handle was found. @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results. @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL. - + **/ EFI_STATUS GetFvbCountAndBuffer ( @@ -305,13 +448,23 @@ VariableCommonInitialize ( /** This function reclaims variable storage if free size is below the threshold. - + **/ VOID ReclaimForOS( VOID - ); + ); + +/** + Get non-volatile maximum variable size. + @return Non-volatile maximum variable size. + +**/ +UINTN +GetNonVolatileMaxVariableSize ( + VOID + ); /** Initializes variable write service after FVB was ready. @@ -324,7 +477,7 @@ EFI_STATUS VariableWriteServiceInitialize ( VOID ); - + /** Retrive the SMM Fault Tolerent Write protocol interface. @@ -355,52 +508,21 @@ GetFvbInfoByAddress ( OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL ); -/** - Finds variable in storage blocks of volatile and non-volatile storage areas. - - This code finds variable in storage blocks of volatile and non-volatile storage areas. - If VariableName is an empty string, then we just return the first - qualified variable without comparing VariableName and VendorGuid. - If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check - at runtime when searching existing variable, only VariableName and VendorGuid are compared. - Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime. - - @param VariableName Name of the variable to be found. - @param VendorGuid Vendor GUID to be found. - @param PtrTrack VARIABLE_POINTER_TRACK structure for output, - including the range searched and the target position. - @param Global Pointer to VARIABLE_GLOBAL structure, including - base of volatile variable storage area, base of - NV variable storage area, and a lock. - @param IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute - check at runtime when searching variable. - - @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while - VendorGuid is NULL. - @retval EFI_SUCCESS Variable successfully found. - @retval EFI_NOT_FOUND Variable not found - -**/ -EFI_STATUS -FindVariable ( - IN CHAR16 *VariableName, - IN EFI_GUID *VendorGuid, - OUT VARIABLE_POINTER_TRACK *PtrTrack, - IN VARIABLE_GLOBAL *Global, - IN BOOLEAN IgnoreRtCheck - ); - /** This code finds variable in storage blocks (Volatile or Non-Volatile). + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode, and datasize and data are external input. + This function will do basic validation, before parse the data. + @param VariableName Name of Variable to be found. @param VendorGuid Variable vendor GUID. @param Attributes Attribute value of the variable found. @param DataSize Size of Data found. If size is less than the data, this value contains the required size. @param Data Data pointer. - + @return EFI_INVALID_PARAMETER Invalid parameter. @return EFI_SUCCESS Find the specified variable. @return EFI_NOT_FOUND Not found. @@ -417,6 +539,28 @@ VariableServiceGetVariable ( OUT VOID *Data ); +/** + This code Finds the Next available variable. + + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode. This function will do basic validation, before parse the data. + + @param[in] VariableName Pointer to variable name. + @param[in] VendorGuid Variable Vendor Guid. + @param[out] VariablePtr Pointer to variable header address. + + @return EFI_SUCCESS Find the specified variable. + @return EFI_NOT_FOUND Not found. + +**/ +EFI_STATUS +EFIAPI +VariableServiceGetNextVariableInternal ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VARIABLE_HEADER **VariablePtr + ); + /** This code Finds the Next available variable. @@ -449,6 +593,9 @@ VariableServiceGetNextVariableName ( Caution: This function may receive untrusted input. This function may be invoked in SMM mode, and datasize and data are external input. This function will do basic validation, before parse the data. + This function will parse the authentication carefully to avoid security issues, like + buffer overflow, integer overflow. + This function will check attribute carefully to avoid authentication bypass. @param VariableName Name of Variable to be found. @param VendorGuid Variable vendor GUID. @@ -530,7 +677,7 @@ VariableServiceQueryVariableInfo ( OUT UINT64 *MaximumVariableStorageSize, OUT UINT64 *RemainingVariableStorageSize, OUT UINT64 *MaximumVariableSize - ); + ); /** Mark a variable that will become read-only after leaving the DXE phase of execution. @@ -623,45 +770,65 @@ VarCheckRegisterSetVariableCheckHandler ( ); /** - Variable property set. + Internal variable property get. + + @param[in] Name Pointer to the variable name. + @param[in] Guid Pointer to the vendor GUID. + @param[out] VariableProperty Pointer to the output variable property. + + @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully. + @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found. + +**/ +EFI_STATUS +EFIAPI +InternalVarCheckVariablePropertyGet ( + IN CHAR16 *Name, + IN EFI_GUID *Guid, + OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty + ); + +/** + Internal variable property set. @param[in] Name Pointer to the variable name. @param[in] Guid Pointer to the vendor GUID. @param[in] VariableProperty Pointer to the input variable property. @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully. - @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string, - or the fields of VariableProperty are not valid. - @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has - already been signaled. @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request. **/ EFI_STATUS EFIAPI -VarCheckVariablePropertySet ( +InternalVarCheckVariablePropertySet ( IN CHAR16 *Name, IN EFI_GUID *Guid, IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty ); + /** - Internal variable property get. + Variable property set. - @param[in] Name Pointer to the variable name. - @param[in] Guid Pointer to the vendor GUID. - @param[out] VariableProperty Pointer to the output variable property. + @param[in] Name Pointer to the variable name. + @param[in] Guid Pointer to the vendor GUID. + @param[in] VariableProperty Pointer to the input variable property. - @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully. - @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found. + @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully. + @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string, + or the fields of VariableProperty are not valid. + @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has + already been signaled. + @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request. **/ EFI_STATUS EFIAPI -InternalVarCheckVariablePropertyGet ( +VarCheckVariablePropertySet ( IN CHAR16 *Name, IN EFI_GUID *Guid, - OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty + IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty ); /** @@ -695,4 +862,134 @@ InitializeVariableQuota ( extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; +extern AUTH_VAR_LIB_CONTEXT_OUT mContextOut; + +/** + Finds variable in storage blocks of volatile and non-volatile storage areas. + + This code finds variable in storage blocks of volatile and non-volatile storage areas. + If VariableName is an empty string, then we just return the first + qualified variable without comparing VariableName and VendorGuid. + + @param[in] VariableName Name of the variable to be found. + @param[in] VendorGuid Variable vendor GUID to be found. + @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO structure for + output of the variable found. + + @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, + while VendorGuid is NULL. + @retval EFI_SUCCESS Variable successfully found. + @retval EFI_NOT_FOUND Variable not found + +**/ +EFI_STATUS +EFIAPI +VariableExLibFindVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT AUTH_VARIABLE_INFO *AuthVariableInfo + ); + +/** + Finds next variable in storage blocks of volatile and non-volatile storage areas. + + This code finds next variable in storage blocks of volatile and non-volatile storage areas. + If VariableName is an empty string, then we just return the first + qualified variable without comparing VariableName and VendorGuid. + + @param[in] VariableName Name of the variable to be found. + @param[in] VendorGuid Variable vendor GUID to be found. + @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO structure for + output of the next variable. + + @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, + while VendorGuid is NULL. + @retval EFI_SUCCESS Variable successfully found. + @retval EFI_NOT_FOUND Variable not found + +**/ +EFI_STATUS +EFIAPI +VariableExLibFindNextVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT AUTH_VARIABLE_INFO *AuthVariableInfo + ); + +/** + 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. + +**/ +EFI_STATUS +EFIAPI +VariableExLibUpdateVariable ( + IN AUTH_VARIABLE_INFO *AuthVariableInfo + ); + +/** + Get scratch buffer. + + @param[in, out] ScratchBufferSize Scratch buffer size. If input size is greater than + the maximum supported buffer size, this value contains + the maximum supported buffer size as output. + @param[out] ScratchBuffer Pointer to scratch buffer address. + + @retval EFI_SUCCESS Get scratch buffer successfully. + @retval EFI_UNSUPPORTED If input size is greater than the maximum supported buffer size. + +**/ +EFI_STATUS +EFIAPI +VariableExLibGetScratchBuffer ( + IN OUT UINTN *ScratchBufferSize, + OUT VOID **ScratchBuffer + ); + +/** + This function is to check if the remaining variable space is enough to set + all Variables from argument list successfully. The purpose of the check + is to keep the consistency of the Variables to be in variable storage. + + Note: Variables are assumed to be in same storage. + The set sequence of Variables will be same with the sequence of VariableEntry from argument list, + so follow the argument sequence to check the Variables. + + @param[in] Attributes Variable attributes for Variable entries. + @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *. + A NULL terminates the list. The VariableSize of + VARIABLE_ENTRY_CONSISTENCY is the variable data size as input. + It will be changed to variable total size as output. + + @retval TRUE Have enough variable space to set the Variables successfully. + @retval FALSE No enough variable space to set the Variables successfully. + +**/ +BOOLEAN +EFIAPI +VariableExLibCheckRemainingSpaceForConsistency ( + IN UINT32 Attributes, + ... + ); + +/** + Return TRUE if at OS runtime. + + @retval TRUE If at OS runtime. + @retval FALSE If at boot time. + +**/ +BOOLEAN +EFIAPI +VariableExLibAtRuntime ( + VOID + ); + #endif diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c index c5cef31944..a95846a934 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c @@ -1,17 +1,16 @@ /** @file - Implement all four UEFI Runtime Variable services for the nonvolatile and volatile storage space and install variable architecture protocol. - + Copyright (C) 2013, Red Hat, Inc. Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ @@ -34,7 +33,7 @@ EDKII_VAR_CHECK_PROTOCOL mVarCheck = { VarCheckRegisterSe /** Return TRUE if ExitBootServices () has been called. - + @retval TRUE If ExitBootServices () has been called. **/ BOOLEAN @@ -49,8 +48,8 @@ AtRuntime ( /** Initializes a basic mutual exclusion lock. - This function initializes a basic mutual exclusion lock to the released state - and returns the lock. Each lock provides mutual exclusion access at its task + This function initializes a basic mutual exclusion lock to the released state + and returns the lock. Each lock provides mutual exclusion access at its task priority level. Since there is no preemption or multiprocessor support in EFI, acquiring the lock only consists of raising to the locks TPL. If Lock is NULL, then ASSERT(). @@ -141,7 +140,7 @@ GetFtwProtocol ( &gEfiFaultTolerantWriteProtocolGuid, NULL, FtwProtocol - ); + ); return Status; } @@ -155,7 +154,7 @@ GetFtwProtocol ( @retval EFI_SUCCESS The interface information for the specified protocol was returned. @retval EFI_UNSUPPORTED The device does not support the FVB protocol. @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL. - + **/ EFI_STATUS GetFvbByHandle ( @@ -176,7 +175,7 @@ GetFvbByHandle ( /** Function returns an array of handles that support the FVB protocol - in a buffer allocated from pool. + in a buffer allocated from pool. @param[out] NumberHandles The number of handles returned in Buffer. @param[out] Buffer A pointer to the buffer to return the requested @@ -187,7 +186,7 @@ GetFvbByHandle ( @retval EFI_NOT_FOUND No FVB handle was found. @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results. @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL. - + **/ EFI_STATUS GetFvbCountAndBuffer ( @@ -246,7 +245,7 @@ VariableClassAddressChangeEvent ( EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.HobVariableBase); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal); - EfiConvertPointer (0x0, (VOID **) &mNvVariableCache); + EfiConvertPointer (0x0, (VOID **) &mNvVariableCache); EfiConvertPointer (0x0, (VOID **) &mHandlerTable); for (Index = 0; Index < mNumberOfHandler; Index++) { EfiConvertPointer (0x0, (VOID **) &mHandlerTable[Index]); @@ -257,6 +256,12 @@ VariableClassAddressChangeEvent ( Status = EfiConvertList (0x0, &mVarCheckVariableList); ASSERT_EFI_ERROR (Status); + + if (mContextOut.AddressPointer != NULL) { + for (Index = 0; Index < mContextOut.AddressPointerCount; Index++) { + EfiConvertPointer (0x0, (VOID **) &mContextOut.AddressPointer[Index]); + } + } } @@ -288,8 +293,14 @@ OnReadyToBoot ( InitializeVariableQuota (); ReclaimForOS (); if (FeaturePcdGet (PcdVariableCollectStatistics)) { - gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo); + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { + gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, gVariableInfo); + } else { + gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo); + } } + + gBS->CloseEvent (Event); } /** @@ -316,17 +327,19 @@ OnEndOfDxe ( if (PcdGetBool (PcdReclaimVariableSpaceAtEndOfDxe)) { ReclaimForOS (); } + + gBS->CloseEvent (Event); } /** Fault Tolerant Write protocol notification event handler. - Non-Volatile variable write may needs FTW protocol to reclaim when + Non-Volatile variable write may needs FTW protocol to reclaim when writting variable. @param[in] Event Event whose notification function is being invoked. @param[in] Context Pointer to the notification function's context. - + **/ VOID EFIAPI @@ -394,21 +407,23 @@ FtwNotificationEvent ( DEBUG ((DEBUG_WARN, "Variable driver failed to add EFI_MEMORY_RUNTIME attribute to Flash.\n")); } } - + Status = VariableWriteServiceInitialize (); - ASSERT_EFI_ERROR (Status); - + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. Status = %r\n", Status)); + } + // // Install the Variable Write Architectural protocol. // Status = gBS->InstallProtocolInterface ( &mHandle, - &gEfiVariableWriteArchProtocolGuid, + &gEfiVariableWriteArchProtocolGuid, EFI_NATIVE_INTERFACE, NULL ); ASSERT_EFI_ERROR (Status); - + // // Close the notify event to avoid install gEfiVariableWriteArchProtocolGuid again. // @@ -419,13 +434,13 @@ FtwNotificationEvent ( /** Variable Driver main entry point. The Variable driver places the 4 EFI - runtime services in the EFI System Table and installs arch protocols - for variable read and write services being availible. It also registers + runtime services in the EFI System Table and installs arch protocols + for variable read and write services being available. It also registers a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. - @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. - + @retval EFI_SUCCESS Variable service successfully initialized. **/ @@ -463,13 +478,13 @@ VariableServiceInitialize ( SystemTable->RuntimeServices->GetNextVariableName = VariableServiceGetNextVariableName; SystemTable->RuntimeServices->SetVariable = VariableServiceSetVariable; SystemTable->RuntimeServices->QueryVariableInfo = VariableServiceQueryVariableInfo; - + // // Now install the Variable Runtime Architectural protocol on a new handle. // Status = gBS->InstallProtocolInterface ( &mHandle, - &gEfiVariableArchProtocolGuid, + &gEfiVariableArchProtocolGuid, EFI_NATIVE_INTERFACE, NULL ); @@ -477,7 +492,7 @@ VariableServiceInitialize ( // // Register FtwNotificationEvent () notify function. - // + // EfiCreateProtocolNotifyEvent ( &gEfiFaultTolerantWriteProtocolGuid, TPL_CALLBACK, @@ -500,9 +515,9 @@ VariableServiceInitialize ( // Register the event handling function to reclaim variable for OS usage. // Status = EfiCreateEventReadyToBootEx ( - TPL_NOTIFY, - OnReadyToBoot, - NULL, + TPL_NOTIFY, + OnReadyToBoot, + NULL, &ReadyToBootEvent ); ASSERT_EFI_ERROR (Status); diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c new file mode 100644 index 0000000000..9067f64f15 --- /dev/null +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c @@ -0,0 +1,256 @@ +/** @file + Provides variable driver extended services. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Variable.h" + +/** + Finds variable in storage blocks of volatile and non-volatile storage areas. + + This code finds variable in storage blocks of volatile and non-volatile storage areas. + If VariableName is an empty string, then we just return the first + qualified variable without comparing VariableName and VendorGuid. + + @param[in] VariableName Name of the variable to be found. + @param[in] VendorGuid Variable vendor GUID to be found. + @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO structure for + output of the variable found. + + @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, + while VendorGuid is NULL. + @retval EFI_SUCCESS Variable successfully found. + @retval EFI_NOT_FOUND Variable not found + +**/ +EFI_STATUS +EFIAPI +VariableExLibFindVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT AUTH_VARIABLE_INFO *AuthVariableInfo + ) +{ + EFI_STATUS Status; + VARIABLE_POINTER_TRACK Variable; + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + Status = FindVariable ( + VariableName, + VendorGuid, + &Variable, + &mVariableModuleGlobal->VariableGlobal, + FALSE + ); + if (EFI_ERROR (Status)) { + AuthVariableInfo->Data = NULL; + AuthVariableInfo->DataSize = 0; + AuthVariableInfo->Attributes = 0; + AuthVariableInfo->PubKeyIndex = 0; + AuthVariableInfo->MonotonicCount = 0; + AuthVariableInfo->TimeStamp = NULL; + return Status; + } + + AuthVariableInfo->DataSize = DataSizeOfVariable (Variable.CurrPtr); + AuthVariableInfo->Data = GetVariableDataPtr (Variable.CurrPtr); + AuthVariableInfo->Attributes = Variable.CurrPtr->Attributes; + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable.CurrPtr; + AuthVariableInfo->PubKeyIndex = AuthVariable->PubKeyIndex; + AuthVariableInfo->MonotonicCount = AuthVariable->MonotonicCount; + AuthVariableInfo->TimeStamp = &AuthVariable->TimeStamp; + } + + return EFI_SUCCESS; +} + +/** + Finds next variable in storage blocks of volatile and non-volatile storage areas. + + This code finds next variable in storage blocks of volatile and non-volatile storage areas. + If VariableName is an empty string, then we just return the first + qualified variable without comparing VariableName and VendorGuid. + + @param[in] VariableName Name of the variable to be found. + @param[in] VendorGuid Variable vendor GUID to be found. + @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO structure for + output of the next variable. + + @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, + while VendorGuid is NULL. + @retval EFI_SUCCESS Variable successfully found. + @retval EFI_NOT_FOUND Variable not found + +**/ +EFI_STATUS +EFIAPI +VariableExLibFindNextVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT AUTH_VARIABLE_INFO *AuthVariableInfo + ) +{ + EFI_STATUS Status; + VARIABLE_HEADER *VariablePtr; + AUTHENTICATED_VARIABLE_HEADER *AuthVariablePtr; + + Status = VariableServiceGetNextVariableInternal ( + VariableName, + VendorGuid, + &VariablePtr + ); + if (EFI_ERROR (Status)) { + AuthVariableInfo->VariableName = NULL; + AuthVariableInfo->VendorGuid = NULL; + AuthVariableInfo->Data = NULL; + AuthVariableInfo->DataSize = 0; + AuthVariableInfo->Attributes = 0; + AuthVariableInfo->PubKeyIndex = 0; + AuthVariableInfo->MonotonicCount = 0; + AuthVariableInfo->TimeStamp = NULL; + return Status; + } + + AuthVariableInfo->VariableName = GetVariableNamePtr (VariablePtr); + AuthVariableInfo->VendorGuid = GetVendorGuidPtr (VariablePtr); + AuthVariableInfo->DataSize = DataSizeOfVariable (VariablePtr); + AuthVariableInfo->Data = GetVariableDataPtr (VariablePtr); + AuthVariableInfo->Attributes = VariablePtr->Attributes; + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { + AuthVariablePtr = (AUTHENTICATED_VARIABLE_HEADER *) VariablePtr; + AuthVariableInfo->PubKeyIndex = AuthVariablePtr->PubKeyIndex; + AuthVariableInfo->MonotonicCount = AuthVariablePtr->MonotonicCount; + AuthVariableInfo->TimeStamp = &AuthVariablePtr->TimeStamp; + } + + return EFI_SUCCESS; +} + +/** + 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. + +**/ +EFI_STATUS +EFIAPI +VariableExLibUpdateVariable ( + IN AUTH_VARIABLE_INFO *AuthVariableInfo + ) +{ + VARIABLE_POINTER_TRACK Variable; + + FindVariable (AuthVariableInfo->VariableName, AuthVariableInfo->VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE); + return UpdateVariable ( + AuthVariableInfo->VariableName, + AuthVariableInfo->VendorGuid, + AuthVariableInfo->Data, + AuthVariableInfo->DataSize, + AuthVariableInfo->Attributes, + AuthVariableInfo->PubKeyIndex, + AuthVariableInfo->MonotonicCount, + &Variable, + AuthVariableInfo->TimeStamp + ); +} + +/** + Get scratch buffer. + + @param[in, out] ScratchBufferSize Scratch buffer size. If input size is greater than + the maximum supported buffer size, this value contains + the maximum supported buffer size as output. + @param[out] ScratchBuffer Pointer to scratch buffer address. + + @retval EFI_SUCCESS Get scratch buffer successfully. + @retval EFI_UNSUPPORTED If input size is greater than the maximum supported buffer size. + +**/ +EFI_STATUS +EFIAPI +VariableExLibGetScratchBuffer ( + IN OUT UINTN *ScratchBufferSize, + OUT VOID **ScratchBuffer + ) +{ + UINTN MaxBufferSize; + + MaxBufferSize = mVariableModuleGlobal->ScratchBufferSize; + if (*ScratchBufferSize > MaxBufferSize) { + *ScratchBufferSize = MaxBufferSize; + return EFI_UNSUPPORTED; + } + + *ScratchBuffer = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)); + return EFI_SUCCESS; +} + +/** + This function is to check if the remaining variable space is enough to set + all Variables from argument list successfully. The purpose of the check + is to keep the consistency of the Variables to be in variable storage. + + Note: Variables are assumed to be in same storage. + The set sequence of Variables will be same with the sequence of VariableEntry from argument list, + so follow the argument sequence to check the Variables. + + @param[in] Attributes Variable attributes for Variable entries. + @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *. + A NULL terminates the list. The VariableSize of + VARIABLE_ENTRY_CONSISTENCY is the variable data size as input. + It will be changed to variable total size as output. + + @retval TRUE Have enough variable space to set the Variables successfully. + @retval FALSE No enough variable space to set the Variables successfully. + +**/ +BOOLEAN +EFIAPI +VariableExLibCheckRemainingSpaceForConsistency ( + IN UINT32 Attributes, + ... + ) +{ + VA_LIST Marker; + BOOLEAN Return; + + VA_START (Marker, Attributes); + + Return = CheckRemainingSpaceForConsistencyInternal (Attributes, Marker); + + VA_END (Marker); + + return Return; +} + +/** + Return TRUE if at OS runtime. + + @retval TRUE If at OS runtime. + @retval FALSE If at boot time. + +**/ +BOOLEAN +EFIAPI +VariableExLibAtRuntime ( + VOID + ) +{ + return AtRuntime (); +} diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf index 05d276590c..6a523b8d76 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf @@ -1,7 +1,8 @@ ## @file -# This module installs variable arch protocol and variable write arch protocol. +# Provides variable service. # -# It provides four EFI_RUNTIME_SERVICES: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo. +# This module installs variable arch protocol and variable write arch protocol to provide +# variable services: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo. # # Caution: This module requires additional review when modified. # This driver will have external input - variable data. @@ -9,14 +10,12 @@ # buffer overflow or integer overflow. # # Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
-# -# This program and the accompanying materials -# are licensed and made available under the terms and conditions of the BSD License -# which accompanies this distribution. The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. # ## @@ -42,7 +41,9 @@ Variable.c VariableDxe.c Variable.h + Measurement.c VarCheck.c + VariableExLib.c [Packages] MdePkg/MdePkg.dec @@ -62,6 +63,8 @@ PcdLib HobLib DevicePathLib + TpmMeasurementLib + AuthVariableLib [Protocols] gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES @@ -74,23 +77,41 @@ gEdkiiVarCheckProtocolGuid ## PRODUCES [Guids] + ## PRODUCES ## GUID # Signature of Variable store header + ## CONSUMES ## GUID # Signature of Variable store header + ## SOMETIMES_CONSUMES ## HOB + ## SOMETIMES_PRODUCES ## SystemTable + gEfiAuthenticatedVariableGuid + ## PRODUCES ## GUID # Signature of Variable store header ## CONSUMES ## GUID # Signature of Variable store header ## SOMETIMES_CONSUMES ## HOB ## SOMETIMES_PRODUCES ## SystemTable gEfiVariableGuid + ## SOMETIMES_CONSUMES ## Variable:L"PlatformLang" ## SOMETIMES_PRODUCES ## Variable:L"PlatformLang" ## SOMETIMES_CONSUMES ## Variable:L"Lang" ## SOMETIMES_PRODUCES ## Variable:L"Lang" ## SOMETIMES_CONSUMES ## Variable:L"HwErrRecSupport" + ## SOMETIMES_CONSUMES ## Variable:L"SetupMode" + ## SOMETIMES_CONSUMES ## Variable:L"PK" + ## SOMETIMES_CONSUMES ## Variable:L"KEK" + ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot" + ## SOMETIMES_CONSUMES ## Variable:L"SignatureSupport" + ## SOMETIMES_CONSUMES ## Variable:L"VendorKeys" gEfiGlobalVariableGuid + + ## SOMETIMES_CONSUMES ## Variable:L"DB" + ## SOMETIMES_CONSUMES ## Variable:L"DBX" + ## SOMETIMES_CONSUMES ## Variable:L"DBT" + gEfiImageSecurityDatabaseGuid + gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event gEfiSystemNvDataFvGuid ## CONSUMES ## GUID gEfiHardwareErrorVariableGuid ## SOMETIMES_CONSUMES ## Variable:L"HwErrRec####" gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event - ## SOMETIMES_CONSUMES ## HOB - gEdkiiFaultTolerantWriteGuid + gEdkiiFaultTolerantWriteGuid ## SOMETIMES_CONSUMES ## HOB gEdkiiVarErrorFlagGuid ## CONSUMES ## GUID [Pcd] @@ -98,6 +119,7 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## SOMETIMES_CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize ## CONSUMES @@ -107,7 +129,7 @@ [FeaturePcd] gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## CONSUMES # statistic the information of variable. - gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## CONSUMES # Auto update PlatformLang/Lang [Depex] TRUE diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.uni b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.uni index ee8acd0ad15e03ec5b02d459b7e2b24fda6f14c1..48745b62f5dced96f8a0e908b2bc1bb50e37af57 100644 GIT binary patch delta 229 zcmbOuazjF-K&A%H%stT$BGX@=aFbY>3rk;AP-q&<8>ot-#>PP{N?VP{2^ckk3%Ykjaq3 zkjhXD6iEZ}OM#*a46Y1rKvnS!K@6b`eheW%wl7dDo*@`W1~G&I`OZLA@Z|fPy^}96 o3T(c?Xu-s2vRRPDpM}wLvN~ryqu%6+9JQWQwTVj!><5rP0NqwCng9R* diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c index 5908408782..1cf288cb98 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c @@ -1,7 +1,6 @@ /** @file - - The sample implementation for SMM variable protocol. And this driver - implements an SMI handler to communicate with the DXE runtime driver + The sample implementation for SMM variable protocol. And this driver + implements an SMI handler to communicate with the DXE runtime driver to provide variable services. Caution: This module requires additional review when modified. @@ -11,20 +10,21 @@ SmmVariableHandler() will receive untrusted input and do basic validation. - Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(), - VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(), + Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(), + VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(), SmmVariableGetStatistics() should also do validation based on its own knowledge. Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ + #include #include #include @@ -34,7 +34,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include -#include #include #include "Variable.h" @@ -48,6 +47,23 @@ UINTN mVariableBufferPayloadSize; extern BOOLEAN mEndOfDxe; extern BOOLEAN mEnableLocking; +/** + SecureBoot Hook for SetVariable. + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + +**/ +VOID +EFIAPI +SecureBootHook ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid + ) +{ + return ; +} + /** This code sets variable in storage blocks (Volatile or Non-Volatile). @@ -106,7 +122,7 @@ EDKII_SMM_VAR_CHECK_PROTOCOL mSmmVarCheck = { VarCheckRegisterSetVariableCheckHa /** Return TRUE if ExitBootServices () has been called. - + @retval TRUE If ExitBootServices () has been called. **/ BOOLEAN @@ -120,8 +136,8 @@ AtRuntime ( /** Initializes a basic mutual exclusion lock. - This function initializes a basic mutual exclusion lock to the released state - and returns the lock. Each lock provides mutual exclusion access at its task + This function initializes a basic mutual exclusion lock to the released state + and returns the lock. Each lock provides mutual exclusion access at its task priority level. Since there is no preemption or multiprocessor support in EFI, acquiring the lock only consists of raising to the locks TPL. If Lock is NULL, then ASSERT(). @@ -204,8 +220,8 @@ GetFtwProtocol ( // Locate Smm Fault Tolerent Write protocol // Status = gSmst->SmmLocateProtocol ( - &gEfiSmmFaultTolerantWriteProtocolGuid, - NULL, + &gEfiSmmFaultTolerantWriteProtocolGuid, + NULL, FtwProtocol ); return Status; @@ -243,7 +259,7 @@ GetFvbByHandle ( /** Function returns an array of handles that support the SMM FVB protocol - in a buffer allocated from pool. + in a buffer allocated from pool. @param[out] NumberHandles The number of handles returned in Buffer. @param[out] Buffer A pointer to the buffer to return the requested @@ -314,16 +330,17 @@ GetFvbCountAndBuffer ( InfoEntry and InfoSize are external input. Care must be taken to make sure not security issue at runtime. @param[in, out] InfoEntry A pointer to the buffer of variable information entry. - On input, point to the variable information returned last time. if + On input, point to the variable information returned last time. if InfoEntry->VendorGuid is zero, return the first information. On output, point to the next variable information. @param[in, out] InfoSize On input, the size of the variable information buffer. On output, the returned variable information size. - @retval EFI_SUCCESS The variable information is found and returned successfully. - @retval EFI_UNSUPPORTED No variable inoformation exists in variable driver. The - PcdVariableCollectStatistics should be set TRUE to support it. - @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the next variable information. + @retval EFI_SUCCESS The variable information is found and returned successfully. + @retval EFI_UNSUPPORTED No variable inoformation exists in variable driver. The + PcdVariableCollectStatistics should be set TRUE to support it. + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the next variable information. + @retval EFI_INVALID_PARAMETER Input parameter is invalid. **/ EFI_STATUS @@ -338,8 +355,11 @@ SmmVariableGetStatistics ( CHAR16 *InfoName; EFI_GUID VendorGuid; - ASSERT (InfoEntry != NULL); - VariableInfo = gVariableInfo; + if (InfoEntry == NULL) { + return EFI_INVALID_PARAMETER; + } + + VariableInfo = gVariableInfo; if (VariableInfo == NULL) { return EFI_UNSUPPORTED; } @@ -381,7 +401,7 @@ SmmVariableGetStatistics ( } VariableInfo = VariableInfo->Next; }; - + if (VariableInfo == NULL) { *InfoSize = 0; return EFI_SUCCESS; @@ -399,7 +419,7 @@ SmmVariableGetStatistics ( CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY)); CopyMem (InfoName, VariableInfo->Name, StrSize (VariableInfo->Name)); *InfoSize = StatisticsInfoSize; - + return EFI_SUCCESS; } @@ -411,8 +431,8 @@ SmmVariableGetStatistics ( Caution: This function may receive untrusted input. This variable data and communicate buffer are external input, so this function will do basic validation. - Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(), - VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(), + Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(), + VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(), SmmVariableGetStatistics() should also do validation based on its own knowledge. @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). @@ -422,11 +442,11 @@ SmmVariableGetStatistics ( be conveyed from a non-SMM environment into an SMM environment. @param[in, out] CommBufferSize The size of the CommBuffer. - @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers + @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers should still be called. - @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should + @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should still be called. - @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still + @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still be called. @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced. **/ @@ -444,6 +464,7 @@ SmmVariableHandler ( SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader; SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *GetNextVariableName; SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *QueryVariableInfo; + SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *GetPayloadSize; VARIABLE_INFO_ENTRY *VariableInfo; SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock; SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty; @@ -496,7 +517,7 @@ SmmVariableHandler ( Status = EFI_ACCESS_DENIED; goto EXIT; } - InfoSize = OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + InfoSize = OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize + SmmVariableHeader->NameSize; // @@ -525,7 +546,7 @@ SmmVariableHandler ( ); CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize); break; - + case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME: if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) { DEBUG ((EFI_D_ERROR, "GetNextVariableName: SMM communication buffer size invalid!\n")); @@ -570,7 +591,7 @@ SmmVariableHandler ( ); CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize); break; - + case SMM_VARIABLE_FUNCTION_SET_VARIABLE: if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) { DEBUG ((EFI_D_ERROR, "SetVariable: SMM communication buffer size invalid!\n")); @@ -618,7 +639,7 @@ SmmVariableHandler ( (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize ); break; - + case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO: if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO)) { DEBUG ((EFI_D_ERROR, "QueryVariableInfo: SMM communication buffer size invalid!\n")); @@ -634,6 +655,16 @@ SmmVariableHandler ( ); break; + case SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE: + if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE)) { + DEBUG ((EFI_D_ERROR, "GetPayloadSize: SMM communication buffer size invalid!\n")); + return EFI_SUCCESS; + } + GetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data; + GetPayloadSize->VariablePayloadSize = mVariableBufferPayloadSize; + Status = EFI_SUCCESS; + break; + case SMM_VARIABLE_FUNCTION_READY_TO_BOOT: mEndOfDxe = TRUE; // @@ -647,7 +678,7 @@ SmmVariableHandler ( ReclaimForOS (); Status = EFI_SUCCESS; break; - + case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE: mAtRuntime = TRUE; Status = EFI_SUCCESS; @@ -658,15 +689,15 @@ SmmVariableHandler ( InfoSize = TempCommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE; // - // Do not need to check SmmVariableFunctionHeader->Data in SMRAM here. - // It is covered by previous CommBuffer check + // Do not need to check SmmVariableFunctionHeader->Data in SMRAM here. + // It is covered by previous CommBuffer check // - + if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)CommBufferSize, sizeof(UINTN))) { DEBUG ((EFI_D_ERROR, "GetStatistics: SMM communication buffer in SMRAM!\n")); Status = EFI_ACCESS_DENIED; goto EXIT; - } + } Status = SmmVariableGetStatistics (VariableInfo, &InfoSize); *CommBufferSize = InfoSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE; @@ -784,16 +815,16 @@ SmmEndOfDxeCallback ( /** SMM Fault Tolerant Write protocol notification event handler. - Non-Volatile variable write may needs FTW protocol to reclaim when + Non-Volatile variable write may needs FTW protocol to reclaim when writting variable. - + @param Protocol Points to the protocol's unique identifier @param Interface Points to the interface instance @param Handle The handle on which the interface was installed @retval EFI_SUCCESS SmmEventCallback runs successfully @retval EFI_NOT_FOUND The Fvb protocol for variable is not found. - + **/ EFI_STATUS EFIAPI @@ -808,7 +839,7 @@ SmmFtwNotificationEvent ( EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; EFI_PHYSICAL_ADDRESS NvStorageVariableBase; UINTN FtwMaxBlockSize; - + if (mVariableModuleGlobal->FvbInstance != NULL) { return EFI_SUCCESS; } @@ -839,10 +870,12 @@ SmmFtwNotificationEvent ( } mVariableModuleGlobal->FvbInstance = FvbProtocol; - + Status = VariableWriteServiceInitialize (); - ASSERT_EFI_ERROR (Status); - + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. Status = %r\n", Status)); + } + // // Notify the variable wrapper driver the variable write service is ready // @@ -853,20 +886,20 @@ SmmFtwNotificationEvent ( NULL ); ASSERT_EFI_ERROR (Status); - + return EFI_SUCCESS; } /** Variable Driver main entry point. The Variable driver places the 4 EFI - runtime services in the EFI System Table and installs arch protocols + runtime services in the EFI System Table and installs arch protocols for variable read and write services being available. It also registers a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. - @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. - + @retval EFI_SUCCESS Variable service successfully initialized. **/ @@ -908,8 +941,8 @@ VariableServiceInitialize ( ); ASSERT_EFI_ERROR (Status); - mVariableBufferPayloadSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) + - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) - sizeof (VARIABLE_HEADER); + mVariableBufferPayloadSize = GetNonVolatileMaxVariableSize () + + OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) - GetVariableHeaderSize (); Status = gSmst->SmmAllocatePool ( EfiRuntimeServicesData, @@ -924,7 +957,7 @@ VariableServiceInitialize ( VariableHandle = NULL; Status = gSmst->SmiHandlerRegister (SmmVariableHandler, &gEfiSmmVariableProtocolGuid, &VariableHandle); ASSERT_EFI_ERROR (Status); - + // // Notify the variable wrapper driver the variable service is ready // @@ -935,7 +968,7 @@ VariableServiceInitialize ( &gSmmVariable ); ASSERT_EFI_ERROR (Status); - + // // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function. // @@ -948,7 +981,7 @@ VariableServiceInitialize ( // // Register FtwNotificationEvent () notify function. - // + // Status = gSmst->SmmRegisterProtocolNotify ( &gEfiSmmFaultTolerantWriteProtocolGuid, SmmFtwNotificationEvent, @@ -957,7 +990,7 @@ VariableServiceInitialize ( ASSERT_EFI_ERROR (Status); SmmFtwNotificationEvent (NULL, NULL, NULL); - + return EFI_SUCCESS; } diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf index 9b8675b631..47b7f3a2c2 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf @@ -1,16 +1,22 @@ ## @file +# Provides SMM variable service. +# # This module installs SMM variable protocol into SMM protocol database, -# which can be used by SMM driver, and installs SMM variable protocol +# which can be used by SMM driver, and installs SMM variable protocol # into BS protocol database, which can be used to notify the SMM Runtime # Dxe driver that the SMM variable service is ready. -# This module should be used with SMM Runtime DXE module together. The -# SMM Runtime DXE module would install variable arch protocol and variable +# This module should be used with SMM Runtime DXE module together. The +# SMM Runtime DXE module would install variable arch protocol and variable # write arch protocol based on SMM variable module. # # Caution: This module requires additional review when modified. # This driver will have external input - variable data and communicate buffer in SMM mode. -# This external input must be validated carefully to avoid security issue like -# buffer overflow, integer overflow. +# This external input must be validated carefully to avoid security issues such as +# buffer overflow or integer overflow. +# The whole SMM authentication variable design relies on the integrity of flash part and SMM. +# which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory +# 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 - 2015, Intel Corporation. All rights reserved.
# This program and the accompanying materials @@ -20,7 +26,6 @@ # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. # -# ## [Defines] @@ -46,6 +51,7 @@ VariableSmm.c VarCheck.c Variable.h + VariableExLib.c [Packages] MdePkg/MdePkg.dec @@ -65,6 +71,7 @@ PcdLib DevicePathLib SmmMemLib + AuthVariableLib [Protocols] gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES @@ -81,35 +88,55 @@ ## PRODUCES ## GUID # Signature of Variable store header ## CONSUMES ## GUID # Signature of Variable store header ## SOMETIMES_CONSUMES ## HOB + ## SOMETIMES_PRODUCES ## SystemTable + gEfiAuthenticatedVariableGuid + + ## PRODUCES ## GUID # Signature of Variable store header + ## CONSUMES ## GUID # Signature of Variable store header + ## SOMETIMES_CONSUMES ## HOB + ## SOMETIMES_PRODUCES ## SystemTable gEfiVariableGuid + ## SOMETIMES_CONSUMES ## Variable:L"PlatformLang" ## SOMETIMES_PRODUCES ## Variable:L"PlatformLang" ## SOMETIMES_CONSUMES ## Variable:L"Lang" ## SOMETIMES_PRODUCES ## Variable:L"Lang" ## SOMETIMES_CONSUMES ## Variable:L"HwErrRecSupport" + ## SOMETIMES_CONSUMES ## Variable:L"SetupMode" + ## SOMETIMES_CONSUMES ## Variable:L"PK" + ## SOMETIMES_CONSUMES ## Variable:L"KEK" + ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot" + ## SOMETIMES_CONSUMES ## Variable:L"SignatureSupport" + ## SOMETIMES_CONSUMES ## Variable:L"VendorKeys" gEfiGlobalVariableGuid - gSmmVariableWriteGuid ## PRODUCES ## UNDEFINED # Install protocol + + ## SOMETIMES_CONSUMES ## Variable:L"DB" + ## SOMETIMES_CONSUMES ## Variable:L"DBX" + ## SOMETIMES_CONSUMES ## Variable:L"DBT" + gEfiImageSecurityDatabaseGuid + + gSmmVariableWriteGuid ## PRODUCES ## GUID # Install protocol gEfiSystemNvDataFvGuid ## CONSUMES ## GUID gEfiHardwareErrorVariableGuid ## SOMETIMES_CONSUMES ## Variable:L"HwErrRec####" - ## SOMETIMES_CONSUMES ## HOB - gEdkiiFaultTolerantWriteGuid + gEdkiiFaultTolerantWriteGuid ## SOMETIMES_CONSUMES ## HOB gEdkiiVarErrorFlagGuid ## CONSUMES ## GUID [Pcd] - gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES - gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## SOMETIMES_CONSUMES - gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## CONSUMES - gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize ## CONSUMES - gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize ## CONSUMES - gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize ## CONSUMES - gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize ## CONSUMES - gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe ## CONSUMES [FeaturePcd] - gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## CONSUMES # statistic the information of variable. - gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## CONSUMES # statistic the information of variable. + gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## CONSUMES # Auto update PlatformLang/Lang [Depex] TRUE diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.uni b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.uni index 3e72476e6479820c62b0c68f2e581a2be40917d1..60502d0451b40b40de52e1339e7666801b1b5409 100644 GIT binary patch delta 216 zcmZ1^`$TDi3V#4Y5ko#h8AB#R3PUPG@#I7vZAQJxyV+zXCou6%w5geVgPm{k2X2YU zUffBWJs6iTZGOjmgHf=UL4l!|p_Cz+Ap^)t1Zq6bs>!MVG^%LwPu6rs)6I!&{w&x` zpFEFe%0!!z$!&~ko4vS07#Z~@DoRhzV=9<@j8S580k6blG3KPnCVVNAzcJTMu3_0U Y*^G4p7W=NVD#Gnk%H%mr5|htymrVS}F diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmExtra.uni b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmExtra.uni index e42cc12b4de70d9e51476aa891469a7d1a84cea5..46f984c809f21e48ed023ea68e685ba74d3f854e 100644 GIT binary patch delta 47 scmX@YwS{ZK4o1_BJ0n??f*EpwPyvYZ8B!QZ8FCm>8I%}!8MxpW05F9KE&u=k delta 63 zcmdnOb%ble4n~uWJ0n?)6c`*Cl7TRlp%@4i7+e@47+k@05kn?J8Bn~4L5YEvfeVfS D -This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include @@ -39,15 +38,13 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include -#include #include #include #include -#include #include -EFI_HANDLE mHandle = NULL; +EFI_HANDLE mHandle = NULL; EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL; EFI_EVENT mVirtualAddressChangeEvent = NULL; EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL; @@ -59,6 +56,20 @@ EFI_LOCK mVariableServicesLock; EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock; EDKII_VAR_CHECK_PROTOCOL mVarCheck; +/** + SecureBoot Hook for SetVariable. + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + +**/ +VOID +EFIAPI +SecureBootHook ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid + ); + /** Acquires lock only at boot time. Simply returns at runtime. @@ -115,7 +126,7 @@ ReleaseLockOnlyAtBootTime ( @param[out] DataPtr Points to the data in the communicate buffer. @param[in] DataSize The data size to send to SMM. @param[in] Function The function number to initialize the communicate header. - + @retval EFI_INVALID_PARAMETER The data size is too big. @retval EFI_SUCCESS Find the specified variable. @@ -127,10 +138,10 @@ InitCommunicateBuffer ( IN UINTN Function ) { - EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; - SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; + - if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) { return EFI_INVALID_PARAMETER; } @@ -138,7 +149,7 @@ InitCommunicateBuffer ( SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer; CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid); SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE; - + SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data; SmmVariableFunctionHeader->Function = Function; if (DataPtr != NULL) { @@ -155,8 +166,8 @@ InitCommunicateBuffer ( @param[in] DataSize This size of the function header and the data. @retval EFI_SUCCESS Success is returned from the functin in SMM. - @retval Others Failure is returned from the function in SMM. - + @retval Others Failure is returned from the function in SMM. + **/ EFI_STATUS SendCommunicateBuffer ( @@ -165,9 +176,9 @@ SendCommunicateBuffer ( { EFI_STATUS Status; UINTN CommSize; - EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; - + CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE; Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize); ASSERT_EFI_ERROR (Status); @@ -432,7 +443,7 @@ Done: @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_INVALID_PARAMETER Invalid parameter. @retval EFI_SUCCESS Find the specified variable. @retval EFI_NOT_FOUND Not found. @@ -594,7 +605,6 @@ RuntimeServiceGetNextVariableName ( // PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize); - Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME); if (EFI_ERROR (Status)) { goto Done; @@ -633,9 +643,9 @@ RuntimeServiceGetNextVariableName ( if (EFI_ERROR (Status)) { goto Done; } - + CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid); - CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize); + CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize); Done: ReleaseLockOnlyAtBootTime (&mVariableServicesLock); @@ -673,16 +683,16 @@ RuntimeServiceSetVariable ( ) { EFI_STATUS Status; - UINTN PayloadSize; + UINTN PayloadSize; SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader; UINTN VariableNameSize; - + // // Check input parameters. // if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) { return EFI_INVALID_PARAMETER; - } + } if (DataSize != 0 && Data == NULL) { return EFI_INVALID_PARAMETER; @@ -700,7 +710,7 @@ RuntimeServiceSetVariable ( } AcquireLockOnlyAtBootTime(&mVariableServicesLock); - + // // Init the communicate buffer. The buffer data size is: // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. @@ -726,6 +736,15 @@ RuntimeServiceSetVariable ( Done: ReleaseLockOnlyAtBootTime (&mVariableServicesLock); + + if (!EfiAtRuntime ()) { + if (!EFI_ERROR (Status)) { + SecureBootHook ( + VariableName, + VendorGuid + ); + } + } return Status; } @@ -794,7 +813,7 @@ RuntimeServiceQueryVariableInfo ( // *MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize; *MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize; - *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize; + *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize; Done: ReleaseLockOnlyAtBootTime (&mVariableServicesLock); @@ -822,7 +841,7 @@ OnExitBootServices ( // Init the communicate buffer. The buffer data size is: // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE. // - InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE); + InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE); // // Send data to SMM. @@ -852,11 +871,13 @@ OnReadyToBoot ( // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE. // InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT); - + // // Send data to SMM. // SendCommunicateBuffer (0); + + gBS->CloseEvent (Event); } @@ -881,13 +902,86 @@ VariableAddressChangeEvent ( EfiConvertPointer (0x0, (VOID **) &mSmmCommunication); } +/** + This code gets variable payload size. + + @param[out] VariablePayloadSize Output pointer to variable payload size. + + @retval EFI_SUCCESS Get successfully. + @retval Others Get unsuccessfully. + +**/ +EFI_STATUS +EFIAPI +GetVariablePayloadSize ( + OUT UINTN *VariablePayloadSize + ) +{ + EFI_STATUS Status; + SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *SmmGetPayloadSize; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; + UINTN CommSize; + UINT8 *CommBuffer; + + SmmGetPayloadSize = NULL; + CommBuffer = NULL; + + if(VariablePayloadSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + AcquireLockOnlyAtBootTime(&mVariableServicesLock); + + // + // Init the communicate buffer. The buffer data size is: + // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE); + // + CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE); + CommBuffer = AllocateZeroPool (CommSize); + if (CommBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer; + CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid); + SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE); + + SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data; + SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE; + SmmGetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data; + + // + // Send data to SMM. + // + Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize); + ASSERT_EFI_ERROR (Status); + + Status = SmmVariableFunctionHeader->ReturnStatus; + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Get data from SMM. + // + *VariablePayloadSize = SmmGetPayloadSize->VariablePayloadSize; + +Done: + if (CommBuffer != NULL) { + FreePool (CommBuffer); + } + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); + return Status; +} /** Initialize variable service and install Variable Architectural protocol. @param[in] Event Event whose notification function is being invoked. @param[in] Context Pointer to the notification function's context. - + **/ VOID EFIAPI @@ -902,15 +996,15 @@ SmmVariableReady ( if (EFI_ERROR (Status)) { return; } - + Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication); ASSERT_EFI_ERROR (Status); - + // // Allocate memory for variable communicate buffer. // - mVariableBufferPayloadSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) + - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) - sizeof (VARIABLE_HEADER); + Status = GetVariablePayloadSize (&mVariableBufferPayloadSize); + ASSERT_EFI_ERROR (Status); mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize; mVariableBuffer = AllocateRuntimePool (mVariableBufferSize); ASSERT (mVariableBuffer != NULL); @@ -924,13 +1018,13 @@ SmmVariableReady ( gRT->GetNextVariableName = RuntimeServiceGetNextVariableName; gRT->SetVariable = RuntimeServiceSetVariable; gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo; - + // // Install the Variable Architectural Protocol on a new handle. // Status = gBS->InstallProtocolInterface ( &mHandle, - &gEfiVariableArchProtocolGuid, + &gEfiVariableArchProtocolGuid, EFI_NATIVE_INTERFACE, NULL ); @@ -955,6 +1049,8 @@ SmmVariableReady ( NULL ); ASSERT_EFI_ERROR (Status); + + gBS->CloseEvent (Event); } @@ -963,7 +1059,7 @@ SmmVariableReady ( @param[in] Event Event whose notification function is being invoked. @param[in] Context Pointer to the notification function's context. - + **/ VOID EFIAPI @@ -982,26 +1078,28 @@ SmmVariableWriteReady ( if (EFI_ERROR (Status)) { return; } - + Status = gBS->InstallProtocolInterface ( &mHandle, - &gEfiVariableWriteArchProtocolGuid, + &gEfiVariableWriteArchProtocolGuid, EFI_NATIVE_INTERFACE, NULL ); - ASSERT_EFI_ERROR (Status); + ASSERT_EFI_ERROR (Status); + + gBS->CloseEvent (Event); } /** Variable Driver main entry point. The Variable driver places the 4 EFI - runtime services in the EFI System Table and installs arch protocols + runtime services in the EFI System Table and installs arch protocols for variable read and write services being available. It also registers a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. - @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. - + @retval EFI_SUCCESS Variable service successfully initialized. **/ @@ -1024,10 +1122,10 @@ VariableSmmRuntimeInitialize ( // Smm variable service is ready // EfiCreateProtocolNotifyEvent ( - &gEfiSmmVariableProtocolGuid, - TPL_CALLBACK, - SmmVariableReady, - NULL, + &gEfiSmmVariableProtocolGuid, + TPL_CALLBACK, + SmmVariableReady, + NULL, &SmmVariableRegistration ); @@ -1035,10 +1133,10 @@ VariableSmmRuntimeInitialize ( // Smm Non-Volatile variable write service is ready // EfiCreateProtocolNotifyEvent ( - &gSmmVariableWriteGuid, - TPL_CALLBACK, - SmmVariableWriteReady, - NULL, + &gSmmVariableWriteGuid, + TPL_CALLBACK, + SmmVariableWriteReady, + NULL, &SmmVariableWriteRegistration ); @@ -1046,11 +1144,11 @@ VariableSmmRuntimeInitialize ( // Register the event to reclaim variable for OS usage. // EfiCreateEventReadyToBootEx ( - TPL_NOTIFY, - OnReadyToBoot, - NULL, + TPL_NOTIFY, + OnReadyToBoot, + NULL, &OnReadyToBootEvent - ); + ); // // Register the event to inform SMM variable that it is at runtime. @@ -1062,7 +1160,7 @@ VariableSmmRuntimeInitialize ( NULL, &gEfiEventExitBootServicesGuid, &ExitBootServiceEvent - ); + ); // // Register the event to inform SMM variable that it is at runtime for legacy boot. @@ -1086,7 +1184,7 @@ VariableSmmRuntimeInitialize ( &gEfiEventVirtualAddressChangeGuid, &mVirtualAddressChangeEvent ); - + return EFI_SUCCESS; } diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf index a72619e002..82ddb00a19 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf @@ -1,24 +1,25 @@ ## @file -# This module is the Runtime DXE part correspond to SMM variable module. +# Runtime DXE part corresponding to SMM authenticated variable module. # -# It installs variable arch protocol and variable write arch protocol to provide -# four EFI_RUNTIME_SERVICES: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo -# and works with SMM variable module together. +# This module installs variable arch protocol and variable write arch protocol to provide +# variable service. This module need work together with SMM authenticated variable module. # # Caution: This module requires additional review when modified. # This driver will have external input - variable data. # This external input must be validated carefully to avoid security issues such as # buffer overflow or integer overflow. +# The whole SMM authentication variable design relies on the integrity of flash part and SMM. +# which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory +# 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 - 2015, Intel Corporation. All rights reserved.
-# -# This program and the accompanying materials -# are licensed and made available under the terms and conditions of the BSD License -# which accompanies this distribution. The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. # ## @@ -41,6 +42,7 @@ [Sources] VariableSmmRuntimeDxe.c + Measurement.c [Packages] MdePkg/MdePkg.dec @@ -48,13 +50,13 @@ [LibraryClasses] MemoryAllocationLib - BaseLib + BaseLib UefiBootServicesTableLib DebugLib UefiRuntimeLib DxeServicesTableLib UefiDriverEntryPoint - PcdLib + TpmMeasurementLib [Protocols] gEfiVariableWriteArchProtocolGuid ## PRODUCES @@ -74,10 +76,15 @@ ## CONSUMES ## GUID # Protocol notify gSmmVariableWriteGuid -[Pcd] - gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize ## CONSUMES - gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize ## CONSUMES - + ## SOMETIMES_CONSUMES ## Variable:L"PK" + ## SOMETIMES_CONSUMES ## Variable:L"KEK" + ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot" + gEfiGlobalVariableGuid + + ## SOMETIMES_CONSUMES ## Variable:L"DB" + ## SOMETIMES_CONSUMES ## Variable:L"DBX" + gEfiImageSecurityDatabaseGuid + [Depex] gEfiSmmCommunicationProtocolGuid -- 2.39.2