]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/ResetVector: Validate the encryption bit position for SEV/SEV-ES
authorTom Lendacky <thomas.lendacky@amd.com>
Thu, 7 Jan 2021 18:48:13 +0000 (12:48 -0600)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Thu, 7 Jan 2021 19:34:39 +0000 (19:34 +0000)
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3108

To help mitigate against ROP attacks, add some checks to validate the
encryption bit position that is reported by the hypervisor.

The first check is to ensure that the hypervisor reports a bit position
above bit 31. After extracting the encryption bit position from the CPUID
information, the code checks that the value is above 31. If the value is
not above 31, then the bit position is not valid, so the code enters a
HLT loop.

The second check is specific to SEV-ES guests and is a two step process.
The first step will obtain random data using RDRAND and store that data to
memory before paging is enabled. When paging is not enabled, all writes to
memory are encrypted. The random data is maintained in registers, which
are protected. The second step is that, after enabling paging, the random
data in memory is compared to the register contents. If they don't match,
then the reported bit position is not valid, so the code enters a HLT
loop.

The third check is after switching to 64-bit long mode. Use the fact that
instruction fetches are automatically decrypted, while a memory fetch is
decrypted only if the encryption bit is set in the page table. By
comparing the bytes of an instruction fetch against a memory read of that
same instruction, the encryption bit position can be validated. If the
compare is not equal, then SEV/SEV-ES is active but the reported bit
position is not valid, so the code enters a HLT loop.

To keep the changes local to the OvmfPkg, an OvmfPkg version of the
Flat32ToFlat64.asm file has been created based on the UefiCpuPkg file
UefiCpuPkg/ResetVector/Vtf0/Ia32/Flat32ToFlat64.asm.

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>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Message-Id: <cb9c5ab23ab02096cd964ed64115046cc706ce67.1610045305.git.thomas.lendacky@amd.com>

OvmfPkg/Include/Library/MemEncryptSevLib.h
OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm [new file with mode: 0644]
OvmfPkg/ResetVector/Ia32/PageTables64.asm
OvmfPkg/ResetVector/ResetVector.nasmb

index a6d82dac7facb85a57e75bc393620eed7479b11c..dc09c61e58bb4296b8b59a3e908f9e24015b29bc 100644 (file)
 // This structure is also used by assembler files:\r
 //   OvmfPkg/ResetVector/ResetVector.nasmb\r
 //   OvmfPkg/ResetVector/Ia32/PageTables64.asm\r
