Skip to content

Commit

Permalink
x86/boot/compressed/64: Check SEV encryption in the 32-bit boot-path
Browse files Browse the repository at this point in the history
commit fef81c8 upstream.

Check whether the hypervisor reported the correct C-bit when running
as an SEV guest. Using a wrong C-bit position could be used to leak
sensitive data from the guest to the hypervisor.

Signed-off-by: Joerg Roedel <jroedel@suse.de>
Signed-off-by: Borislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/20210312123824.306-8-joro@8bytes.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Joerg Roedel authored and Greg Kroah-Hartman committed May 26, 2021
1 parent 0296c90 commit d28aa3c
Showing 1 changed file with 85 additions and 0 deletions.
85 changes: 85 additions & 0 deletions arch/x86/boot/compressed/head_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,21 @@ SYM_FUNC_START(startup_32)
*/
call get_sev_encryption_bit
xorl %edx, %edx
#ifdef CONFIG_AMD_MEM_ENCRYPT
testl %eax, %eax
jz 1f
subl $32, %eax /* Encryption bit is always above bit 31 */
bts %eax, %edx /* Set encryption mask for page tables */
/*
* Mark SEV as active in sev_status so that startup32_check_sev_cbit()
* will do a check. The sev_status memory will be fully initialized
* with the contents of MSR_AMD_SEV_STATUS later in
* set_sev_encryption_mask(). For now it is sufficient to know that SEV
* is active.
*/
movl $1, rva(sev_status)(%ebp)
1:
#endif

/* Initialize Page tables to 0 */
leal rva(pgtable)(%ebx), %edi
Expand Down Expand Up @@ -261,6 +271,9 @@ SYM_FUNC_START(startup_32)
movl %esi, %edx
1:
#endif
/* Check if the C-bit position is correct when SEV is active */
call startup32_check_sev_cbit

pushl $__KERNEL_CS
pushl %eax

Expand Down Expand Up @@ -786,6 +799,78 @@ SYM_DATA_START_LOCAL(loaded_image_proto)
SYM_DATA_END(loaded_image_proto)
#endif

/*
* Check for the correct C-bit position when the startup_32 boot-path is used.
*
* The check makes use of the fact that all memory is encrypted when paging is
* disabled. The function creates 64 bits of random data using the RDRAND
* instruction. RDRAND is mandatory for SEV guests, so always available. If the
* hypervisor violates that the kernel will crash right here.
*
* The 64 bits of random data are stored to a memory location and at the same
* time kept in the %eax and %ebx registers. Since encryption is always active
* when paging is off the random data will be stored encrypted in main memory.
*
* Then paging is enabled. When the C-bit position is correct all memory is
* still mapped encrypted and comparing the register values with memory will
* succeed. An incorrect C-bit position will map all memory unencrypted, so that
* the compare will use the encrypted random data and fail.
*/
__HEAD
.code32
SYM_FUNC_START(startup32_check_sev_cbit)
#ifdef CONFIG_AMD_MEM_ENCRYPT
pushl %eax
pushl %ebx
pushl %ecx
pushl %edx

/* Check for non-zero sev_status */
movl rva(sev_status)(%ebp), %eax
testl %eax, %eax
jz 4f

/*
* Get two 32-bit random values - Don't bail out if RDRAND fails
* because it is better to prevent forward progress if no random value
* can be gathered.
*/
1: rdrand %eax
jnc 1b
2: rdrand %ebx
jnc 2b

/* Store to memory and keep it in the registers */
movl %eax, rva(sev_check_data)(%ebp)
movl %ebx, rva(sev_check_data+4)(%ebp)

/* Enable paging to see if encryption is active */
movl %cr0, %edx /* Backup %cr0 in %edx */
movl $(X86_CR0_PG | X86_CR0_PE), %ecx /* Enable Paging and Protected mode */
movl %ecx, %cr0

cmpl %eax, rva(sev_check_data)(%ebp)
jne 3f
cmpl %ebx, rva(sev_check_data+4)(%ebp)
jne 3f

movl %edx, %cr0 /* Restore previous %cr0 */

jmp 4f

3: /* Check failed - hlt the machine */
hlt
jmp 3b

4:
popl %edx
popl %ecx
popl %ebx
popl %eax
#endif
ret
SYM_FUNC_END(startup32_check_sev_cbit)

/*
* Stack and heap for uncompression
*/
Expand Down

0 comments on commit d28aa3c

Please sign in to comment.