Skip to content

Commit d28aa3c

Browse files
joergroedelgregkh
authored andcommitted
x86/boot/compressed/64: Check SEV encryption in the 32-bit boot-path
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 <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 0296c90 commit d28aa3c

File tree

1 file changed

+85
-0
lines changed

1 file changed

+85
-0
lines changed

arch/x86/boot/compressed/head_64.S

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,21 @@ SYM_FUNC_START(startup_32)
172172
*/
173173
call get_sev_encryption_bit
174174
xorl %edx, %edx
175+
#ifdef CONFIG_AMD_MEM_ENCRYPT
175176
testl %eax, %eax
176177
jz 1f
177178
subl $32, %eax /* Encryption bit is always above bit 31 */
178179
bts %eax, %edx /* Set encryption mask for page tables */
180+
/*
181+
* Mark SEV as active in sev_status so that startup32_check_sev_cbit()
182+
* will do a check. The sev_status memory will be fully initialized
183+
* with the contents of MSR_AMD_SEV_STATUS later in
184+
* set_sev_encryption_mask(). For now it is sufficient to know that SEV
185+
* is active.
186+
*/
187+
movl $1, rva(sev_status)(%ebp)
179188
1:
189+
#endif
180190

181191
/* Initialize Page tables to 0 */
182192
leal rva(pgtable)(%ebx), %edi
@@ -261,6 +271,9 @@ SYM_FUNC_START(startup_32)
261271
movl %esi, %edx
262272
1:
263273
#endif
274+
/* Check if the C-bit position is correct when SEV is active */
275+
call startup32_check_sev_cbit
276+
264277
pushl $__KERNEL_CS
265278
pushl %eax
266279

@@ -786,6 +799,78 @@ SYM_DATA_START_LOCAL(loaded_image_proto)
786799
SYM_DATA_END(loaded_image_proto)
787800
#endif
788801

802+
/*
803+
* Check for the correct C-bit position when the startup_32 boot-path is used.
804+
*
805+
* The check makes use of the fact that all memory is encrypted when paging is
806+
* disabled. The function creates 64 bits of random data using the RDRAND
807+
* instruction. RDRAND is mandatory for SEV guests, so always available. If the
808+
* hypervisor violates that the kernel will crash right here.
809+
*
810+
* The 64 bits of random data are stored to a memory location and at the same
811+
* time kept in the %eax and %ebx registers. Since encryption is always active
812+
* when paging is off the random data will be stored encrypted in main memory.
813+
*
814+
* Then paging is enabled. When the C-bit position is correct all memory is
815+
* still mapped encrypted and comparing the register values with memory will
816+
* succeed. An incorrect C-bit position will map all memory unencrypted, so that
817+
* the compare will use the encrypted random data and fail.
818+
*/
819+
__HEAD
820+
.code32
821+
SYM_FUNC_START(startup32_check_sev_cbit)
822+
#ifdef CONFIG_AMD_MEM_ENCRYPT
823+
pushl %eax
824+
pushl %ebx
825+
pushl %ecx
826+
pushl %edx
827+
828+
/* Check for non-zero sev_status */
829+
movl rva(sev_status)(%ebp), %eax
830+
testl %eax, %eax
831+
jz 4f
832+
833+
/*
834+
* Get two 32-bit random values - Don't bail out if RDRAND fails
835+
* because it is better to prevent forward progress if no random value
836+
* can be gathered.
837+
*/
838+
1: rdrand %eax
839+
jnc 1b
840+
2: rdrand %ebx
841+
jnc 2b
842+
843+
/* Store to memory and keep it in the registers */
844+
movl %eax, rva(sev_check_data)(%ebp)
845+
movl %ebx, rva(sev_check_data+4)(%ebp)
846+
847+
/* Enable paging to see if encryption is active */
848+
movl %cr0, %edx /* Backup %cr0 in %edx */
849+
movl $(X86_CR0_PG | X86_CR0_PE), %ecx /* Enable Paging and Protected mode */
850+
movl %ecx, %cr0
851+
852+
cmpl %eax, rva(sev_check_data)(%ebp)
853+
jne 3f
854+
cmpl %ebx, rva(sev_check_data+4)(%ebp)
855+
jne 3f
856+
857+
movl %edx, %cr0 /* Restore previous %cr0 */
858+
859+
jmp 4f
860+
861+
3: /* Check failed - hlt the machine */
862+
hlt
863+
jmp 3b
864+
865+
4:
866+
popl %edx
867+
popl %ecx
868+
popl %ebx
869+
popl %eax
870+
#endif
871+
ret
872+
SYM_FUNC_END(startup32_check_sev_cbit)
873+
789874
/*
790875
* Stack and heap for uncompression
791876
*/

0 commit comments

Comments
 (0)