[edk2-devel] [PATCH 12/12] OvfmPkg/VmgExitLib: Validate #VC MMIO is to un-encrypted memory

Lendacky, Thomas thomas.lendacky at amd.com
Tue Jan 5 14:45:01 UTC 2021


On 1/5/21 4:28 AM, Laszlo Ersek wrote:
> On 12/15/20 21:51, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky at amd.com>
>>
>> BZ: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D3108&data=04%7C01%7Cthomas.lendacky%40amd.com%7C4a5d3dd1c25d4935bd6608d8b164b73b%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637454393417282277%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=vEIKCoKCg1P46pkl2X0iod8x5I7%2FGyDu9beOoR2Pfww%3D&reserved=0
>>
>> 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 at intel.com>
>> Cc: Laszlo Ersek <lersek at redhat.com>
>> Cc: Ard Biesheuvel <ard.biesheuvel at arm.com>
>> Cc: Brijesh Singh <brijesh.singh at amd.com>
>> Signed-off-by: Tom Lendacky <thomas.lendacky at amd.com>
>> ---
>>  OvmfPkg/AmdSev/AmdSevX64.dsc                  |  1 +
>>  OvmfPkg/OvmfPkgX64.dsc                        |  1 +
>>  .../DxeBaseMemEncryptSevLib.inf               |  2 +-
>>  OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf  |  1 +
>>  OvmfPkg/Library/VmgExitLib/VmgExitLib.inf     |  2 +
>>  OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c | 81 +++++++++++++++++++
>>  6 files changed, 87 insertions(+), 1 deletion(-)
>>
>> diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
>> index 3e5a3f648ad5..d0e9d28fc492 100644
>> --- a/OvmfPkg/AmdSev/AmdSevX64.dsc
>> +++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
>> @@ -237,6 +237,7 @@ [LibraryClasses.common.SEC]
>>    CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
>>  !endif
>>    VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
>> +  MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecBaseMemEncryptSevLib.inf
>>  
>>  [LibraryClasses.common.PEI_CORE]
>>    HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
>> index 226b576545a9..2a230888c636 100644
>> --- a/OvmfPkg/OvmfPkgX64.dsc
>> +++ b/OvmfPkg/OvmfPkgX64.dsc
>> @@ -265,6 +265,7 @@ [LibraryClasses.common.SEC]
>>    CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
>>  !endif
>>    VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
>> +  MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecBaseMemEncryptSevLib.inf
>>  
>>  [LibraryClasses.common.PEI_CORE]
>>    HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
>> diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeBaseMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeBaseMemEncryptSevLib.inf
>> index 04728a5dd256..10f794759207 100644
>> --- a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeBaseMemEncryptSevLib.inf
>> +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeBaseMemEncryptSevLib.inf
>> @@ -14,7 +14,7 @@ [Defines]
>>    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
>> diff --git a/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf b/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
>> index df14de3c21bc..9c8de326f3d1 100644
>> --- a/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
>> +++ b/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
>> @@ -35,6 +35,7 @@ [LibraryClasses]
>>    BaseLib
>>    BaseMemoryLib
>>    DebugLib
>> +  MemEncryptSevLib
>>    PcdLib
>>  
>>  [FixedPcd]
>> diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf b/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
>> index b3c3e56ecff8..c66c68726cdb 100644
>> --- a/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
>> +++ b/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
>> @@ -35,4 +35,6 @@ [LibraryClasses]
>>    BaseLib
>>    BaseMemoryLib
>>    DebugLib
>> +  LocalApicLib
>> +  MemEncryptSevLib
>>  
> 
> (1) I don't understand why LocalApicLib is added only to
> "VmgExitLib.inf", and not "SecVmgExitLib.inf". The source file
> "VmgExitVcHandler.c" is shared between both INF files, and that file
> gets a GetLocalApicBaseAddress() call below. And, "SecVmgExitLib.inf"
> doesn't list the LocalApicLib class dependency from any earlier patch.
> 
> ... Hm, the issue is masked because "OvmfPkg/Sec/SecMain.inf" lists
> LocalApicLib already, so when the SEC module is linked, the LocalApicLib
> dependency is ultimately (independently) noted/satisfied.
> 
> But, that doesn't make this omission right; please amend the
> "SecVmgExitLib.inf" file.

Good catch, I'm not sure how I missed that. I'll make that change.

Thanks,
Tom

> 
> With that update:
> 
> Acked-by: Laszlo Ersek <lersek at redhat.com>
> 
> Thanks
> Laszlo
> 
>> diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
>> index ce577e4677eb..24259060fd65 100644
>> --- a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
>> +++ b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
>> @@ -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;
>>  
>>
> 


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#69713): https://edk2.groups.io/g/devel/message/69713
Mute This Topic: https://groups.io/mt/78986184/1813853
Mute #vc:https://edk2.groups.io/g/devel/mutehashtag/vc
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-





More information about the edk2-devel-archive mailing list