mirror of https://review.coreboot.org/STM.git
1016 lines
31 KiB
C
1016 lines
31 KiB
C
/** @file
|
|
SMI VMCALL handler
|
|
|
|
Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
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 "StmRuntime.h"
|
|
#include "PeStm.h"
|
|
#include "PeLoadVm.h"
|
|
#include "StmInit.h"
|
|
|
|
extern PE_VM_DATA PeVmData[4];
|
|
extern VOID EptDumpPageTable (IN EPT_POINTER *EptPointer );
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallInitializeProtectionHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
DEBUG ((EFI_D_INFO, "STM_API_INITIALIZE_PROTECTION:\n"));
|
|
return ERROR_STM_ALREADY_STARTED;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
|
|
extern VOID CpuReadySync(UINT32 Index);
|
|
|
|
STM_STATUS
|
|
SmiVmcallStartHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
//
|
|
// Let STM enable SMI for SMM guest
|
|
//
|
|
|
|
GUEST_INTERRUPTIBILITY_STATE GuestInterruptibilityState;
|
|
|
|
DEBUG ((EFI_D_INFO, "%ld SmiVmcallStartHandler - STM_API_START:\n", Index));
|
|
if (!mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[Index].Actived) {
|
|
mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[Index].Actived = TRUE;
|
|
SmmSetup (Index);
|
|
|
|
if(Index == 0)
|
|
{
|
|
//EptDumpPageTable (&mGuestContextCommonSmm[0].EptPointer); // **DEBUG** Dump the SMI Handler EPT tables
|
|
// sync the BSP CPU once the API is ready
|
|
CpuReadySync(Index);
|
|
|
|
// turn on SMI for the BSP - the base code allows SMIs before this point
|
|
// this mod prvents SMIs until the STM is ready to process them
|
|
|
|
GuestInterruptibilityState.Uint32 = VmRead32 (VMCS_32_GUEST_INTERRUPTIBILITY_STATE_INDEX);
|
|
GuestInterruptibilityState.Bits.BlockingBySmi = 0;
|
|
VmWrite32 (VMCS_32_GUEST_INTERRUPTIBILITY_STATE_INDEX, GuestInterruptibilityState.Uint32);
|
|
}
|
|
#if 0
|
|
DumpVmcsAllField();
|
|
#endif
|
|
return STM_SUCCESS;
|
|
} else {
|
|
DEBUG((EFI_D_ERROR, "%d STM_API_START -- Error STM already started\n", (UINTN) Index));
|
|
return ERROR_STM_ALREADY_STARTED;
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallStopHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
X86_REGISTER *Reg;
|
|
|
|
Reg = &mGuestContextCommonSmi.GuestContextPerCpu[Index].Register;
|
|
|
|
mHostContextCommon.StmShutdown = 1; // let the VM/PE know to quit
|
|
//
|
|
// Launch SMM Teardown handler.
|
|
//
|
|
DEBUG ((EFI_D_INFO, "STM_API_STOP:\n"));
|
|
SmmTeardown (Index);
|
|
WriteUnaligned32 ((UINT32 *)&Reg->Rax, STM_SUCCESS);
|
|
VmWriteN (VMCS_N_GUEST_RFLAGS_INDEX, VmReadN(VMCS_N_GUEST_RFLAGS_INDEX) & ~RFLAGS_CF);
|
|
StmTeardown (Index);
|
|
DEBUG((EFI_D_INFO, "CpuDeadLoop\n"));
|
|
CpuDeadLoop ();
|
|
|
|
return STM_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallProtectResourceHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
STM_RSC *StmResource;
|
|
STM_RSC *BiosResource;
|
|
STM_STATUS Status;
|
|
STM_RSC *LocalBuffer;
|
|
|
|
// ECX:EBX - STM_RESOURCE_LIST
|
|
AcquireSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
DEBUG ((EFI_D_INFO, "%ld STM_API_PROTECT_RESOURCE:\n", Index));
|
|
|
|
// BiosHwResourceRequirementsPtr to local BiosResource, delay it to first ProtectResource VMCALL, because BIOS may change resource at runtime.
|
|
if (mGuestContextCommonSmm[SMI_HANDLER].BiosHwResourceRequirementsPtr == 0) {
|
|
if (!IsResourceListValid ((STM_RSC *)(UINTN)mHostContextCommon.HostContextPerCpu[0].TxtProcessorSmmDescriptor->BiosHwResourceRequirementsPtr, FALSE)) {
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
DEBUG ((EFI_D_ERROR, "%ld SmiVmcallProtectResourceHandler - ValidateBiosResourceList fail!\n", Index));
|
|
return ERROR_STM_MALFORMED_RESOURCE_LIST;
|
|
}
|
|
mGuestContextCommonSmm[SMI_HANDLER].BiosHwResourceRequirementsPtr = (UINT64)(UINTN)DuplicateResource ((STM_RSC *)(UINTN)mHostContextCommon.HostContextPerCpu[0].TxtProcessorSmmDescriptor->BiosHwResourceRequirementsPtr);
|
|
RegisterBiosResource ((STM_RSC *)(UINTN)mGuestContextCommonSmm[SMI_HANDLER].BiosHwResourceRequirementsPtr);
|
|
}
|
|
|
|
//
|
|
// Copy data to local, to prevent time of check VS time of use attack
|
|
//
|
|
LocalBuffer = RawDuplicateResource ((STM_RSC *)(UINTN)AddressParameter);
|
|
if (LocalBuffer == NULL) {
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
return ERROR_STM_MALFORMED_RESOURCE_LIST;
|
|
}
|
|
|
|
StmResource = (STM_RSC *)(UINTN)LocalBuffer;
|
|
|
|
DumpStmResource (StmResource);
|
|
|
|
if (!IsResourceListValid (StmResource, TRUE)) {
|
|
DEBUG ((EFI_D_ERROR, "IsResourceListValid fail!\n"));
|
|
RawFreeResource (LocalBuffer);
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
return ERROR_STM_MALFORMED_RESOURCE_LIST;
|
|
}
|
|
DEBUG ((EFI_D_INFO, "IsResourceListValid pass!\n"));
|
|
|
|
BiosResource = (STM_RSC *)(UINTN)mGuestContextCommonSmm[SMI_HANDLER].BiosHwResourceRequirementsPtr;
|
|
if (IsResourceListOverlap (StmResource, BiosResource)) {
|
|
DEBUG ((EFI_D_ERROR, "IsResourceListOverlap fail!\n"));
|
|
RawFreeResource (LocalBuffer);
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
return ERROR_STM_UNPROTECTABLE_RESOURCE;
|
|
}
|
|
DEBUG ((EFI_D_INFO, "IsResourceListOverlap pass!\n"));
|
|
|
|
Status = AddProtectedResource (&mHostContextCommon.MleProtectedResource, StmResource);
|
|
if (Status != STM_SUCCESS) {
|
|
DEBUG ((EFI_D_ERROR, "AddProtectedResource fail!\n"));
|
|
RawFreeResource (LocalBuffer);
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
return Status;
|
|
}
|
|
AddProtectedResourceWithType (&mHostContextCommon.MleProtectedTrappedIoResource, StmResource, TRAPPED_IO_RANGE);
|
|
|
|
RegisterProtectedResource (StmResource);
|
|
|
|
RawFreeResource (LocalBuffer);
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
|
|
return STM_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallUnprotectResourceHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
STM_RSC *StmResource;
|
|
STM_RSC *LocalBuffer;
|
|
|
|
// ECX:EBX - STM_RESOURCE_LIST
|
|
AcquireSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
DEBUG ((EFI_D_INFO, "STM_API_UNPROTECT_RESOURCE:\n"));
|
|
|
|
//
|
|
// Copy data to local, to prevent time of check VS time of use attack
|
|
//
|
|
LocalBuffer = RawDuplicateResource ((STM_RSC *)(UINTN)AddressParameter);
|
|
if (LocalBuffer == NULL) {
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
return ERROR_STM_MALFORMED_RESOURCE_LIST;
|
|
}
|
|
|
|
StmResource = (STM_RSC *)(UINTN)LocalBuffer;
|
|
|
|
if (!IsResourceListValid (StmResource, TRUE)) {
|
|
DEBUG ((EFI_D_ERROR, "IsResourceListValid fail!\n"));
|
|
RawFreeResource (LocalBuffer);
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
return ERROR_STM_MALFORMED_RESOURCE_LIST;
|
|
}
|
|
DEBUG ((EFI_D_INFO, "IsResourceListValid pass!\n"));
|
|
|
|
DumpStmResource (StmResource);
|
|
|
|
DeleteProtectedResource (&mHostContextCommon.MleProtectedResource, StmResource);
|
|
|
|
UnRegisterProtectedResource (StmResource);
|
|
|
|
RawFreeResource (LocalBuffer);
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
|
|
return STM_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallGetBiosResourcesHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
STM_RSC *BiosResource;
|
|
UINTN BiosResourceSize;
|
|
UINT32 PageNum;
|
|
X86_REGISTER *Reg;
|
|
Reg = &mGuestContextCommonSmi.GuestContextPerCpu[Index].Register;
|
|
|
|
// ECX:EBX - STM_RESOURCE_LIST
|
|
// EDX: PageCount
|
|
AcquireSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
DEBUG ((EFI_D_INFO, "%ld STM_API_GET_BIOS_RESOURCES:\n", Index));
|
|
|
|
// BiosHwResourceRequirementsPtr to local BiosResource, delay it to first ProtectResource VMCALL, because BIOS may change resource at runtime.
|
|
if (mGuestContextCommonSmm[SMI_HANDLER].BiosHwResourceRequirementsPtr == 0) {
|
|
if (!IsResourceListValid ((STM_RSC *)(UINTN)mHostContextCommon.HostContextPerCpu[0].TxtProcessorSmmDescriptor->BiosHwResourceRequirementsPtr, FALSE)) {
|
|
DEBUG ((EFI_D_ERROR, "%ld SmiVmcallGetBiosResourcesHandler - ValidateBiosResourceList fail!\n", Index));
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
return ERROR_STM_MALFORMED_RESOURCE_LIST;
|
|
}
|
|
mGuestContextCommonSmm[SMI_HANDLER].BiosHwResourceRequirementsPtr = (UINT64)(UINTN)DuplicateResource ((STM_RSC *)(UINTN)mHostContextCommon.HostContextPerCpu[0].TxtProcessorSmmDescriptor->BiosHwResourceRequirementsPtr);
|
|
RegisterBiosResource ((STM_RSC *)(UINTN)mGuestContextCommonSmm[SMI_HANDLER].BiosHwResourceRequirementsPtr);
|
|
}
|
|
|
|
PageNum = (UINT32)Reg->Rdx;
|
|
|
|
if (!IsGuestAddressValid ((UINTN)AddressParameter, STM_PAGES_TO_SIZE(PageNum + 1), TRUE)) {
|
|
DEBUG ((EFI_D_ERROR, "%ld Security Violation!\n", Index));
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
return ERROR_STM_SECURITY_VIOLATION;
|
|
}
|
|
|
|
BiosResource = (STM_RSC *)(UINTN)mGuestContextCommonSmm[SMI_HANDLER].BiosHwResourceRequirementsPtr;
|
|
BiosResourceSize = GetSizeFromResource (BiosResource);
|
|
if (BiosResourceSize == 0) {
|
|
ReleaseSpinLock(&mHostContextCommon.SmiVmcallLock);
|
|
return ERROR_STM_SECURITY_VIOLATION;
|
|
}
|
|
|
|
DEBUG ((EFI_D_INFO, "%ld BiosResource - %016lx(%08x), PageCount - %d\n", (UINTN)Index, (UINT64)(UINTN)BiosResource, (UINTN)BiosResourceSize, (UINTN)PageNum));
|
|
// DumpStmResource (BiosResource);
|
|
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
|
|
if (PageNum >= STM_SIZE_TO_PAGES (BiosResourceSize)) {
|
|
WriteUnaligned32 ((UINT32 *)&Reg->Rdx, 0);
|
|
DEBUG((EFI_D_INFO, "%ld SmiVmcallGetBiosResourcesHandler - ERROR_STM_PAGE_NOT_FOUND - writing 0 to 0x%x\n", Index, &Reg->Rdx));
|
|
return ERROR_STM_PAGE_NOT_FOUND;
|
|
}
|
|
// Write data
|
|
CopyMem (
|
|
(VOID *)(UINTN)AddressParameter,
|
|
(VOID *)((UINTN)BiosResource + SIZE_4KB * PageNum),
|
|
SIZE_4KB
|
|
);
|
|
PageNum++;
|
|
if (PageNum >= STM_SIZE_TO_PAGES (BiosResourceSize)) {
|
|
WriteUnaligned32 ((UINT32 *)&Reg->Rdx, 0);
|
|
} else {
|
|
WriteUnaligned32 ((UINT32 *)&Reg->Rdx, PageNum);
|
|
}
|
|
|
|
return STM_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallManageVmcsDatabaseHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
STM_VMCS_DATABASE_REQUEST *VmcsDatabaseRequest;
|
|
STM_STATUS Status;
|
|
STM_VMCS_DATABASE_REQUEST LocalBuffer;
|
|
|
|
// ECX:EBX - STM_VMCS_DATABASE_REQUEST
|
|
AcquireSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
DEBUG ((EFI_D_INFO, "STM_API_MANAGE_VMCS_DATABASE:\n"));
|
|
|
|
if (!IsGuestAddressValid ((UINTN)AddressParameter, sizeof(STM_VMCS_DATABASE_REQUEST), TRUE)) {
|
|
DEBUG ((EFI_D_ERROR, "Security Violation!\n"));
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
return ERROR_STM_SECURITY_VIOLATION;
|
|
}
|
|
|
|
//
|
|
// Copy data to local, to prevent time of check VS time of use attack
|
|
//
|
|
CopyMem (&LocalBuffer, (VOID *)(UINTN)AddressParameter, sizeof(LocalBuffer));
|
|
|
|
VmcsDatabaseRequest = (STM_VMCS_DATABASE_REQUEST *)&LocalBuffer;
|
|
|
|
Status = RequestVmcsDatabaseEntry (
|
|
VmcsDatabaseRequest,
|
|
(VMCS_RECORD_STRUCTURE *)(UINTN)mHostContextCommon.VmcsDatabase
|
|
);
|
|
|
|
DEBUG ((EFI_D_INFO, "VMCS Database (%d) - %016lx\n", (UINTN)Index, mHostContextCommon.VmcsDatabase));
|
|
|
|
DumpVmcsRecord (mHostContextCommon.VmcsDatabase);
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallEventNewLogHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
UINT32 PageIndex;
|
|
STM_EVENT_LOG_MANAGEMENT_REQUEST *EventLogRequest;
|
|
UINTN PageCount;
|
|
UINT8 LocalBuffer[SIZE_4KB];
|
|
|
|
//
|
|
// SmiVmcallManageEventLogHandler already checked [AddressParameter, sizeof(STM_EVENT_LOG_MANAGEMENT_REQUEST)]
|
|
//
|
|
// Use PageCount only, because other data is still in Non-SMRAM and under attack.
|
|
//
|
|
|
|
// ECX:EBX - STM_EVENT_LOG_MANAGEMENT_REQUEST
|
|
EventLogRequest = (STM_EVENT_LOG_MANAGEMENT_REQUEST *)(UINTN)AddressParameter;
|
|
|
|
PageCount = (UINTN)EventLogRequest->Data.LogBuffer.PageCount;
|
|
if (PageCount == 0) {
|
|
return ERROR_STM_INVALID_PAGECOUNT;
|
|
}
|
|
if (PageCount > ((SIZE_4KB - sizeof(STM_EVENT_LOG_MANAGEMENT_REQUEST)) / sizeof(UINT64))) {
|
|
return ERROR_STM_INVALID_PAGECOUNT;
|
|
}
|
|
if (!IsGuestAddressValid((UINTN)AddressParameter, sizeof(STM_EVENT_LOG_MANAGEMENT_REQUEST) + (PageCount - 1) * sizeof(UINT64), TRUE)) {
|
|
DEBUG((EFI_D_ERROR, "Security Violation!\n"));
|
|
return ERROR_STM_SECURITY_VIOLATION;
|
|
}
|
|
|
|
//
|
|
// Copy data to local, to prevent time of check VS time of use attack
|
|
//
|
|
CopyMem (LocalBuffer, (VOID *)(UINTN)AddressParameter, sizeof(STM_EVENT_LOG_MANAGEMENT_REQUEST) + (PageCount - 1) * sizeof(UINT64));
|
|
|
|
// ECX:EBX - STM_EVENT_LOG_MANAGEMENT_REQUEST
|
|
EventLogRequest = (STM_EVENT_LOG_MANAGEMENT_REQUEST *)LocalBuffer;
|
|
//
|
|
// Check if local copy matches previous PageCount
|
|
//
|
|
if (PageCount != (UINTN)EventLogRequest->Data.LogBuffer.PageCount) {
|
|
DEBUG ((EFI_D_ERROR, "Security Violation!\n"));
|
|
return ERROR_STM_SECURITY_VIOLATION;
|
|
}
|
|
|
|
DEBUG ((EFI_D_INFO, "NEW_LOG: PageCount - %x\n", PageCount));
|
|
for (PageIndex = 0; PageIndex < PageCount; PageIndex++) {
|
|
DEBUG ((EFI_D_INFO, "Page(%x) - %08x\n", (UINTN)PageIndex, (UINTN)EventLogRequest->Data.LogBuffer.Pages[PageIndex]));
|
|
if (!IsGuestAddressValid ((UINTN)EventLogRequest->Data.LogBuffer.Pages[PageIndex], SIZE_4KB, TRUE)) {
|
|
DEBUG ((EFI_D_ERROR, "Security Violation!\n"));
|
|
return ERROR_STM_SECURITY_VIOLATION;
|
|
}
|
|
}
|
|
DEBUG ((EFI_D_INFO, "\n"));
|
|
|
|
if (mHostContextCommon.EventLog.State != EvtInvalid) {
|
|
return ERROR_STM_LOG_ALLOCATED;
|
|
}
|
|
|
|
mHostContextCommon.EventLog.PageCount = EventLogRequest->Data.LogBuffer.PageCount;
|
|
// Check page in MLE memory
|
|
CopyMem (mHostContextCommon.EventLog.Pages, EventLogRequest->Data.LogBuffer.Pages, EventLogRequest->Data.LogBuffer.PageCount * sizeof(UINT64));
|
|
|
|
mHostContextCommon.EventLog.State = EvtLogStopped;
|
|
|
|
return STM_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallEventConfigureLogHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
STM_EVENT_LOG_MANAGEMENT_REQUEST *EventLogRequest;
|
|
STM_EVENT_LOG_MANAGEMENT_REQUEST LocalBuffer;
|
|
|
|
//
|
|
// Copy data to local, to prevent time of check VS time of use attack
|
|
//
|
|
CopyMem (&LocalBuffer, (VOID *)(UINTN)AddressParameter, sizeof(LocalBuffer));
|
|
|
|
// ECX:EBX - STM_EVENT_LOG_MANAGEMENT_REQUEST
|
|
EventLogRequest = (STM_EVENT_LOG_MANAGEMENT_REQUEST *)&LocalBuffer;
|
|
|
|
DEBUG ((EFI_D_INFO, "CONFIGURE_LOG: EventEnables - (%x)\n", (UINTN)EventLogRequest->Data.EventEnableBitmap));
|
|
if (mHostContextCommon.EventLog.State == EvtInvalid) {
|
|
return ERROR_STM_LOG_NOT_ALLOCATED;
|
|
}
|
|
if (mHostContextCommon.EventLog.State == EvtLogStarted) {
|
|
return ERROR_STM_LOG_NOT_STOPPED;
|
|
}
|
|
if (EventLogRequest->Data.EventEnableBitmap >= (1 << EvtMleMax)) {
|
|
return ERROR_STM_RESERVED_BIT_SET;
|
|
}
|
|
mHostContextCommon.EventLog.EventEnableBitmap = EventLogRequest->Data.EventEnableBitmap;
|
|
|
|
return STM_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallEventStartLogHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
LOG_ENTRY_DATA LogEntryData;
|
|
|
|
DEBUG ((EFI_D_INFO, "START_LOG:\n"));
|
|
if (mHostContextCommon.EventLog.State == EvtInvalid) {
|
|
return ERROR_STM_LOG_NOT_ALLOCATED;
|
|
}
|
|
if (mHostContextCommon.EventLog.State == EvtLogStarted) {
|
|
return ERROR_STM_LOG_NOT_STOPPED;
|
|
}
|
|
if (mHostContextCommon.EventLog.EventEnableBitmap == 0) {
|
|
return ERROR_STM_NO_EVENTS_ENABLED;
|
|
}
|
|
mHostContextCommon.EventLog.State = EvtLogStarted;
|
|
LogEntryData.Started.Reserved = 0;
|
|
AddEventLog (EvtLogStarted, &LogEntryData, sizeof(LogEntryData.Started), &mHostContextCommon.EventLog);
|
|
|
|
return STM_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallEventStopLogHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
LOG_ENTRY_DATA LogEntryData;
|
|
|
|
DEBUG ((EFI_D_INFO, "STOP_LOG:\n"));
|
|
if (mHostContextCommon.EventLog.State == EvtInvalid) {
|
|
return ERROR_STM_LOG_NOT_ALLOCATED;
|
|
}
|
|
if (mHostContextCommon.EventLog.State == EvtLogStopped) {
|
|
return ERROR_STM_LOG_NOT_STARTED;
|
|
}
|
|
LogEntryData.Stopped.Reserved = 0;
|
|
AddEventLog (EvtLogStopped, &LogEntryData, sizeof(LogEntryData.Stopped), &mHostContextCommon.EventLog);
|
|
mHostContextCommon.EventLog.State = EvtLogStopped;
|
|
|
|
return STM_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallEventClearLogHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
DEBUG ((EFI_D_INFO, "CLEAR_LOG:\n"));
|
|
if (mHostContextCommon.EventLog.State == EvtInvalid) {
|
|
return ERROR_STM_LOG_NOT_ALLOCATED;
|
|
}
|
|
if (mHostContextCommon.EventLog.State == EvtLogStarted) {
|
|
return ERROR_STM_LOG_NOT_STOPPED;
|
|
}
|
|
ClearEventLog (&mHostContextCommon.EventLog);
|
|
|
|
return STM_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallEventDeleteLogHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
DEBUG ((EFI_D_INFO, "DELETE_LOG:\n"));
|
|
if (mHostContextCommon.EventLog.State == EvtLogStarted) {
|
|
return ERROR_STM_LOG_NOT_STOPPED;
|
|
}
|
|
mHostContextCommon.EventLog.State = (UINT32)EvtInvalid;
|
|
mHostContextCommon.EventLog.EventSerialNumber = 0;
|
|
mHostContextCommon.EventLog.EventEnableBitmap = 0;
|
|
mHostContextCommon.EventLog.PageCount = 0;
|
|
ZeroMem (mHostContextCommon.EventLog.Pages, STM_PAGES_TO_SIZE(1));
|
|
|
|
return STM_SUCCESS;
|
|
}
|
|
|
|
STM_VMCALL_HANDLER_STRUCT mSmiVmcallEventLogHandler[] = {
|
|
{NEW_LOG, SmiVmcallEventNewLogHandler},
|
|
{CONFIGURE_LOG, SmiVmcallEventConfigureLogHandler},
|
|
{START_LOG, SmiVmcallEventStartLogHandler},
|
|
{STOP_LOG, SmiVmcallEventStopLogHandler},
|
|
{CLEAR_LOG, SmiVmcallEventClearLogHandler},
|
|
{DELETE_LOG, SmiVmcallEventDeleteLogHandler},
|
|
};
|
|
|
|
/**
|
|
|
|
This function returns SMI EventLog VMCALL handler by FuncIndex.
|
|
|
|
@param FuncIndex VmCall function index
|
|
|
|
@return VMCALL Handler
|
|
|
|
**/
|
|
STM_VMCALL_HANDLER
|
|
GetSmiVmcallEventLogHandlerByIndex (
|
|
IN UINT32 FuncIndex
|
|
)
|
|
{
|
|
UINTN Index;
|
|
for (Index = 0; Index < sizeof(mSmiVmcallEventLogHandler)/sizeof(mSmiVmcallEventLogHandler[0]); Index++) {
|
|
if (mSmiVmcallEventLogHandler[Index].FuncIndex == FuncIndex) {
|
|
return mSmiVmcallEventLogHandler[Index].StmVmcallHandler;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallManageEventLogHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
STM_EVENT_LOG_MANAGEMENT_REQUEST *EventLogRequest;
|
|
STM_STATUS Status;
|
|
STM_VMCALL_HANDLER StmVmcallHandler;
|
|
|
|
// ECX:EBX - STM_EVENT_LOG_MANAGEMENT_REQUEST
|
|
AcquireSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
DEBUG ((EFI_D_INFO, "STM_API_MANAGE_EVENT_LOG:\n"));
|
|
|
|
EventLogRequest = (STM_EVENT_LOG_MANAGEMENT_REQUEST *)(UINTN)AddressParameter;
|
|
|
|
if (!IsGuestAddressValid ((UINTN)AddressParameter, sizeof(STM_EVENT_LOG_MANAGEMENT_REQUEST), TRUE)) {
|
|
DEBUG ((EFI_D_ERROR, "Security Violation!\n"));
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
return ERROR_STM_SECURITY_VIOLATION;
|
|
}
|
|
|
|
StmVmcallHandler = GetSmiVmcallEventLogHandlerByIndex (EventLogRequest->SubFunctionIndex);
|
|
if (StmVmcallHandler == NULL) {
|
|
// Should not happen
|
|
DEBUG ((EFI_D_INFO, "GetSmiVmcallEventLogHandlerByIndex - %x!\n", (UINTN)EventLogRequest->SubFunctionIndex));
|
|
CpuDeadLoop ();
|
|
Status = ERROR_INVALID_API;
|
|
} else {
|
|
Status = StmVmcallHandler (Index, AddressParameter);
|
|
}
|
|
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallAddTempPeVmHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
STM_STATUS Status;
|
|
PE_MODULE_INFO LocalBuffer;
|
|
|
|
// STM_ADD_TEMP_PE
|
|
AcquireSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
DEBUG ((EFI_D_ERROR, "STM_API_ADD_TEMP_VM:\n"));
|
|
|
|
if (!IsGuestAddressValid ((UINTN)AddressParameter, sizeof(PE_MODULE_INFO), TRUE)) {
|
|
DEBUG ((EFI_D_ERROR, "Security Violation!\n"));
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
return ERROR_STM_SECURITY_VIOLATION;
|
|
}
|
|
|
|
//
|
|
// Copy data to local, to prevent time of check VS time of use attack
|
|
//
|
|
CopyMem (&LocalBuffer, (VOID *)(UINTN)AddressParameter, sizeof(LocalBuffer));
|
|
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
Status = AddPeVm(Index, &LocalBuffer, PE_TEMP, 1);
|
|
|
|
//Status = STM_SUCCESS;
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallAddPermPeVmHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
STM_STATUS Status;
|
|
PE_MODULE_INFO LocalBuffer;
|
|
|
|
// - STM_ADD_PERM_PE_VM
|
|
AcquireSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
DEBUG ((EFI_D_ERROR, "STM_API_ADD_PERM_VM:\n"));
|
|
|
|
if (!IsGuestAddressValid ((UINTN)AddressParameter, sizeof(PE_MODULE_INFO), TRUE)) {
|
|
DEBUG ((EFI_D_ERROR, "Security Violation!\n"));
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
return ERROR_STM_SECURITY_VIOLATION;
|
|
}
|
|
|
|
//
|
|
// Copy data to local, to prevent time of check VS time of use attack
|
|
//
|
|
CopyMem (&LocalBuffer, (VOID *)(UINTN)AddressParameter, sizeof(LocalBuffer));
|
|
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
Status = AddPeVm(Index, &LocalBuffer, PE_PERM, 1);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallAddPermPeVmNoRunHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
STM_STATUS Status;
|
|
PE_MODULE_INFO LocalBuffer;
|
|
|
|
// - STM_ADD_PERM_PE_VM
|
|
AcquireSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
DEBUG ((EFI_D_ERROR, "%ld SmiVmcallAddPermPeVmNoRunHandler - STM_API_ADD_PERM_VM_NO_RUN:\n", Index));
|
|
|
|
if (!IsGuestAddressValid ((UINTN)AddressParameter, sizeof(PE_MODULE_INFO), TRUE)) {
|
|
DEBUG ((EFI_D_ERROR, "%ld SmiVmcallAddPermPeVmNoRunHandler - Security Violation!\n", Index));
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
return ERROR_STM_SECURITY_VIOLATION;
|
|
}
|
|
|
|
//
|
|
// Copy data to local, to prevent time of check VS time of use attack
|
|
//
|
|
CopyMem (&LocalBuffer, (VOID *)(UINTN)AddressParameter, sizeof(LocalBuffer));
|
|
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
Status = AddPeVm(Index, &LocalBuffer, PE_PERM, 0); // do not run PE/VM
|
|
|
|
return Status;
|
|
}
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallRunPeVmHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
STM_STATUS Status;
|
|
PE_MODULE_INFO LocalBuffer;
|
|
|
|
UINT32 PeType = PE_PERM;
|
|
// ECX:EBX - STM_VMCS_DATABASE_REQUEST
|
|
AcquireSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
DEBUG ((EFI_D_ERROR, " %ld STM_API_RUN_PERM_VM:\n", Index));
|
|
|
|
if (!IsGuestAddressValid ((UINTN)AddressParameter, sizeof(PE_MODULE_INFO), TRUE)) {
|
|
DEBUG ((EFI_D_ERROR, " %ld Security Violation!\n", Index));
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
return ERROR_STM_SECURITY_VIOLATION;
|
|
}
|
|
|
|
//
|
|
// Copy data to local, to prevent time of check VS time of use attack
|
|
//
|
|
CopyMem (&LocalBuffer, (VOID *)(UINTN)AddressParameter, sizeof(LocalBuffer));
|
|
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
// provide the root state for the measurement VM
|
|
//GetRootVmxState(StmVmm, (ROOT_VMX_STATE *) ptData[CR3index].ShareModuleStm);
|
|
PeVmData[PeType].StartMode = PEVM_START_VMCALL;
|
|
RunPermVM(Index);
|
|
|
|
Status = STM_SUCCESS;
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
@param AddressParameter Addresss parameter
|
|
|
|
@return VMCALL status
|
|
|
|
**/
|
|
STM_STATUS
|
|
SmiVmcallEndPermVmHandler (
|
|
IN UINT32 Index,
|
|
IN UINT64 AddressParameter
|
|
)
|
|
{
|
|
STM_STATUS Status;
|
|
PE_MODULE_INFO LocalBuffer;
|
|
|
|
// ECX:EBX - STM_VMCS_DATABASE_REQUEST
|
|
AcquireSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
DEBUG ((EFI_D_ERROR, "STM_API_END_PERM_VM:\n"));
|
|
|
|
if (!IsGuestAddressValid ((UINTN)AddressParameter, sizeof(PE_MODULE_INFO), TRUE)) {
|
|
DEBUG ((EFI_D_ERROR, "Security Violation!\n"));
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
return ERROR_STM_SECURITY_VIOLATION;
|
|
}
|
|
|
|
DEBUG ((EFI_D_ERROR, "STM_API_END_PERM_VM - not implemented\n"));
|
|
//
|
|
// Copy data to local, to prevent time of check VS time of use attack
|
|
//
|
|
CopyMem (&LocalBuffer, (VOID *)(UINTN)AddressParameter, sizeof(LocalBuffer));
|
|
|
|
Status = STM_SUCCESS;
|
|
ReleaseSpinLock (&mHostContextCommon.SmiVmcallLock);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
STM_VMCALL_HANDLER_STRUCT mSmiVmcallHandler[] = {
|
|
{STM_API_START, SmiVmcallStartHandler},
|
|
{STM_API_STOP, SmiVmcallStopHandler},
|
|
{STM_API_PROTECT_RESOURCE, SmiVmcallProtectResourceHandler},
|
|
{STM_API_UNPROTECT_RESOURCE, SmiVmcallUnprotectResourceHandler},
|
|
{STM_API_GET_BIOS_RESOURCES, SmiVmcallGetBiosResourcesHandler},
|
|
{STM_API_MANAGE_VMCS_DATABASE, SmiVmcallManageVmcsDatabaseHandler},
|
|
{STM_API_INITIALIZE_PROTECTION, SmiVmcallInitializeProtectionHandler},
|
|
{STM_API_MANAGE_EVENT_LOG, SmiVmcallManageEventLogHandler},
|
|
{STM_API_ADD_TEMP_PE_VM, SmiVmcallAddTempPeVmHandler},
|
|
{STM_API_ADD_PERM_PE_VM, SmiVmcallAddPermPeVmHandler},
|
|
{STM_API_ADD_PERM_PE_VM_NORUN, SmiVmcallAddPermPeVmNoRunHandler},
|
|
{STM_API_RUN_PE_VM, SmiVmcallRunPeVmHandler},
|
|
{STM_API_END_ADD_PERM_PE_VM, SmiVmcallEndPermVmHandler}
|
|
};
|
|
|
|
/**
|
|
|
|
This function returns SMI VMCALL handler by FuncIndex.
|
|
|
|
@param FuncIndex VmCall function index
|
|
|
|
@return VMCALL Handler
|
|
|
|
**/
|
|
STM_VMCALL_HANDLER
|
|
GetSmiVmcallHandlerByIndex (
|
|
IN UINT32 FuncIndex
|
|
)
|
|
{
|
|
UINTN Index;
|
|
for (Index = 0; Index < sizeof(mSmiVmcallHandler)/sizeof(mSmiVmcallHandler[0]); Index++) {
|
|
if (mSmiVmcallHandler[Index].FuncIndex == FuncIndex) {
|
|
return mSmiVmcallHandler[Index].StmVmcallHandler;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
|
|
This function is VMCALL handler for SMI.
|
|
|
|
@param Index CPU index
|
|
|
|
**/
|
|
VOID
|
|
SmiVmcallHandler (
|
|
IN UINT32 Index
|
|
)
|
|
{
|
|
X86_REGISTER *Reg;
|
|
STM_STATUS Status;
|
|
STM_VMCALL_HANDLER StmVmcallHandler;
|
|
UINT64 AddressParameter;
|
|
//DEBUG((EFI_D_ERROR, "%ld SmiVmcallHandler - entereda\n", Index));
|
|
|
|
Reg = &mGuestContextCommonSmi.GuestContextPerCpu[Index].Register;
|
|
StmVmcallHandler = GetSmiVmcallHandlerByIndex (ReadUnaligned32 ((UINT32 *)&Reg->Rax));
|
|
if (StmVmcallHandler == NULL) {
|
|
DEBUG ((EFI_D_INFO, "%ld SmiVmcallHandler - GetSmiVmcallHandlerByIndex- Invalid API entry - %x!\n", Index, (UINTN)ReadUnaligned32 ((UINT32 *)&Reg->Rax)));
|
|
//DumpVmcsAllField ();
|
|
//DEBUG ((EFI_D_ERROR, "%ld SmiVmcallHandler - ***Error*** Halting STM\n", Index));
|
|
|
|
// Should not happen
|
|
//CpuDeadLoop ();
|
|
Status = ERROR_INVALID_API;
|
|
} else {
|
|
AddressParameter = ReadUnaligned32 ((UINT32 *)&Reg->Rbx) + LShiftU64 (ReadUnaligned32 ((UINT32 *)&Reg->Rcx), 32);
|
|
|
|
Status = StmVmcallHandler (Index, AddressParameter);
|
|
}
|
|
|
|
if (Status == STM_SUCCESS) {
|
|
VmWriteN (VMCS_N_GUEST_RFLAGS_INDEX, VmReadN(VMCS_N_GUEST_RFLAGS_INDEX) & ~RFLAGS_CF);
|
|
} else {
|
|
VmWriteN (VMCS_N_GUEST_RFLAGS_INDEX, VmReadN(VMCS_N_GUEST_RFLAGS_INDEX) | RFLAGS_CF);
|
|
AddEventLogInvalidParameter (ReadUnaligned32 ((UINT32 *)&Reg->Rax));
|
|
}
|
|
WriteUnaligned32 ((UINT32 *)&Reg->Rax, Status);
|
|
VmWriteN (VMCS_N_GUEST_RIP_INDEX, VmReadN (VMCS_N_GUEST_RIP_INDEX) + VmRead32 (VMCS_32_RO_VMEXIT_INSTRUCTION_LENGTH_INDEX));
|
|
|
|
return ;
|
|
}
|