318 lines
9.8 KiB
C
318 lines
9.8 KiB
C
/** @file
|
|
Variable Runtime Protection by hooking gRT->SetVariable()
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2014, Insyde Software Corporation. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
#include "VariableRuntimeProtectionDxe.h"
|
|
|
|
EFI_SET_VARIABLE mOrgRuntimeSetVariable = NULL;
|
|
|
|
EFI_L05_PROTECTION_VARIABLE_INFO mVariableProtectionList[] = {
|
|
{
|
|
SYSTEM_CONFIGURATION_GUID, // gSystemConfigurationGuid
|
|
SETUP_VARIABLE_NAME
|
|
},
|
|
//_Start_L05_WIRELESS_DEVICE_SUPPORT_
|
|
{
|
|
EFI_L05WIRELESS_DEVICE_SUPPORT_VARIABLE_GUID, // gL05WirelessDeviceSupportVariableGuid
|
|
L05_WIRELESS_DEVICE_SUPPORT_VARIABLE_NAME_BROADCOM
|
|
},
|
|
{
|
|
EFI_L05WIRELESS_DEVICE_SUPPORT_VARIABLE_GUID, // gL05WirelessDeviceSupportVariableGuid
|
|
L05_WIRELESS_DEVICE_SUPPORT_VARIABLE_NAME_INTEL
|
|
},
|
|
{
|
|
EFI_L05WIRELESS_DEVICE_SUPPORT_VARIABLE_GUID, // gL05WirelessDeviceSupportVariableGuid
|
|
L05_WIRELESS_DEVICE_SUPPORT_VARIABLE_NAME_QUALCOMM
|
|
},
|
|
{
|
|
EFI_L05WIRELESS_DEVICE_SUPPORT_VARIABLE_GUID, // gL05WirelessDeviceSupportVariableGuid
|
|
L05_WIRELESS_DEVICE_SUPPORT_VARIABLE_NAME_REALTEK
|
|
},
|
|
//_End_L05_WIRELESS_DEVICE_SUPPORT_
|
|
{
|
|
EFI_GENERIC_VARIABLE_GUID, // gEfiGenericVariableGuid
|
|
L"PerfDataMemAddr"
|
|
},
|
|
};
|
|
|
|
/**
|
|
Hook function for sets the value of a variable.
|
|
|
|
@param VariableName A Null-terminated string that is the name of the vendor's variable.
|
|
Each VariableName is unique for each VendorGuid. VariableName must
|
|
contain 1 or more characters. If VariableName is an empty string,
|
|
then EFI_INVALID_PARAMETER is returned.
|
|
@param VendorGuid A unique identifier for the vendor.
|
|
@param Attributes Attributes bitmask to set for the variable.
|
|
@param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
|
|
EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or
|
|
EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
|
|
causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
|
|
set, then a SetVariable() call with a DataSize of zero will not cause any change to
|
|
the variable value (the timestamp associated with the variable may be updated however
|
|
even if no new data value is provided,see the description of the
|
|
EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
|
|
be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
|
|
@param Data The contents for the variable.
|
|
|
|
@retval EFI_SECURITY_VIOLATION Find the matched name and GUID of variable
|
|
@retval Others An unexpected error occurred by referring original function gRT->SetVariable()
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetVariableHookFunc (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN UINT32 Attributes,
|
|
IN UINTN DataSize,
|
|
IN VOID *Data
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
|
|
//
|
|
// Check name and GUID of variable which need be avoided to modify in Runtime
|
|
//
|
|
for (Index = 0; Index < sizeof (mVariableProtectionList) / sizeof (EFI_L05_PROTECTION_VARIABLE_INFO); Index++) {
|
|
|
|
if (StrCmp (VariableName, mVariableProtectionList[Index].VariableName) == 0 &&
|
|
CompareGuid (VendorGuid, &(mVariableProtectionList[Index].VariableGuid))) {
|
|
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
}
|
|
|
|
return mOrgRuntimeSetVariable (VariableName, VendorGuid, Attributes, DataSize, Data);
|
|
}
|
|
|
|
/**
|
|
Function for hook gRT->SetVariable()
|
|
|
|
@param Enabled The setting to determine hook gRT->SetVariable() or not
|
|
**/
|
|
VOID
|
|
HookSetVariable (
|
|
BOOLEAN Enabled
|
|
)
|
|
{
|
|
UINT32 Crc32Result;
|
|
BOOLEAN ReCalculateCrc32;
|
|
|
|
Crc32Result = 0;
|
|
ReCalculateCrc32 = FALSE;
|
|
gRT->Hdr.CRC32 = 0;
|
|
|
|
if (Enabled) {
|
|
|
|
//
|
|
// Hook gRT->SetVariable()
|
|
//
|
|
if (mOrgRuntimeSetVariable == NULL) {
|
|
|
|
mOrgRuntimeSetVariable = gRT->SetVariable;
|
|
gRT->SetVariable = SetVariableHookFunc;
|
|
ReCalculateCrc32 = TRUE;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Un-hook gRT->SetVariable()
|
|
//
|
|
if (mOrgRuntimeSetVariable != NULL) {
|
|
|
|
gRT->SetVariable = mOrgRuntimeSetVariable;
|
|
mOrgRuntimeSetVariable = NULL;
|
|
ReCalculateCrc32 = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// ReCalculate a 32-bit CRC to make sure the contents of the EFI System Table are valid.
|
|
//
|
|
if (ReCalculateCrc32) {
|
|
|
|
gBS->CalculateCrc32 ((VOID *) &(gRT->Hdr), gRT->Hdr.HeaderSize, &Crc32Result);
|
|
gRT->Hdr.CRC32 = Crc32Result;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Ready To Boot Envet callback function for enable Variable Runtime Protection
|
|
|
|
@param Event Pointer to this event
|
|
@param Context Event hanlder private data
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
EnableVariableRuntimeProtectionCallBack (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
HookSetVariable (TRUE);
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
Return From Image Envet callback function for disable Variable Runtime Protection
|
|
|
|
@param Event Pointer to this event
|
|
@param Context Event hanlder private data
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
DisableVariableRuntimeProtectionCallBack (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
HookSetVariable (FALSE);
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
|
|
|
|
This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
|
|
It convers pointer to new virtual address.
|
|
|
|
@param Event Event whose notification function is being invoked.
|
|
@param Context Pointer to the notification function's context.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
VirtualAddressChangeNotify (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
//
|
|
// Convert the original function of pointer gRT->SetVariable() if be hooked before
|
|
//
|
|
if (mOrgRuntimeSetVariable != NULL) {
|
|
|
|
gRT->ConvertPointer (0x0, (VOID **) &mOrgRuntimeSetVariable);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
This is the declaration of an EFI image entry point. This entry point is
|
|
the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
|
|
both device drivers and bus drivers.
|
|
|
|
@param ImageHandle The firmware allocated handle for the UEFI image.
|
|
@param SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The operation completed successfully.
|
|
@retval Others An unexpected error occurred.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
VariableRuntimeProtectionDxeDriverEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_EVENT ReadyToBootEvent;
|
|
EFI_EVENT ReturnFromImageEvent;
|
|
VOID *Registration;
|
|
EFI_EVENT VirtualAddressChangeEvent;
|
|
|
|
Status = EFI_SUCCESS;
|
|
ReadyToBootEvent = NULL;
|
|
ReturnFromImageEvent = NULL;
|
|
Registration = NULL;
|
|
VirtualAddressChangeEvent = NULL;
|
|
|
|
//
|
|
// Register Ready To Boot Envet for enable Variable Runtime Protection
|
|
//
|
|
Status = EfiCreateEventReadyToBootEx (
|
|
TPL_NOTIFY,
|
|
EnableVariableRuntimeProtectionCallBack,
|
|
NULL,
|
|
&ReadyToBootEvent
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Register Return From Image Envet for disable Variable Runtime Protection
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
DisableVariableRuntimeProtectionCallBack,
|
|
NULL,
|
|
&ReturnFromImageEvent
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
Status = gBS->RegisterProtocolNotify (
|
|
&gReturnFromImageGuid,
|
|
ReturnFromImageEvent,
|
|
&Registration
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
goto Done;
|
|
}
|
|
|
|
} else {
|
|
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Register the event to convert the pointer for runtime.
|
|
//
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
VirtualAddressChangeNotify,
|
|
NULL,
|
|
&gEfiEventVirtualAddressChangeGuid,
|
|
&VirtualAddressChangeEvent
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
Done:
|
|
|
|
//
|
|
// Close all Events if any error occurred
|
|
//
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
if (ReadyToBootEvent != NULL) gBS->CloseEvent (ReadyToBootEvent);
|
|
|
|
if (ReturnFromImageEvent != NULL) gBS->CloseEvent (ReturnFromImageEvent);
|
|
|
|
if (VirtualAddressChangeEvent != NULL) gBS->CloseEvent (VirtualAddressChangeEvent);
|
|
}
|
|
|
|
return Status;
|
|
}
|