+//   OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm\r
 // any changes must stay in sync with its usage.\r
 //\r
 typedef struct _SEC_SEV_ES_WORK_AREA {\r
   UINT8    SevEsEnabled;\r
+  UINT8    Reserved1[7];\r
+\r
+  UINT64   RandomData;\r
 } SEC_SEV_ES_WORK_AREA;\r
 \r
 /**\r
diff --git a/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm b/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
new file mode 100644 (file)
index 0000000..c6d0d89
--- /dev/null
@@ -0,0 +1,118 @@
+;------------------------------------------------------------------------------\r
+; @file\r
+; Transition from 32 bit flat protected mode into 64 bit flat protected mode\r
+;\r
+; Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>\r
+; Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
+; SPDX-License-Identifier: BSD-2-Clause-Patent\r
+;\r
+;------------------------------------------------------------------------------\r
+\r
+BITS    32\r
+\r
+;\r
+; Modified:  EAX, ECX, EDX\r
+;\r
+Transition32FlatTo64Flat:\r
+\r
+    OneTimeCall SetCr3ForPageTables64\r
+\r
+    mov     eax, cr4\r
+    bts     eax, 5                      ; enable PAE\r
+    mov     cr4, eax\r
+\r
+    mov     ecx, 0xc0000080\r
+    rdmsr\r
+    bts     eax, 8                      ; set LME\r
+    wrmsr\r
+\r
+    ;\r
+    ; SEV-ES mitigation check support\r
+    ;\r
+    xor     ebx, ebx\r
+\r
+    cmp     byte[SEV_ES_WORK_AREA], 0\r
+    jz      EnablePaging\r
+\r
+    ;\r
+    ; SEV-ES is active, perform a quick sanity check against the reported\r
+    ; encryption bit position. This is to help mitigate against attacks where\r
+    ; the hypervisor reports an incorrect encryption bit position.\r
+    ;\r
+    ; This is the first step in a two step process. Before paging is enabled\r
+    ; writes to memory are encrypted. Using the RDRAND instruction (available\r
+    ; on all SEV capable processors), write 64-bits of random data to the\r
+    ; SEV_ES_WORK_AREA and maintain the random data in registers (register\r
+    ; state is protected under SEV-ES). This will be used in the second step.\r
+    ;\r
+RdRand1:\r
+    rdrand  ecx\r
+    jnc     RdRand1\r
+    mov     dword[SEV_ES_WORK_AREA_RDRAND], ecx\r
+RdRand2:\r
+    rdrand  edx\r
+    jnc     RdRand2\r
+    mov     dword[SEV_ES_WORK_AREA_RDRAND + 4], edx\r
+\r
+    ;\r
+    ; Use EBX instead of the SEV_ES_WORK_AREA memory to determine whether to\r
+    ; perform the second step.\r
+    ;\r
+    mov     ebx, 1\r
+\r
+EnablePaging:\r
+    mov     eax, cr0\r
+    bts     eax, 31                     ; set PG\r
+    mov     cr0, eax                    ; enable paging\r
+\r
+    jmp     LINEAR_CODE64_SEL:ADDR_OF(jumpTo64BitAndLandHere)\r
+BITS    64\r
+jumpTo64BitAndLandHere:\r
+\r
+    ;\r
+    ; Check if the second step of the SEV-ES mitigation is to be performed.\r
+    ;\r
+    test    ebx, ebx\r
+    jz      InsnCompare\r
+\r
+    ;\r
+    ; SEV-ES is active, perform the second step of the encryption bit postion\r
+    ; mitigation check. The ECX and EDX register contain data from RDRAND that\r
+    ; was stored to memory in encrypted form. If the encryption bit position is\r
+    ; valid, the contents of ECX and EDX will match the memory location.\r
+    ;\r
+    cmp     dword[SEV_ES_WORK_AREA_RDRAND], ecx\r
+    jne     SevEncBitHlt\r
+    cmp     dword[SEV_ES_WORK_AREA_RDRAND + 4], edx\r
+    jne     SevEncBitHlt\r
+\r
+    ;\r
+    ; If SEV or SEV-ES is active, perform a quick sanity check against\r
+    ; the reported encryption bit position. This is to help mitigate\r
+    ; against attacks where the hypervisor reports an incorrect encryption\r
+    ; bit position. If SEV is not active, this check will always succeed.\r
+    ;\r
+    ; The cmp instruction compares the first four bytes of the cmp instruction\r
+    ; itself (which will be read decrypted if SEV or SEV-ES is active and the\r
+    ; encryption bit position is valid) against the immediate within the\r
+    ; instruction (an instruction fetch is always decrypted correctly by\r
+    ; hardware) based on RIP relative addressing.\r
+    ;\r
+InsnCompare:\r
+    cmp     dword[rel InsnCompare], 0xFFF63D81\r
+    je      GoodCompare\r
+\r
+    ;\r
+    ; The hypervisor provided an incorrect encryption bit position, do not\r
+    ; proceed.\r
+    ;\r
+SevEncBitHlt:\r
+    cli\r
+    hlt\r
+    jmp     SevEncBitHlt\r
+\r
+GoodCompare:\r
+    debugShowPostCode POSTCODE_64BIT_MODE\r
+\r
+    OneTimeCallRet Transition32FlatTo64Flat\r
+\r
index 4032719c30755a2af644fd757494b949ef3af7bc..ccc95ad4715d3770e53fa6f9680c9ce28279a7c2 100644 (file)
@@ -140,9 +140,18 @@ GetSevEncBit:
     ; Get pte bit position to enable memory encryption\r
     ; CPUID Fn8000_001F[EBX] - Bits 5:0\r
     ;\r
+    and       ebx, 0x3f\r
     mov       eax, ebx\r
-    and       eax, 0x3f\r
-    jmp       SevExit\r
+\r
+    ; The encryption bit position is always above 31\r
+    sub       ebx, 32\r
+    jns       SevExit\r
+\r
+    ; Encryption bit was reported as 31 or below, enter a HLT loop\r
+SevEncBitLowHlt:\r
+    cli\r
+    hlt\r
+    jmp       SevEncBitLowHlt\r
 \r
 NoSev:\r
     xor       eax, eax\r
index c5e0fe93abf44df9e0b1bb49f816db35fc918bf8..d3aa879829593e12c52adc88a859d1b99c05c2eb 100644 (file)
@@ -3,6 +3,7 @@
 ; This file includes all other code files to assemble the reset vector code\r
 ;\r
 ; Copyright (c) 2008 - 2013, Intel Corporation. All rights reserved.<BR>\r
+; Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
 ; SPDX-License-Identifier: BSD-2-Clause-Patent\r
 ;\r
 ;------------------------------------------------------------------------------\r
   %endif\r
 \r
   %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))\r
-%include "Ia32/Flat32ToFlat64.asm"\r
 \r
   %define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))\r
   %define GHCB_BASE (FixedPcdGet32 (PcdOvmfSecGhcbBase))\r
   %define GHCB_SIZE (FixedPcdGet32 (PcdOvmfSecGhcbSize))\r
   %define SEV_ES_WORK_AREA (FixedPcdGet32 (PcdSevEsWorkAreaBase))\r
+  %define SEV_ES_WORK_AREA_RDRAND (FixedPcdGet32 (PcdSevEsWorkAreaBase) + 8)\r
   %define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))\r
+%include "Ia32/Flat32ToFlat64.asm"\r
 %include "Ia32/PageTables64.asm"\r
 %endif\r
 \r