diff --git a/MdeModulePkg/Include/Library/VarCheckLib.h b/MdeModulePkg/Include/Library/VarCheckLib.h new file mode 100644 index 0000000000..a423bc0e54 --- /dev/null +++ b/MdeModulePkg/Include/Library/VarCheckLib.h @@ -0,0 +1,180 @@ +/** @file + Provides variable check services and database management. + +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 that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _VARIABLE_CHECK_LIB_H_ +#define _VARIABLE_CHECK_LIB_H_ + +#include + +typedef enum { + VarCheckRequestReserved0 = 0, + VarCheckRequestReserved1 = 1, + VarCheckFromTrusted = 2, + VarCheckFromUntrusted = 3, +} VAR_CHECK_REQUEST_SOURCE; + +typedef +VOID +(EFIAPI *VAR_CHECK_END_OF_DXE_CALLBACK) ( + VOID + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +#endif diff --git a/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c b/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c new file mode 100644 index 0000000000..cf001547a5 --- /dev/null +++ b/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c @@ -0,0 +1,650 @@ +/** @file + Implementation functions and structures for var check 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 +#include +#include +#include +#include + +#include +#include + +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 + }, + }, + { + &gEfiHardwareErrorVariableGuid, + L"HwErrRec####", + { + 0 + }, + }, +}; + +/** + 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 + L'0' to L'9', L'a' to L'f', or L'A' to L'F'. + + + @param[in] Char The character to check against. + + @retval TRUE If the Char is a hexadecmial character. + @retval FALSE If the Char is not a hexadecmial character. + +**/ +BOOLEAN +EFIAPI +VarCheckInternalIsHexaDecimalDigitCharacter ( + IN CHAR16 Char + ) +{ + return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_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; + + 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); + if (Property != NULL) { + 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); + if (Property != NULL) { + if ((RequestSource != VarCheckFromTrusted) && ((Property->Property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) != 0)) { + DEBUG ((EFI_D_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 ((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 != 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; + } + } + } + } + + for (Index = 0; Index < mNumberOfVarCheckHandler; Index++) { + Status = mVarCheckHandlerTable[Index] ( + VariableName, + VendorGuid, + Attributes, + DataSize, + Data + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "Variable Check handler fail %r - %g:%s\n", Status, VendorGuid, VariableName)); + return Status; + } + } + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf b/MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf new file mode 100644 index 0000000000..099f83dd6a --- /dev/null +++ b/MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf @@ -0,0 +1,51 @@ +## @file +# Provides variable check services and database management. +# +# 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = VarCheckLib + MODULE_UNI_FILE = VarCheckLib.uni + FILE_GUID = 63E12D08-0C5D-47F8-95E4-09F89D7506C5 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = VarCheckLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + VarCheckLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + +[Guids] + ## SOMETIMES_CONSUMES ## Variable:L"Boot####" + ## SOMETIMES_CONSUMES ## Variable:L"Driver####" + ## SOMETIMES_CONSUMES ## Variable:L"SysPrep####" + ## SOMETIMES_CONSUMES ## Variable:L"Key####" + gEfiGlobalVariableGuid + gEfiHardwareErrorVariableGuid ## SOMETIMES_CONSUMES ## Variable:L"HwErrRec####" diff --git a/MdeModulePkg/Library/VarCheckLib/VarCheckLib.uni b/MdeModulePkg/Library/VarCheckLib/VarCheckLib.uni new file mode 100644 index 0000000000..d9761a1103 Binary files /dev/null and b/MdeModulePkg/Library/VarCheckLib/VarCheckLib.uni differ diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 9a3f2cdcb4..4cd9c4dd89 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -123,6 +123,10 @@ # AuthVariableLib|Include/Library/AuthVariableLib.h + ## @libraryclass Provides variable check services and database management. + # + VarCheckLib|Include/Library/VarCheckLib.h + [Guids] ## MdeModule package token space guid # Include/Guid/MdeModulePkgTokenSpace.h