blob: 90cef6e85d270b3351eae5a8c97938dfe6fc4e92 [file] [log] [blame]
/** @file
Var Check PCD handler.
Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Library/VarCheckLib.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DxeServicesLib.h>
#include "VarCheckPcdStructure.h"
// #define DUMP_VAR_CHECK_PCD
GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mVarCheckPcdHex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
/**
Dump some hexadecimal data.
@param[in] Indent How many spaces to indent the output.
@param[in] Offset The offset of the dump.
@param[in] DataSize The size in bytes of UserData.
@param[in] UserData The data to dump.
**/
VOID
VarCheckPcdInternalDumpHex (
IN UINTN Indent,
IN UINTN Offset,
IN UINTN DataSize,
IN VOID *UserData
)
{
UINT8 *Data;
CHAR8 Val[50];
CHAR8 Str[20];
UINT8 TempByte;
UINTN Size;
UINTN Index;
Data = UserData;
while (DataSize != 0) {
Size = 16;
if (Size > DataSize) {
Size = DataSize;
}
for (Index = 0; Index < Size; Index += 1) {
TempByte = Data[Index];
Val[Index * 3 + 0] = mVarCheckPcdHex[TempByte >> 4];
Val[Index * 3 + 1] = mVarCheckPcdHex[TempByte & 0xF];
Val[Index * 3 + 2] = (CHAR8)((Index == 7) ? '-' : ' ');
Str[Index] = (CHAR8)((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
}
Val[Index * 3] = 0;
Str[Index] = 0;
DEBUG ((DEBUG_INFO, "%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str));
Data += Size;
Offset += Size;
DataSize -= Size;
}
}
/**
Var Check Pcd ValidData.
@param[in] PcdValidData Pointer to Pcd ValidData
@param[in] Data Data pointer.
@param[in] DataSize Size of Data to set.
@retval TRUE Check pass
@retval FALSE Check fail.
**/
BOOLEAN
VarCheckPcdValidData (
IN VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData,
IN VOID *Data,
IN UINTN DataSize
)
{
UINT64 OneData;
UINT64 Minimum;
UINT64 Maximum;
UINT64 OneValue;
UINT8 *Ptr;
OneData = 0;
CopyMem (&OneData, (UINT8 *)Data + PcdValidData->VarOffset, PcdValidData->StorageWidth);
switch (PcdValidData->Type) {
case VarCheckPcdValidList:
Ptr = (UINT8 *)((VAR_CHECK_PCD_VALID_LIST *)PcdValidData + 1);
while ((UINTN)Ptr < (UINTN)PcdValidData + PcdValidData->Length) {
OneValue = 0;
CopyMem (&OneValue, Ptr, PcdValidData->StorageWidth);
if (OneData == OneValue) {
//
// Match
//
break;
}
Ptr += PcdValidData->StorageWidth;
}
if ((UINTN)Ptr >= ((UINTN)PcdValidData + PcdValidData->Length)) {
//
// No match
//
DEBUG ((DEBUG_INFO, "VarCheckPcdValidData fail: ValidList mismatch (0x%lx)\n", OneData));
DEBUG_CODE (
VarCheckPcdInternalDumpHex (2, 0, PcdValidData->Length, (UINT8 *)PcdValidData);
);
return FALSE;
}
break;
case VarCheckPcdValidRange:
Minimum = 0;
Maximum = 0;
Ptr = (UINT8 *)((VAR_CHECK_PCD_VALID_RANGE *)PcdValidData + 1);
while ((UINTN)Ptr < (UINTN)PcdValidData + PcdValidData->Length) {
CopyMem (&Minimum, Ptr, PcdValidData->StorageWidth);
Ptr += PcdValidData->StorageWidth;
CopyMem (&Maximum, Ptr, PcdValidData->StorageWidth);
Ptr += PcdValidData->StorageWidth;
if ((OneData >= Minimum) && (OneData <= Maximum)) {
return TRUE;
}
}
DEBUG ((DEBUG_INFO, "VarCheckPcdValidData fail: ValidRange mismatch (0x%lx)\n", OneData));
DEBUG_CODE (
VarCheckPcdInternalDumpHex (2, 0, PcdValidData->Length, (UINT8 *)PcdValidData);
);
return FALSE;
break;
default:
ASSERT (FALSE);
break;
}
return TRUE;
}
VAR_CHECK_PCD_VARIABLE_HEADER *mVarCheckPcdBin = NULL;
UINTN mVarCheckPcdBinSize = 0;
/**
SetVariable check handler PCD.
@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.
@retval EFI_SUCCESS The SetVariable check result was success.
@retval EFI_SECURITY_VIOLATION Check fail.
**/
EFI_STATUS
EFIAPI
SetVariableCheckHandlerPcd (
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
IN UINT32 Attributes,
IN UINTN DataSize,
IN VOID *Data
)
{
VAR_CHECK_PCD_VARIABLE_HEADER *PcdVariable;
VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData;
if (mVarCheckPcdBin == NULL) {
return EFI_SUCCESS;
}
if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
//
// Do not check delete variable.
//
return EFI_SUCCESS;
}
//
// For Pcd Variable header align.
//
PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *)HEADER_ALIGN (mVarCheckPcdBin);
while ((UINTN)PcdVariable < ((UINTN)mVarCheckPcdBin + mVarCheckPcdBinSize)) {
if ((StrCmp ((CHAR16 *)(PcdVariable + 1), VariableName) == 0) &&
(CompareGuid (&PcdVariable->Guid, VendorGuid)))
{
//
// Found the Pcd Variable that could be used to do check.
//
DEBUG ((DEBUG_INFO, "VarCheckPcdVariable - %s:%g with Attributes = 0x%08x Size = 0x%x\n", VariableName, VendorGuid, Attributes, DataSize));
if ((PcdVariable->Attributes != 0) && (PcdVariable->Attributes != Attributes)) {
DEBUG ((DEBUG_INFO, "VarCheckPcdVariable fail for Attributes - 0x%08x\n", PcdVariable->Attributes));
return EFI_SECURITY_VIOLATION;
}
if (DataSize == 0) {
DEBUG ((DEBUG_INFO, "VarCheckPcdVariable - CHECK PASS with DataSize == 0 !\n"));
return EFI_SUCCESS;
}
//
// Do the check.
// For Pcd ValidData header align.
//
PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *)HEADER_ALIGN (((UINTN)PcdVariable + PcdVariable->HeaderLength));
while ((UINTN)PcdValidData < ((UINTN)PcdVariable + PcdVariable->Length)) {
if (((UINTN)PcdValidData->VarOffset + PcdValidData->StorageWidth) <= DataSize) {
if (!VarCheckPcdValidData (PcdValidData, Data, DataSize)) {
return EFI_SECURITY_VIOLATION;
}
}
//
// For Pcd ValidData header align.
//
PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *)HEADER_ALIGN (((UINTN)PcdValidData + PcdValidData->Length));
}
DEBUG ((DEBUG_INFO, "VarCheckPcdVariable - ALL CHECK PASS!\n"));
return EFI_SUCCESS;
}
//
// For Pcd Variable header align.
//
PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *)HEADER_ALIGN (((UINTN)PcdVariable + PcdVariable->Length));
}
// Not found, so pass.
return EFI_SUCCESS;
}
#ifdef DUMP_VAR_CHECK_PCD
/**
Dump Pcd ValidData.
@param[in] PcdValidData Pointer to Pcd ValidData.
**/
VOID
DumpPcdValidData (
IN VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData
)
{
UINT64 Minimum;
UINT64 Maximum;
UINT64 OneValue;
UINT8 *Ptr;
DEBUG ((DEBUG_INFO, " VAR_CHECK_PCD_VALID_DATA_HEADER\n"));
DEBUG ((DEBUG_INFO, " Type - 0x%02x\n", PcdValidData->Type));
DEBUG ((DEBUG_INFO, " Length - 0x%02x\n", PcdValidData->Length));
DEBUG ((DEBUG_INFO, " VarOffset - 0x%04x\n", PcdValidData->VarOffset));
DEBUG ((DEBUG_INFO, " StorageWidth - 0x%02x\n", PcdValidData->StorageWidth));
switch (PcdValidData->Type) {
case VarCheckPcdValidList:
Ptr = (UINT8 *)((VAR_CHECK_PCD_VALID_LIST *)PcdValidData + 1);
while ((UINTN)Ptr < ((UINTN)PcdValidData + PcdValidData->Length)) {
OneValue = 0;
CopyMem (&OneValue, Ptr, PcdValidData->StorageWidth);
switch (PcdValidData->StorageWidth) {
case sizeof (UINT8):
DEBUG ((DEBUG_INFO, " ValidList - 0x%02x\n", OneValue));
break;
case sizeof (UINT16):
DEBUG ((DEBUG_INFO, " ValidList - 0x%04x\n", OneValue));
break;
case sizeof (UINT32):
DEBUG ((DEBUG_INFO, " ValidList - 0x%08x\n", OneValue));
break;
case sizeof (UINT64):
DEBUG ((DEBUG_INFO, " ValidList - 0x%016lx\n", OneValue));
break;
default:
ASSERT (FALSE);
break;
}
Ptr += PcdValidData->StorageWidth;
}
break;
case VarCheckPcdValidRange:
Minimum = 0;
Maximum = 0;
Ptr = (UINT8 *)((VAR_CHECK_PCD_VALID_RANGE *)PcdValidData + 1);
while ((UINTN)Ptr < (UINTN)PcdValidData + PcdValidData->Length) {
CopyMem (&Minimum, Ptr, PcdValidData->StorageWidth);
Ptr += PcdValidData->StorageWidth;
CopyMem (&Maximum, Ptr, PcdValidData->StorageWidth);
Ptr += PcdValidData->StorageWidth;
switch (PcdValidData->StorageWidth) {
case sizeof (UINT8):
DEBUG ((DEBUG_INFO, " Minimum - 0x%02x\n", Minimum));
DEBUG ((DEBUG_INFO, " Maximum - 0x%02x\n", Maximum));
break;
case sizeof (UINT16):
DEBUG ((DEBUG_INFO, " Minimum - 0x%04x\n", Minimum));
DEBUG ((DEBUG_INFO, " Maximum - 0x%04x\n", Maximum));
break;
case sizeof (UINT32):
DEBUG ((DEBUG_INFO, " Minimum - 0x%08x\n", Minimum));
DEBUG ((DEBUG_INFO, " Maximum - 0x%08x\n", Maximum));
break;
case sizeof (UINT64):
DEBUG ((DEBUG_INFO, " Minimum - 0x%016lx\n", Minimum));
DEBUG ((DEBUG_INFO, " Maximum - 0x%016lx\n", Maximum));
break;
default:
ASSERT (FALSE);
break;
}
}
break;
default:
ASSERT (FALSE);
break;
}
}
/**
Dump Pcd Variable.
@param[in] PcdVariable Pointer to Pcd Variable.
**/
VOID
DumpPcdVariable (
IN VAR_CHECK_PCD_VARIABLE_HEADER *PcdVariable
)
{
VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData;
DEBUG ((DEBUG_INFO, "VAR_CHECK_PCD_VARIABLE_HEADER\n"));
DEBUG ((DEBUG_INFO, " Revision - 0x%04x\n", PcdVariable->Revision));
DEBUG ((DEBUG_INFO, " HeaderLength - 0x%04x\n", PcdVariable->HeaderLength));
DEBUG ((DEBUG_INFO, " Length - 0x%08x\n", PcdVariable->Length));
DEBUG ((DEBUG_INFO, " Type - 0x%02x\n", PcdVariable->Type));
DEBUG ((DEBUG_INFO, " Attributes - 0x%08x\n", PcdVariable->Attributes));
DEBUG ((DEBUG_INFO, " Guid - %g\n", &PcdVariable->Guid));
DEBUG ((DEBUG_INFO, " Name - %s\n", PcdVariable + 1));
//
// For Pcd ValidData header align.
//
PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *)HEADER_ALIGN (((UINTN)PcdVariable + PcdVariable->HeaderLength));
while ((UINTN)PcdValidData < ((UINTN)PcdVariable + PcdVariable->Length)) {
//
// Dump Pcd ValidData related to the Pcd Variable.
//
DumpPcdValidData (PcdValidData);
//
// For Pcd ValidData header align.
//
PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *)HEADER_ALIGN (((UINTN)PcdValidData + PcdValidData->Length));
}
}
/**
Dump Var Check PCD.
@param[in] VarCheckPcdBin Pointer to VarCheckPcdBin.
@param[in] VarCheckPcdBinSize VarCheckPcdBin size.
**/
VOID
DumpVarCheckPcd (
IN VOID *VarCheckPcdBin,
IN UINTN VarCheckPcdBinSize
)
{
VAR_CHECK_PCD_VARIABLE_HEADER *PcdVariable;
DEBUG ((DEBUG_INFO, "DumpVarCheckPcd\n"));
//
// For Pcd Variable header align.
//
PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *)HEADER_ALIGN (VarCheckPcdBin);
while ((UINTN)PcdVariable < ((UINTN)VarCheckPcdBin + VarCheckPcdBinSize)) {
DumpPcdVariable (PcdVariable);
//
// For Pcd Variable header align.
//
PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *)HEADER_ALIGN (((UINTN)PcdVariable + PcdVariable->Length));
}
}
#endif
/**
Locate VarCheckPcdBin.
**/
VOID
EFIAPI
LocateVarCheckPcdBin (
VOID
)
{
EFI_STATUS Status;
VAR_CHECK_PCD_VARIABLE_HEADER *VarCheckPcdBin;
UINTN VarCheckPcdBinSize;
//
// Search the VarCheckPcdBin from the first RAW section of current FFS.
//
Status = GetSectionFromFfs (
EFI_SECTION_RAW,
0,
(VOID **)&VarCheckPcdBin,
&VarCheckPcdBinSize
);
if (!EFI_ERROR (Status)) {
//
// AllocateRuntimeZeroPool () from MemoryAllocateLib is used for runtime access
// in SetVariable check handler.
//
mVarCheckPcdBin = AllocateRuntimeCopyPool (VarCheckPcdBinSize, VarCheckPcdBin);
ASSERT (mVarCheckPcdBin != NULL);
//
// Make sure the allocated buffer for VarCheckPcdBin at required alignment.
//
ASSERT ((((UINTN)mVarCheckPcdBin) & (HEADER_ALIGNMENT - 1)) == 0);
mVarCheckPcdBinSize = VarCheckPcdBinSize;
FreePool (VarCheckPcdBin);
DEBUG ((DEBUG_INFO, "VarCheckPcdBin - at 0x%x size = 0x%x\n", mVarCheckPcdBin, mVarCheckPcdBinSize));
#ifdef DUMP_VAR_CHECK_PCD
DEBUG_CODE (
DumpVarCheckPcd (mVarCheckPcdBin, mVarCheckPcdBinSize);
);
#endif
} else {
DEBUG ((DEBUG_INFO, "[VarCheckPcd] No VarCheckPcdBin found at the first RAW section\n"));
}
}
/**
Constructor function of VarCheckPcdLib to register var check PCD handler.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The constructor executed correctly.
**/
EFI_STATUS
EFIAPI
VarCheckPcdLibNullClassConstructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
LocateVarCheckPcdBin ();
VarCheckLibRegisterAddressPointer ((VOID **)&mVarCheckPcdBin);
VarCheckLibRegisterSetVariableCheckHandler (SetVariableCheckHandlerPcd);
return EFI_SUCCESS;
}