OvfmPkg/VmgExitLib: Validate #VC MMIO is to un-encrypted memory

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3108

When SEV-ES is active, and MMIO operation will trigger a #VC and the
VmgExitLib exception handler will process this MMIO operation.

A malicious hypervisor could try to extract information from encrypted
memory by setting a reserved bit in the guests nested page tables for
a non-MMIO area. This can result in the encrypted data being copied into
the GHCB shared buffer area and accessed by the hypervisor.

Prevent this by ensuring that the MMIO source/destination is un-encrypted
memory. For the APIC register space, access is allowed in general.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Message-Id: <0cf28470ad5e694af45f7f0b35296628f819567d.1610045305.git.thomas.lendacky@amd.com>
This commit is contained in:
Tom Lendacky 2021-01-07 12:48:25 -06:00 committed by mergify[bot]
parent 362654246a
commit 85b8eac59b
6 changed files with 88 additions and 1 deletions

View File

@ -237,6 +237,7 @@
CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
!endif
VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf
[LibraryClasses.common.PEI_CORE]
HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf

View File

@ -14,7 +14,7 @@
FILE_GUID = c1594631-3888-4be4-949f-9c630dbc842b
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = MemEncryptSevLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
LIBRARY_CLASS = MemEncryptSevLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
#
# The following information is for reference only and not required by the build

View File

@ -35,6 +35,8 @@
BaseLib
BaseMemoryLib
DebugLib
LocalApicLib
MemEncryptSevLib
PcdLib
[FixedPcd]

View File

@ -35,4 +35,6 @@
BaseLib
BaseMemoryLib
DebugLib
LocalApicLib
MemEncryptSevLib

View File

@ -9,6 +9,7 @@
#include <Base.h>
#include <Uefi.h>
#include <Library/BaseMemoryLib.h>
#include <Library/LocalApicLib.h>
#include <Library/MemEncryptSevLib.h>
#include <Library/VmgExitLib.h>
#include <Register/Amd/Msr.h>
@ -595,6 +596,61 @@ UnsupportedExit (
return Status;
}
/**
Validate that the MMIO memory access is not to encrypted memory.
Examine the pagetable entry for the memory specified. MMIO should not be
performed against encrypted memory. MMIO to the APIC page is always allowed.
@param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block
@param[in] MemoryAddress Memory address to validate
@param[in] MemoryLength Memory length to validate
@retval 0 Memory is not encrypted
@return New exception value to propogate
**/
STATIC
UINT64
ValidateMmioMemory (
IN GHCB *Ghcb,
IN UINTN MemoryAddress,
IN UINTN MemoryLength
)
{
MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State;
GHCB_EVENT_INJECTION GpEvent;
UINTN Address;
//
// Allow APIC accesses (which will have the encryption bit set during
// SEC and PEI phases).
//
Address = MemoryAddress & ~(SIZE_4KB - 1);
if (Address == GetLocalApicBaseAddress ()) {
return 0;
}
State = MemEncryptSevGetAddressRangeState (
0,
MemoryAddress,
MemoryLength
);
if (State == MemEncryptSevAddressRangeUnencrypted) {
return 0;
}
//
// Any state other than unencrypted is an error, issue a #GP.
//
GpEvent.Uint64 = 0;
GpEvent.Elements.Vector = GP_EXCEPTION;
GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;
GpEvent.Elements.Valid = 1;
return GpEvent.Uint64;
}
/**
Handle an MMIO event.
@ -653,6 +709,11 @@ MmioExit (
return UnsupportedExit (Ghcb, Regs, InstructionData);
}
Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
if (Status != 0) {
return Status;
}
ExitInfo1 = InstructionData->Ext.RmData;
ExitInfo2 = Bytes;
CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes);
@ -683,6 +744,11 @@ MmioExit (
InstructionData->ImmediateSize = Bytes;
InstructionData->End += Bytes;
Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
if (Status != 0) {
return Status;
}
ExitInfo1 = InstructionData->Ext.RmData;
ExitInfo2 = Bytes;
CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes);
@ -717,6 +783,11 @@ MmioExit (
return UnsupportedExit (Ghcb, Regs, InstructionData);
}
Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
if (Status != 0) {
return Status;
}
ExitInfo1 = InstructionData->Ext.RmData;
ExitInfo2 = Bytes;
@ -748,6 +819,11 @@ MmioExit (
case 0xB7:
Bytes = (Bytes != 0) ? Bytes : 2;
Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
if (Status != 0) {
return Status;
}
ExitInfo1 = InstructionData->Ext.RmData;
ExitInfo2 = Bytes;
@ -774,6 +850,11 @@ MmioExit (
case 0xBF:
Bytes = (Bytes != 0) ? Bytes : 2;
Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
if (Status != 0) {
return Status;
}
ExitInfo1 = InstructionData->Ext.RmData;
ExitInfo2 = Bytes;

View File

@ -266,6 +266,7 @@
CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
!endif
VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf
[LibraryClasses.common.PEI_CORE]
HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf