305 lines
9.4 KiB
C
305 lines
9.4 KiB
C
/** @file
|
|
Provide support functions for variable lock service.
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2014 - 2021, Insyde Software Corp. 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 "VariableLock.h"
|
|
#include "VariablePolicy.h"
|
|
///
|
|
/// The list to store the variables which cannot be set after the EFI_END_OF_DXE_EVENT_GROUP_GUID
|
|
/// or EVT_GROUP_READY_TO_BOOT event.
|
|
///
|
|
LIST_ENTRY mLockedVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mLockedVariableList);
|
|
BOOLEAN mEnableLocking = TRUE;
|
|
|
|
/**
|
|
Acquires lock only at boot time. Simply returns at runtime.
|
|
|
|
This is a temperary function that will be removed when
|
|
EfiAcquireLock() in UefiLib can handle the call in UEFI
|
|
Runtimer driver in RT phase.
|
|
It calls EfiAcquireLock() at boot time, and simply returns
|
|
at runtime.
|
|
|
|
@param[in] Lock A pointer to the lock to acquire.
|
|
|
|
**/
|
|
VOID
|
|
AcquireLockOnlyAtBootTime (
|
|
IN EFI_LOCK *Lock
|
|
)
|
|
{
|
|
if (mSmst == NULL && !VariableAtRuntime ()) {
|
|
EfiAcquireLock (Lock);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Releases lock only at boot time. Simply returns at runtime.
|
|
|
|
This is a temperary function which will be removed when
|
|
EfiReleaseLock() in UefiLib can handle the call in UEFI
|
|
Runtimer driver in RT phase.
|
|
It calls EfiReleaseLock() at boot time and simply returns
|
|
at runtime.
|
|
|
|
@param[in] Lock A pointer to the lock to release.
|
|
|
|
**/
|
|
VOID
|
|
ReleaseLockOnlyAtBootTime (
|
|
IN EFI_LOCK *Lock
|
|
)
|
|
{
|
|
if (mSmst == NULL && !VariableAtRuntime ()) {
|
|
EfiReleaseLock (Lock);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Internal function to check this variable is whether in variable lock list
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
|
|
@retval TRUE This variable is in variable lock list.
|
|
@retval FALSE This variable isn't in variable lock list.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsVariableInLockList (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
VARIABLE_ENTRY *Entry;
|
|
CHAR16 *Name;
|
|
|
|
for ( Link = GetFirstNode (&mLockedVariableList)
|
|
; !IsNull (&mLockedVariableList, Link)
|
|
; Link = GetNextNode (&mLockedVariableList, Link)
|
|
) {
|
|
Entry = BASE_CR (Link, VARIABLE_ENTRY, Link);
|
|
Name = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));
|
|
if (CompareGuid (&Entry->Guid, VendorGuid) && (StrCmp (Name, VariableName) == 0)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
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.
|
|
|
|
@retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
|
|
as pending to be read-only.
|
|
@retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
|
|
Or VariableName is an empty string.
|
|
@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 to hold the lock request.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
VariableLockRequestToLock (
|
|
IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VARIABLE_POLICY_ENTRY *NewPolicy;
|
|
|
|
DEBUG ((DEBUG_WARN, "!!! DEPRECATED INTERFACE !!! %a() will go away soon!\n", __FUNCTION__));
|
|
DEBUG ((DEBUG_WARN, "!!! DEPRECATED INTERFACE !!! Please move to use Variable Policy!\n"));
|
|
DEBUG ((DEBUG_WARN, "!!! DEPRECATED INTERFACE !!! Variable: %g %s\n", VendorGuid, VariableName));
|
|
|
|
NewPolicy = NULL;
|
|
Status = CreateBasicVariablePolicy( VendorGuid,
|
|
VariableName,
|
|
VARIABLE_POLICY_NO_MIN_SIZE,
|
|
VARIABLE_POLICY_NO_MAX_SIZE,
|
|
VARIABLE_POLICY_NO_MUST_ATTR,
|
|
VARIABLE_POLICY_NO_CANT_ATTR,
|
|
VARIABLE_POLICY_TYPE_LOCK_NOW,
|
|
&NewPolicy );
|
|
if (!EFI_ERROR( Status )) {
|
|
Status = ProtocolRegisterVariablePolicy ( NewPolicy );
|
|
//
|
|
// If the error returned is EFI_ALREADY_STARTED, we need to check the
|
|
// current database for the variable and see whether it's locked. If it's
|
|
// locked, we're still fine, but also generate a DEBUG_WARN message so the
|
|
// duplicate lock can be removed.
|
|
//
|
|
if (Status == EFI_ALREADY_STARTED) {
|
|
Status = ValidateSetVariable (VariableName, VendorGuid, 0, 0, NULL);
|
|
if (Status == EFI_WRITE_PROTECTED) {
|
|
DEBUG ((DEBUG_WARN, " Variable: %g %s is already locked!\n", VendorGuid, VariableName));
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
DEBUG ((DEBUG_WARN, " Variable: %g %s is already locked!\n", VendorGuid, VariableName));
|
|
Status = EFI_ACCESS_DENIED;
|
|
}
|
|
}
|
|
}
|
|
if (EFI_ERROR( Status )) {
|
|
ASSERT_EFI_ERROR( Status );
|
|
}
|
|
if (NewPolicy != NULL) {
|
|
FreePool( NewPolicy );
|
|
}
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
Convert all of variables in variable list to virtual address.
|
|
**/
|
|
VOID
|
|
ConvertVariableLockList (
|
|
VOID
|
|
)
|
|
{
|
|
ConvertList (&mLockedVariableList);
|
|
}
|
|
|
|
/**
|
|
Internal function to check this variable is whether locked.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
|
|
@retval TRUE This variable is locked.
|
|
@retval FALSE This variable isn't locked.
|
|
**/
|
|
BOOLEAN
|
|
IsVariableLocked (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid
|
|
)
|
|
{
|
|
if (mSmst == NULL) {
|
|
if (mVariableModuleGlobal->EndOfDxe && mEnableLocking && IsVariableInLockList (VariableName, VendorGuid)) {
|
|
return TRUE;
|
|
}
|
|
} else {
|
|
if (mSmmVariableGlobal->ProtectedModeVariableModuleGlobal->EndOfDxe && mEnableLocking && IsVariableInLockList (VariableName, VendorGuid)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Create variable lock list in SMM RAM.
|
|
|
|
@param[in] ListHead Head of linked list from protected mode.
|
|
|
|
@retval EFI_SUCCESS Create variable lock list in SMM RAM successfully.
|
|
@retval EFI_UNSUPPORTED System isn't in SMM mode.
|
|
@retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the variable entry.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
CreateVariableLockListInSmm (
|
|
LIST_ENTRY *ListHead
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
VARIABLE_ENTRY *Entry;
|
|
UINTN EntrySize;
|
|
VARIABLE_ENTRY *WorkingEntry;
|
|
CHAR16 *Name;
|
|
|
|
if (mSmst == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// in the list of locked variables, convert the name pointers first
|
|
//
|
|
for ( Link = GetFirstNode (ListHead)
|
|
; !IsNull (ListHead, Link)
|
|
; Link = GetNextNode (ListHead, Link)
|
|
) {
|
|
Entry = BASE_CR (Link, VARIABLE_ENTRY, Link);
|
|
Name = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));
|
|
EntrySize = sizeof (VARIABLE_ENTRY) + StrSize (Name);
|
|
WorkingEntry = VariableAllocateZeroBuffer (EntrySize, TRUE);
|
|
ASSERT (WorkingEntry != NULL);
|
|
if (WorkingEntry == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
CopyMem (WorkingEntry, Entry, EntrySize);
|
|
InsertTailList (&mLockedVariableList, &WorkingEntry->Link);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
This function uses to send SMI to create variable lock list in SMM mode.
|
|
**/
|
|
VOID
|
|
CreateVariableLockListThroughSmi (
|
|
VOID
|
|
)
|
|
{
|
|
LIST_ENTRY *ListHead;
|
|
|
|
if (mVariableModuleGlobal->SmmCodeReady && mSmst == NULL) {
|
|
InitCommunicationBufferHeader ();
|
|
mVariableModuleGlobal->SmmVarBuf->Signature = SMM_VARIABLE_LOCK_SIGNATURE;
|
|
mVariableModuleGlobal->SmmVarBuf->AccessType = SMM_VARIABLE_LOCK_FUN_NUM;
|
|
mVariableModuleGlobal->SmmVarBuf->DataSize = sizeof (LIST_ENTRY *);
|
|
ListHead = &mLockedVariableList;
|
|
CopyMem (mVariableModuleGlobal->SmmVarBuf + 1, &ListHead, sizeof (LIST_ENTRY *));
|
|
SendCommunicateBuffer ();
|
|
}
|
|
}
|
|
|
|
/**
|
|
This function uses to create variable lock list.
|
|
|
|
@return EFI_SUCCESS Create variable lock list in SMM RAM successfully.
|
|
@return Other Any error occurred while creating variable lock list in SMM RAM.
|
|
**/
|
|
EFI_STATUS
|
|
SmmCreateVariableLockList (
|
|
VOID
|
|
)
|
|
{
|
|
SMM_VAR_BUFFER *VariableBuffer;
|
|
LIST_ENTRY *ListHead;
|
|
STATIC BOOLEAN Initialized = FALSE;
|
|
|
|
if (Initialized) {
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
VariableBuffer = mVariableModuleGlobal->SmmVarBuf;
|
|
if (VariableBuffer->Signature != SMM_VARIABLE_LOCK_SIGNATURE || VariableBuffer->DataSize != sizeof (LIST_ENTRY *)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
Initialized = TRUE;
|
|
ListHead = *((LIST_ENTRY **) (VariableBuffer + 1));
|
|
return CreateVariableLockListInSmm (ListHead);
|
|
}
|