diff options
| author | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
|---|---|---|
| committer | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
| commit | 7e2ccccace24636f29ddc210b94606abd4c7e42b (patch) | |
| tree | 545d43ea12671048956cafeb12303e84d601e571 /MdeModulePkg/Library/VarCheckLib/VarCheckLib.c | |
| parent | 27b044605cd5f6b33a3d231576003850b3fe305b (diff) | |
| download | edk2-trunk.tar.xz | |
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'MdeModulePkg/Library/VarCheckLib/VarCheckLib.c')
| -rw-r--r-- | MdeModulePkg/Library/VarCheckLib/VarCheckLib.c | 1360 |
1 files changed, 680 insertions, 680 deletions
diff --git a/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c b/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c index 87afe03414..0fed8a6131 100644 --- a/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c +++ b/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c @@ -1,680 +1,680 @@ -/** @file
- Implementation functions and structures for var check services.
-
-Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <Library/VarCheckLib.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/DebugLib.h>
-#include <Library/MemoryAllocationLib.h>
-
-#include <Guid/GlobalVariable.h>
-#include <Guid/HardwareErrorVariable.h>
-
-BOOLEAN mVarCheckLibEndOfDxe = FALSE;
-
-#define VAR_CHECK_TABLE_SIZE 0x8
-
-UINTN mVarCheckLibEndOfDxeCallbackCount = 0;
-UINTN mVarCheckLibEndOfDxeCallbackMaxCount = 0;
-VAR_CHECK_END_OF_DXE_CALLBACK *mVarCheckLibEndOfDxeCallback = NULL;
-
-UINTN mVarCheckLibAddressPointerCount = 0;
-UINTN mVarCheckLibAddressPointerMaxCount = 0;
-VOID ***mVarCheckLibAddressPointer = NULL;
-
-UINTN mNumberOfVarCheckHandler = 0;
-UINTN mMaxNumberOfVarCheckHandler = 0;
-VAR_CHECK_SET_VARIABLE_CHECK_HANDLER *mVarCheckHandlerTable = NULL;
-
-typedef struct {
- EFI_GUID Guid;
- VAR_CHECK_VARIABLE_PROPERTY VariableProperty;
- // CHAR16 *Name;
-} VAR_CHECK_VARIABLE_ENTRY;
-
-UINTN mNumberOfVarCheckVariable = 0;
-UINTN mMaxNumberOfVarCheckVariable = 0;
-VARIABLE_ENTRY_PROPERTY **mVarCheckVariableTable = NULL;
-
-//
-// Handle variables with wildcard name specially.
-//
-VARIABLE_ENTRY_PROPERTY mVarCheckVariableWithWildcardName[] = {
- {
- &gEfiGlobalVariableGuid,
- L"Boot####",
- {
- 0
- },
- },
- {
- &gEfiGlobalVariableGuid,
- L"Driver####",
- {
- 0
- },
- },
- {
- &gEfiGlobalVariableGuid,
- L"SysPrep####",
- {
- 0
- },
- },
- {
- &gEfiGlobalVariableGuid,
- L"Key####",
- {
- 0
- },
- },
- {
- &gEfiGlobalVariableGuid,
- L"PlatformRecovery####",
- {
- 0
- },
- },
- {
- &gEfiHardwareErrorVariableGuid,
- L"HwErrRec####",
- {
- 0
- },
- },
-};
-
-/**
- Check if a Unicode character is an upper case hexadecimal character.
-
- This function checks if a Unicode character is an upper case
- hexadecimal character. The valid upper case hexadecimal character is
- L'0' to L'9', or L'A' to L'F'.
-
-
- @param[in] Char The character to check against.
-
- @retval TRUE If the Char is an upper case hexadecmial character.
- @retval FALSE If the Char is not an upper case hexadecmial character.
-
-**/
-BOOLEAN
-EFIAPI
-VarCheckInternalIsHexaDecimalDigitCharacter (
- IN CHAR16 Char
- )
-{
- return (BOOLEAN)((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F'));
-}
-
-/**
- Variable property get with wildcard name.
-
- @param[in] VariableName Pointer to variable name.
- @param[in] VendorGuid Pointer to variable vendor GUID.
- @param[in] WildcardMatch Try wildcard match or not.
-
- @return Pointer to variable property.
-
-**/
-VAR_CHECK_VARIABLE_PROPERTY *
-VariablePropertyGetWithWildcardName (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN BOOLEAN WildcardMatch
- )
-{
- UINTN Index;
- UINTN NameLength;
-
- NameLength = StrLen (VariableName) - 4;
- for (Index = 0; Index < sizeof (mVarCheckVariableWithWildcardName)/sizeof (mVarCheckVariableWithWildcardName[0]); Index++) {
- if (CompareGuid (mVarCheckVariableWithWildcardName[Index].Guid, VendorGuid)) {
- if (WildcardMatch) {
- if ((StrLen (VariableName) == StrLen (mVarCheckVariableWithWildcardName[Index].Name)) &&
- (StrnCmp (VariableName, mVarCheckVariableWithWildcardName[Index].Name, NameLength) == 0) &&
- VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength]) &&
- VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 1]) &&
- VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 2]) &&
- VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 3]))
- {
- return &mVarCheckVariableWithWildcardName[Index].VariableProperty;
- }
- }
-
- if (StrCmp (mVarCheckVariableWithWildcardName[Index].Name, VariableName) == 0) {
- return &mVarCheckVariableWithWildcardName[Index].VariableProperty;
- }
- }
- }
-
- return NULL;
-}
-
-/**
- Variable property get function.
-
- @param[in] Name Pointer to the variable name.
- @param[in] Guid Pointer to the vendor GUID.
- @param[in] WildcardMatch Try wildcard match or not.
-
- @return Pointer to the property of variable specified by the Name and Guid.
-
-**/
-VAR_CHECK_VARIABLE_PROPERTY *
-VariablePropertyGetFunction (
- IN CHAR16 *Name,
- IN EFI_GUID *Guid,
- IN BOOLEAN WildcardMatch
- )
-{
- UINTN Index;
- VAR_CHECK_VARIABLE_ENTRY *Entry;
- CHAR16 *VariableName;
-
- for (Index = 0; Index < mNumberOfVarCheckVariable; Index++) {
- Entry = (VAR_CHECK_VARIABLE_ENTRY *)mVarCheckVariableTable[Index];
- VariableName = (CHAR16 *)((UINTN)Entry + sizeof (*Entry));
- if (CompareGuid (&Entry->Guid, Guid) && (StrCmp (VariableName, Name) == 0)) {
- return &Entry->VariableProperty;
- }
- }
-
- return VariablePropertyGetWithWildcardName (Name, Guid, WildcardMatch);
-}
-
-/**
- Var check add table entry.
-
- @param[in, out] Table Pointer to table buffer.
- @param[in, out] MaxNumber Pointer to maximum number of entry in the table.
- @param[in, out] CurrentNumber Pointer to current number of entry in the table.
- @param[in] Entry Entry will be added to the table.
-
- @retval EFI_SUCCESS Reallocate memory successfully.
- @retval EFI_OUT_OF_RESOURCES No enough memory to allocate.
-
-**/
-EFI_STATUS
-VarCheckAddTableEntry (
- IN OUT UINTN **Table,
- IN OUT UINTN *MaxNumber,
- IN OUT UINTN *CurrentNumber,
- IN UINTN Entry
- )
-{
- UINTN *TempTable;
-
- //
- // Check whether the table is enough to store new entry.
- //
- if (*CurrentNumber == *MaxNumber) {
- //
- // Reallocate memory for the table.
- //
- TempTable = ReallocateRuntimePool (
- *MaxNumber * sizeof (UINTN),
- (*MaxNumber + VAR_CHECK_TABLE_SIZE) * sizeof (UINTN),
- *Table
- );
-
- //
- // No enough resource to allocate.
- //
- if (TempTable == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- *Table = TempTable;
- //
- // Increase max number.
- //
- *MaxNumber += VAR_CHECK_TABLE_SIZE;
- }
-
- //
- // Add entry to the table.
- //
- (*Table)[*CurrentNumber] = Entry;
- (*CurrentNumber)++;
-
- return EFI_SUCCESS;
-}
-
-/**
- Register END_OF_DXE callback.
- The callback will be invoked by VarCheckLibInitializeAtEndOfDxe().
-
- @param[in] Callback END_OF_DXE callback.
-
- @retval EFI_SUCCESS The callback was registered successfully.
- @retval EFI_INVALID_PARAMETER Callback is NULL.
- @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 callback register request.
-
-**/
-EFI_STATUS
-EFIAPI
-VarCheckLibRegisterEndOfDxeCallback (
- IN VAR_CHECK_END_OF_DXE_CALLBACK Callback
- )
-{
- EFI_STATUS Status;
-
- if (Callback == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (mVarCheckLibEndOfDxe) {
- return EFI_ACCESS_DENIED;
- }
-
- Status = VarCheckAddTableEntry (
- (UINTN **)&mVarCheckLibEndOfDxeCallback,
- &mVarCheckLibEndOfDxeCallbackMaxCount,
- &mVarCheckLibEndOfDxeCallbackCount,
- (UINTN)Callback
- );
-
- DEBUG ((DEBUG_INFO, "VarCheckLibRegisterEndOfDxeCallback - 0x%x %r\n", Callback, Status));
-
- return Status;
-}
-
-/**
- Var check initialize at END_OF_DXE.
-
- This function needs to be called at END_OF_DXE.
- Address pointers may be returned,
- and caller needs to ConvertPointer() for the pointers.
-
- @param[in, out] AddressPointerCount Output pointer to address pointer count.
-
- @return Address pointer buffer, NULL if input AddressPointerCount is NULL.
-
-**/
-VOID ***
-EFIAPI
-VarCheckLibInitializeAtEndOfDxe (
- IN OUT UINTN *AddressPointerCount OPTIONAL
- )
-{
- VOID *TempTable;
- UINTN TotalCount;
- UINTN Index;
-
- for (Index = 0; Index < mVarCheckLibEndOfDxeCallbackCount; Index++) {
- //
- // Invoke the callback registered by VarCheckLibRegisterEndOfDxeCallback().
- //
- mVarCheckLibEndOfDxeCallback[Index]();
- }
-
- if (mVarCheckLibEndOfDxeCallback != NULL) {
- //
- // Free the callback buffer.
- //
- mVarCheckLibEndOfDxeCallbackCount = 0;
- mVarCheckLibEndOfDxeCallbackMaxCount = 0;
- FreePool ((VOID *)mVarCheckLibEndOfDxeCallback);
- mVarCheckLibEndOfDxeCallback = NULL;
- }
-
- mVarCheckLibEndOfDxe = TRUE;
-
- if (AddressPointerCount == NULL) {
- if (mVarCheckLibAddressPointer != NULL) {
- //
- // Free the address pointer buffer.
- //
- mVarCheckLibAddressPointerCount = 0;
- mVarCheckLibAddressPointerMaxCount = 0;
- FreePool ((VOID *)mVarCheckLibAddressPointer);
- mVarCheckLibAddressPointer = NULL;
- }
-
- return NULL;
- }
-
- //
- // Get the total count needed.
- // Also cover VarCheckHandler and the entries, and VarCheckVariable and the entries.
- //
- TotalCount = mVarCheckLibAddressPointerCount + (mNumberOfVarCheckHandler + 1) + (mNumberOfVarCheckVariable + 1);
- TempTable = ReallocateRuntimePool (
- mVarCheckLibAddressPointerMaxCount * sizeof (VOID **),
- TotalCount * sizeof (VOID **),
- (VOID *)mVarCheckLibAddressPointer
- );
-
- if (TempTable != NULL) {
- mVarCheckLibAddressPointer = (VOID ***)TempTable;
-
- //
- // Cover VarCheckHandler and the entries.
- //
- mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **)&mVarCheckHandlerTable;
- for (Index = 0; Index < mNumberOfVarCheckHandler; Index++) {
- mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **)&mVarCheckHandlerTable[Index];
- }
-
- //
- // Cover VarCheckVariable and the entries.
- //
- mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **)&mVarCheckVariableTable;
- for (Index = 0; Index < mNumberOfVarCheckVariable; Index++) {
- mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **)&mVarCheckVariableTable[Index];
- }
-
- ASSERT (mVarCheckLibAddressPointerCount == TotalCount);
- mVarCheckLibAddressPointerMaxCount = mVarCheckLibAddressPointerCount;
- }
-
- *AddressPointerCount = mVarCheckLibAddressPointerCount;
- return mVarCheckLibAddressPointer;
-}
-
-/**
- Register address pointer.
- The AddressPointer may be returned by VarCheckLibInitializeAtEndOfDxe().
-
- @param[in] AddressPointer Address pointer.
-
- @retval EFI_SUCCESS The address pointer was registered successfully.
- @retval EFI_INVALID_PARAMETER AddressPointer is NULL.
- @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 address pointer register request.
-
-**/
-EFI_STATUS
-EFIAPI
-VarCheckLibRegisterAddressPointer (
- IN VOID **AddressPointer
- )
-{
- EFI_STATUS Status;
-
- if (AddressPointer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (mVarCheckLibEndOfDxe) {
- return EFI_ACCESS_DENIED;
- }
-
- Status = VarCheckAddTableEntry (
- (UINTN **)&mVarCheckLibAddressPointer,
- &mVarCheckLibAddressPointerMaxCount,
- &mVarCheckLibAddressPointerCount,
- (UINTN)AddressPointer
- );
-
- DEBUG ((DEBUG_INFO, "VarCheckLibRegisterAddressPointer - 0x%x %r\n", AddressPointer, Status));
-
- return Status;
-}
-
-/**
- Register SetVariable check handler.
-
- @param[in] Handler Pointer to check handler.
-
- @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
- @retval EFI_INVALID_PARAMETER Handler is NULL.
- @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 SetVariable check handler register request.
- @retval EFI_UNSUPPORTED This interface is not implemented.
- For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
-
-**/
-EFI_STATUS
-EFIAPI
-VarCheckLibRegisterSetVariableCheckHandler (
- IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
- )
-{
- EFI_STATUS Status;
-
- if (Handler == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (mVarCheckLibEndOfDxe) {
- return EFI_ACCESS_DENIED;
- }
-
- Status = VarCheckAddTableEntry (
- (UINTN **)&mVarCheckHandlerTable,
- &mMaxNumberOfVarCheckHandler,
- &mNumberOfVarCheckHandler,
- (UINTN)Handler
- );
-
- DEBUG ((DEBUG_INFO, "VarCheckLibRegisterSetVariableCheckHandler - 0x%x %r\n", Handler, Status));
-
- return Status;
-}
-
-/**
- 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
-VarCheckLibVariablePropertySet (
- 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;
-
- if ((Name == NULL) || (Name[0] == 0) || (Guid == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (VariableProperty == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (mVarCheckLibEndOfDxe) {
- return EFI_ACCESS_DENIED;
- }
-
- Status = EFI_SUCCESS;
-
- //
- // Get the pointer of property data for set.
- //
- Property = VariablePropertyGetFunction (Name, Guid, FALSE);
- if (Property != NULL) {
- CopyMem (Property, VariableProperty, sizeof (*VariableProperty));
- } else {
- Entry = AllocateRuntimeZeroPool (sizeof (*Entry) + StrSize (Name));
- if (Entry == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- VariableName = (CHAR16 *)((UINTN)Entry + sizeof (*Entry));
- StrCpyS (VariableName, StrSize (Name)/sizeof (CHAR16), Name);
- CopyGuid (&Entry->Guid, Guid);
- CopyMem (&Entry->VariableProperty, VariableProperty, sizeof (*VariableProperty));
-
- Status = VarCheckAddTableEntry (
- (UINTN **)&mVarCheckVariableTable,
- &mMaxNumberOfVarCheckVariable,
- &mNumberOfVarCheckVariable,
- (UINTN)Entry
- );
-
- if (EFI_ERROR (Status)) {
- FreePool (Entry);
- }
- }
-
- return Status;
-}
-
-/**
- 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_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
- @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
-
-**/
-EFI_STATUS
-EFIAPI
-VarCheckLibVariablePropertyGet (
- IN CHAR16 *Name,
- IN EFI_GUID *Guid,
- OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
- )
-{
- VAR_CHECK_VARIABLE_PROPERTY *Property;
-
- if ((Name == NULL) || (Name[0] == 0) || (Guid == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (VariableProperty == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- Property = VariablePropertyGetFunction (Name, Guid, TRUE);
- //
- // Also check the property revision before using the property data.
- // There is no property set to this variable(wildcard name)
- // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION.
- //
- if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) {
- CopyMem (VariableProperty, Property, sizeof (*VariableProperty));
- return EFI_SUCCESS;
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- SetVariable check.
-
- @param[in] VariableName Name of Variable to set.
- @param[in] VendorGuid Variable vendor GUID.
- @param[in] Attributes Attribute value of the variable.
- @param[in] DataSize Size of Data to set.
- @param[in] Data Data pointer.
- @param[in] RequestSource Request source.
-
- @retval EFI_SUCCESS The SetVariable check result was success.
- @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, GUID,
- DataSize and Data value was supplied.
- @retval EFI_WRITE_PROTECTED The variable in question is read-only.
- @retval Others The other return status from check handler.
-
-**/
-EFI_STATUS
-EFIAPI
-VarCheckLibSetVariableCheck (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN UINT32 Attributes,
- IN UINTN DataSize,
- IN VOID *Data,
- IN VAR_CHECK_REQUEST_SOURCE RequestSource
- )
-{
- EFI_STATUS Status;
- UINTN Index;
- VAR_CHECK_VARIABLE_PROPERTY *Property;
-
- if (!mVarCheckLibEndOfDxe) {
- //
- // Only do check after End Of Dxe.
- //
- return EFI_SUCCESS;
- }
-
- Property = VariablePropertyGetFunction (VariableName, VendorGuid, TRUE);
- //
- // Also check the property revision before using the property data.
- // There is no property set to this variable(wildcard name)
- // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION.
- //
- if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) {
- if ((RequestSource != VarCheckFromTrusted) && ((Property->Property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) != 0)) {
- DEBUG ((DEBUG_INFO, "Variable Check ReadOnly variable fail %r - %g:%s\n", EFI_WRITE_PROTECTED, VendorGuid, VariableName));
- return EFI_WRITE_PROTECTED;
- }
-
- if (!((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0))) {
- //
- // Not to delete variable.
- //
- if ((Property->Attributes != 0) && ((Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Property->Attributes)) {
- DEBUG ((DEBUG_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 != 0) {
- if ((DataSize < Property->MinSize) || (DataSize > Property->MaxSize)) {
- DEBUG ((DEBUG_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;
- }
- }
- }
- }
-
- for (Index = 0; Index < mNumberOfVarCheckHandler; Index++) {
- Status = mVarCheckHandlerTable[Index](
- VariableName,
- VendorGuid,
- Attributes,
- DataSize,
- Data
- );
- if ((Status == EFI_WRITE_PROTECTED) && (RequestSource == VarCheckFromTrusted)) {
- //
- // If RequestSource is trusted, then allow variable to be set even if it
- // is write protected.
- //
- continue;
- }
-
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_INFO, "Variable Check handler fail %r - %g:%s\n", Status, VendorGuid, VariableName));
- return Status;
- }
- }
-
- return EFI_SUCCESS;
-}
+/** @file + Implementation functions and structures for var check services. + +Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/VarCheckLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> + +#include <Guid/GlobalVariable.h> +#include <Guid/HardwareErrorVariable.h> + +BOOLEAN mVarCheckLibEndOfDxe = FALSE; + +#define VAR_CHECK_TABLE_SIZE 0x8 + +UINTN mVarCheckLibEndOfDxeCallbackCount = 0; +UINTN mVarCheckLibEndOfDxeCallbackMaxCount = 0; +VAR_CHECK_END_OF_DXE_CALLBACK *mVarCheckLibEndOfDxeCallback = NULL; + +UINTN mVarCheckLibAddressPointerCount = 0; +UINTN mVarCheckLibAddressPointerMaxCount = 0; +VOID ***mVarCheckLibAddressPointer = NULL; + +UINTN mNumberOfVarCheckHandler = 0; +UINTN mMaxNumberOfVarCheckHandler = 0; +VAR_CHECK_SET_VARIABLE_CHECK_HANDLER *mVarCheckHandlerTable = NULL; + +typedef struct { + EFI_GUID Guid; + VAR_CHECK_VARIABLE_PROPERTY VariableProperty; + // CHAR16 *Name; +} VAR_CHECK_VARIABLE_ENTRY; + +UINTN mNumberOfVarCheckVariable = 0; +UINTN mMaxNumberOfVarCheckVariable = 0; +VARIABLE_ENTRY_PROPERTY **mVarCheckVariableTable = NULL; + +// +// Handle variables with wildcard name specially. +// +VARIABLE_ENTRY_PROPERTY mVarCheckVariableWithWildcardName[] = { + { + &gEfiGlobalVariableGuid, + L"Boot####", + { + 0 + }, + }, + { + &gEfiGlobalVariableGuid, + L"Driver####", + { + 0 + }, + }, + { + &gEfiGlobalVariableGuid, + L"SysPrep####", + { + 0 + }, + }, + { + &gEfiGlobalVariableGuid, + L"Key####", + { + 0 + }, + }, + { + &gEfiGlobalVariableGuid, + L"PlatformRecovery####", + { + 0 + }, + }, + { + &gEfiHardwareErrorVariableGuid, + L"HwErrRec####", + { + 0 + }, + }, +}; + +/** + Check if a Unicode character is an upper case hexadecimal character. + + This function checks if a Unicode character is an upper case + hexadecimal character. The valid upper case hexadecimal character is + L'0' to L'9', or L'A' to L'F'. + + + @param[in] Char The character to check against. + + @retval TRUE If the Char is an upper case hexadecmial character. + @retval FALSE If the Char is not an upper case hexadecmial character. + +**/ +BOOLEAN +EFIAPI +VarCheckInternalIsHexaDecimalDigitCharacter ( + IN CHAR16 Char + ) +{ + return (BOOLEAN)((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F')); +} + +/** + Variable property get with wildcard name. + + @param[in] VariableName Pointer to variable name. + @param[in] VendorGuid Pointer to variable vendor GUID. + @param[in] WildcardMatch Try wildcard match or not. + + @return Pointer to variable property. + +**/ +VAR_CHECK_VARIABLE_PROPERTY * +VariablePropertyGetWithWildcardName ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN BOOLEAN WildcardMatch + ) +{ + UINTN Index; + UINTN NameLength; + + NameLength = StrLen (VariableName) - 4; + for (Index = 0; Index < sizeof (mVarCheckVariableWithWildcardName)/sizeof (mVarCheckVariableWithWildcardName[0]); Index++) { + if (CompareGuid (mVarCheckVariableWithWildcardName[Index].Guid, VendorGuid)) { + if (WildcardMatch) { + if ((StrLen (VariableName) == StrLen (mVarCheckVariableWithWildcardName[Index].Name)) && + (StrnCmp (VariableName, mVarCheckVariableWithWildcardName[Index].Name, NameLength) == 0) && + VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength]) && + VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 1]) && + VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 2]) && + VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 3])) + { + return &mVarCheckVariableWithWildcardName[Index].VariableProperty; + } + } + + if (StrCmp (mVarCheckVariableWithWildcardName[Index].Name, VariableName) == 0) { + return &mVarCheckVariableWithWildcardName[Index].VariableProperty; + } + } + } + + return NULL; +} + +/** + Variable property get function. + + @param[in] Name Pointer to the variable name. + @param[in] Guid Pointer to the vendor GUID. + @param[in] WildcardMatch Try wildcard match or not. + + @return Pointer to the property of variable specified by the Name and Guid. + +**/ +VAR_CHECK_VARIABLE_PROPERTY * +VariablePropertyGetFunction ( + IN CHAR16 *Name, + IN EFI_GUID *Guid, + IN BOOLEAN WildcardMatch + ) +{ + UINTN Index; + VAR_CHECK_VARIABLE_ENTRY *Entry; + CHAR16 *VariableName; + + for (Index = 0; Index < mNumberOfVarCheckVariable; Index++) { + Entry = (VAR_CHECK_VARIABLE_ENTRY *)mVarCheckVariableTable[Index]; + VariableName = (CHAR16 *)((UINTN)Entry + sizeof (*Entry)); + if (CompareGuid (&Entry->Guid, Guid) && (StrCmp (VariableName, Name) == 0)) { + return &Entry->VariableProperty; + } + } + + return VariablePropertyGetWithWildcardName (Name, Guid, WildcardMatch); +} + +/** + Var check add table entry. + + @param[in, out] Table Pointer to table buffer. + @param[in, out] MaxNumber Pointer to maximum number of entry in the table. + @param[in, out] CurrentNumber Pointer to current number of entry in the table. + @param[in] Entry Entry will be added to the table. + + @retval EFI_SUCCESS Reallocate memory successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to allocate. + +**/ +EFI_STATUS +VarCheckAddTableEntry ( + IN OUT UINTN **Table, + IN OUT UINTN *MaxNumber, + IN OUT UINTN *CurrentNumber, + IN UINTN Entry + ) +{ + UINTN *TempTable; + + // + // Check whether the table is enough to store new entry. + // + if (*CurrentNumber == *MaxNumber) { + // + // Reallocate memory for the table. + // + TempTable = ReallocateRuntimePool ( + *MaxNumber * sizeof (UINTN), + (*MaxNumber + VAR_CHECK_TABLE_SIZE) * sizeof (UINTN), + *Table + ); + + // + // No enough resource to allocate. + // + if (TempTable == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *Table = TempTable; + // + // Increase max number. + // + *MaxNumber += VAR_CHECK_TABLE_SIZE; + } + + // + // Add entry to the table. + // + (*Table)[*CurrentNumber] = Entry; + (*CurrentNumber)++; + + return EFI_SUCCESS; +} + +/** + Register END_OF_DXE callback. + The callback will be invoked by VarCheckLibInitializeAtEndOfDxe(). + + @param[in] Callback END_OF_DXE callback. + + @retval EFI_SUCCESS The callback was registered successfully. + @retval EFI_INVALID_PARAMETER Callback is NULL. + @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 callback register request. + +**/ +EFI_STATUS +EFIAPI +VarCheckLibRegisterEndOfDxeCallback ( + IN VAR_CHECK_END_OF_DXE_CALLBACK Callback + ) +{ + EFI_STATUS Status; + + if (Callback == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (mVarCheckLibEndOfDxe) { + return EFI_ACCESS_DENIED; + } + + Status = VarCheckAddTableEntry ( + (UINTN **)&mVarCheckLibEndOfDxeCallback, + &mVarCheckLibEndOfDxeCallbackMaxCount, + &mVarCheckLibEndOfDxeCallbackCount, + (UINTN)Callback + ); + + DEBUG ((DEBUG_INFO, "VarCheckLibRegisterEndOfDxeCallback - 0x%x %r\n", Callback, Status)); + + return Status; +} + +/** + Var check initialize at END_OF_DXE. + + This function needs to be called at END_OF_DXE. + Address pointers may be returned, + and caller needs to ConvertPointer() for the pointers. + + @param[in, out] AddressPointerCount Output pointer to address pointer count. + + @return Address pointer buffer, NULL if input AddressPointerCount is NULL. + +**/ +VOID *** +EFIAPI +VarCheckLibInitializeAtEndOfDxe ( + IN OUT UINTN *AddressPointerCount OPTIONAL + ) +{ + VOID *TempTable; + UINTN TotalCount; + UINTN Index; + + for (Index = 0; Index < mVarCheckLibEndOfDxeCallbackCount; Index++) { + // + // Invoke the callback registered by VarCheckLibRegisterEndOfDxeCallback(). + // + mVarCheckLibEndOfDxeCallback[Index](); + } + + if (mVarCheckLibEndOfDxeCallback != NULL) { + // + // Free the callback buffer. + // + mVarCheckLibEndOfDxeCallbackCount = 0; + mVarCheckLibEndOfDxeCallbackMaxCount = 0; + FreePool ((VOID *)mVarCheckLibEndOfDxeCallback); + mVarCheckLibEndOfDxeCallback = NULL; + } + + mVarCheckLibEndOfDxe = TRUE; + + if (AddressPointerCount == NULL) { + if (mVarCheckLibAddressPointer != NULL) { + // + // Free the address pointer buffer. + // + mVarCheckLibAddressPointerCount = 0; + mVarCheckLibAddressPointerMaxCount = 0; + FreePool ((VOID *)mVarCheckLibAddressPointer); + mVarCheckLibAddressPointer = NULL; + } + + return NULL; + } + + // + // Get the total count needed. + // Also cover VarCheckHandler and the entries, and VarCheckVariable and the entries. + // + TotalCount = mVarCheckLibAddressPointerCount + (mNumberOfVarCheckHandler + 1) + (mNumberOfVarCheckVariable + 1); + TempTable = ReallocateRuntimePool ( + mVarCheckLibAddressPointerMaxCount * sizeof (VOID **), + TotalCount * sizeof (VOID **), + (VOID *)mVarCheckLibAddressPointer + ); + + if (TempTable != NULL) { + mVarCheckLibAddressPointer = (VOID ***)TempTable; + + // + // Cover VarCheckHandler and the entries. + // + mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **)&mVarCheckHandlerTable; + for (Index = 0; Index < mNumberOfVarCheckHandler; Index++) { + mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **)&mVarCheckHandlerTable[Index]; + } + + // + // Cover VarCheckVariable and the entries. + // + mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **)&mVarCheckVariableTable; + for (Index = 0; Index < mNumberOfVarCheckVariable; Index++) { + mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **)&mVarCheckVariableTable[Index]; + } + + ASSERT (mVarCheckLibAddressPointerCount == TotalCount); + mVarCheckLibAddressPointerMaxCount = mVarCheckLibAddressPointerCount; + } + + *AddressPointerCount = mVarCheckLibAddressPointerCount; + return mVarCheckLibAddressPointer; +} + +/** + Register address pointer. + The AddressPointer may be returned by VarCheckLibInitializeAtEndOfDxe(). + + @param[in] AddressPointer Address pointer. + + @retval EFI_SUCCESS The address pointer was registered successfully. + @retval EFI_INVALID_PARAMETER AddressPointer is NULL. + @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 address pointer register request. + +**/ +EFI_STATUS +EFIAPI +VarCheckLibRegisterAddressPointer ( + IN VOID **AddressPointer + ) +{ + EFI_STATUS Status; + + if (AddressPointer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (mVarCheckLibEndOfDxe) { + return EFI_ACCESS_DENIED; + } + + Status = VarCheckAddTableEntry ( + (UINTN **)&mVarCheckLibAddressPointer, + &mVarCheckLibAddressPointerMaxCount, + &mVarCheckLibAddressPointerCount, + (UINTN)AddressPointer + ); + + DEBUG ((DEBUG_INFO, "VarCheckLibRegisterAddressPointer - 0x%x %r\n", AddressPointer, Status)); + + return Status; +} + +/** + Register SetVariable check handler. + + @param[in] Handler Pointer to check handler. + + @retval EFI_SUCCESS The SetVariable check handler was registered successfully. + @retval EFI_INVALID_PARAMETER Handler is NULL. + @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 SetVariable check handler register request. + @retval EFI_UNSUPPORTED This interface is not implemented. + For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present. + +**/ +EFI_STATUS +EFIAPI +VarCheckLibRegisterSetVariableCheckHandler ( + IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler + ) +{ + EFI_STATUS Status; + + if (Handler == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (mVarCheckLibEndOfDxe) { + return EFI_ACCESS_DENIED; + } + + Status = VarCheckAddTableEntry ( + (UINTN **)&mVarCheckHandlerTable, + &mMaxNumberOfVarCheckHandler, + &mNumberOfVarCheckHandler, + (UINTN)Handler + ); + + DEBUG ((DEBUG_INFO, "VarCheckLibRegisterSetVariableCheckHandler - 0x%x %r\n", Handler, Status)); + + return Status; +} + +/** + 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 +VarCheckLibVariablePropertySet ( + 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; + + if ((Name == NULL) || (Name[0] == 0) || (Guid == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (VariableProperty == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) { + return EFI_INVALID_PARAMETER; + } + + if (mVarCheckLibEndOfDxe) { + return EFI_ACCESS_DENIED; + } + + Status = EFI_SUCCESS; + + // + // Get the pointer of property data for set. + // + Property = VariablePropertyGetFunction (Name, Guid, FALSE); + if (Property != NULL) { + CopyMem (Property, VariableProperty, sizeof (*VariableProperty)); + } else { + Entry = AllocateRuntimeZeroPool (sizeof (*Entry) + StrSize (Name)); + if (Entry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + VariableName = (CHAR16 *)((UINTN)Entry + sizeof (*Entry)); + StrCpyS (VariableName, StrSize (Name)/sizeof (CHAR16), Name); + CopyGuid (&Entry->Guid, Guid); + CopyMem (&Entry->VariableProperty, VariableProperty, sizeof (*VariableProperty)); + + Status = VarCheckAddTableEntry ( + (UINTN **)&mVarCheckVariableTable, + &mMaxNumberOfVarCheckVariable, + &mNumberOfVarCheckVariable, + (UINTN)Entry + ); + + if (EFI_ERROR (Status)) { + FreePool (Entry); + } + } + + return Status; +} + +/** + 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_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string. + @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found. + +**/ +EFI_STATUS +EFIAPI +VarCheckLibVariablePropertyGet ( + IN CHAR16 *Name, + IN EFI_GUID *Guid, + OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty + ) +{ + VAR_CHECK_VARIABLE_PROPERTY *Property; + + if ((Name == NULL) || (Name[0] == 0) || (Guid == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (VariableProperty == NULL) { + return EFI_INVALID_PARAMETER; + } + + Property = VariablePropertyGetFunction (Name, Guid, TRUE); + // + // Also check the property revision before using the property data. + // There is no property set to this variable(wildcard name) + // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION. + // + if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) { + CopyMem (VariableProperty, Property, sizeof (*VariableProperty)); + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +/** + SetVariable check. + + @param[in] VariableName Name of Variable to set. + @param[in] VendorGuid Variable vendor GUID. + @param[in] Attributes Attribute value of the variable. + @param[in] DataSize Size of Data to set. + @param[in] Data Data pointer. + @param[in] RequestSource Request source. + + @retval EFI_SUCCESS The SetVariable check result was success. + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, GUID, + DataSize and Data value was supplied. + @retval EFI_WRITE_PROTECTED The variable in question is read-only. + @retval Others The other return status from check handler. + +**/ +EFI_STATUS +EFIAPI +VarCheckLibSetVariableCheck ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data, + IN VAR_CHECK_REQUEST_SOURCE RequestSource + ) +{ + EFI_STATUS Status; + UINTN Index; + VAR_CHECK_VARIABLE_PROPERTY *Property; + + if (!mVarCheckLibEndOfDxe) { + // + // Only do check after End Of Dxe. + // + return EFI_SUCCESS; + } + + Property = VariablePropertyGetFunction (VariableName, VendorGuid, TRUE); + // + // Also check the property revision before using the property data. + // There is no property set to this variable(wildcard name) + // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION. + // + if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) { + if ((RequestSource != VarCheckFromTrusted) && ((Property->Property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) != 0)) { + DEBUG ((DEBUG_INFO, "Variable Check ReadOnly variable fail %r - %g:%s\n", EFI_WRITE_PROTECTED, VendorGuid, VariableName)); + return EFI_WRITE_PROTECTED; + } + + if (!((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0))) { + // + // Not to delete variable. + // + if ((Property->Attributes != 0) && ((Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Property->Attributes)) { + DEBUG ((DEBUG_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 != 0) { + if ((DataSize < Property->MinSize) || (DataSize > Property->MaxSize)) { + DEBUG ((DEBUG_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; + } + } + } + } + + for (Index = 0; Index < mNumberOfVarCheckHandler; Index++) { + Status = mVarCheckHandlerTable[Index]( + VariableName, + VendorGuid, + Attributes, + DataSize, + Data + ); + if ((Status == EFI_WRITE_PROTECTED) && (RequestSource == VarCheckFromTrusted)) { + // + // If RequestSource is trusted, then allow variable to be set even if it + // is write protected. + // + continue; + } + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "Variable Check handler fail %r - %g:%s\n", Status, VendorGuid, VariableName)); + return Status; + } + } + + return EFI_SUCCESS; +} |
