x86/boot/compressed/64: Check SEV encryption in the 32-bit boot-path
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
This commit is contained in:
Родитель
e927e62d8e
Коммит
fef81c8626
|
@ -183,11 +183,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
|
||||
|
@ -272,6 +282,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
|
||||
|
||||
|
@ -871,6 +884,76 @@ SYM_FUNC_START(startup32_load_idt)
|
|||
ret
|
||||
SYM_FUNC_END(startup32_load_idt)
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче