Patch "x86/decompressor: Don't rely on upper 32 bits of GPRs being preserved" has been added to the 5.4-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    x86/decompressor: Don't rely on upper 32 bits of GPRs being preserved

to the 5.4-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     x86-decompressor-don-t-rely-on-upper-32-bits-of-gprs.patch
and it can be found in the queue-5.4 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 6fd234885c819b460c628881f1392480c7771002
Author: Ard Biesheuvel <ardb@xxxxxxxxxx>
Date:   Mon Aug 7 18:26:58 2023 +0200

    x86/decompressor: Don't rely on upper 32 bits of GPRs being preserved
    
    [ Upstream commit 264b82fdb4989cf6a44a2bcd0c6ea05e8026b2ac ]
    
    The 4-to-5 level mode switch trampoline disables long mode and paging in
    order to be able to flick the LA57 bit. According to section 3.4.1.1 of
    the x86 architecture manual [0], 64-bit GPRs might not retain the upper
    32 bits of their contents across such a mode switch.
    
    Given that RBP, RBX and RSI are live at this point, preserve them on the
    stack, along with the return address that might be above 4G as well.
    
    [0] Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1: Basic Architecture
    
      "Because the upper 32 bits of 64-bit general-purpose registers are
       undefined in 32-bit modes, the upper 32 bits of any general-purpose
       register are not preserved when switching from 64-bit mode to a 32-bit
       mode (to protected mode or compatibility mode). Software must not
       depend on these bits to maintain a value after a 64-bit to 32-bit
       mode switch."
    
    Fixes: 194a9749c73d650c ("x86/boot/compressed/64: Handle 5-level paging boot if kernel is above 4G")
    Signed-off-by: Ard Biesheuvel <ardb@xxxxxxxxxx>
    Signed-off-by: Borislav Petkov (AMD) <bp@xxxxxxxxx>
    Link: https://lore.kernel.org/r/20230807162720.545787-2-ardb@xxxxxxxxxx
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index 95ee795d97964..d8164e6abaaff 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -381,11 +381,25 @@ ENTRY(startup_64)
 	/* Save the trampoline address in RCX */
 	movq	%rax, %rcx
 
+	/* Set up 32-bit addressable stack */
+	leaq	TRAMPOLINE_32BIT_STACK_END(%rcx), %rsp
+
+	/*
+	 * Preserve live 64-bit registers on the stack: this is necessary
+	 * because the architecture does not guarantee that GPRs will retain
+	 * their full 64-bit values across a 32-bit mode switch.
+	 */
+	pushq	%rbp
+	pushq	%rbx
+	pushq	%rsi
+
 	/*
-	 * Load the address of trampoline_return() into RDI.
-	 * It will be used by the trampoline to return to the main code.
+	 * Push the 64-bit address of trampoline_return() onto the new stack.
+	 * It will be used by the trampoline to return to the main code. Due to
+	 * the 32-bit mode switch, it cannot be kept it in a register either.
 	 */
 	leaq	trampoline_return(%rip), %rdi
+	pushq	%rdi
 
 	/* Switch to compatibility mode (CS.L = 0 CS.D = 1) via far return */
 	pushq	$__KERNEL32_CS
@@ -393,6 +407,11 @@ ENTRY(startup_64)
 	pushq	%rax
 	lretq
 trampoline_return:
+	/* Restore live 64-bit registers */
+	popq	%rsi
+	popq	%rbx
+	popq	%rbp
+
 	/* Restore the stack, the 32-bit trampoline uses its own stack */
 	leaq	boot_stack_end(%rbx), %rsp
 
@@ -573,7 +592,7 @@ SYM_FUNC_END(.Lrelocated)
 /*
  * This is the 32-bit trampoline that will be copied over to low memory.
  *
- * RDI contains the return address (might be above 4G).
+ * Return address is at the top of the stack (might be above 4G).
  * ECX contains the base address of the trampoline memory.
  * Non zero RDX means trampoline needs to enable 5-level paging.
  */
@@ -583,9 +602,6 @@ ENTRY(trampoline_32bit_src)
 	movl	%eax, %ds
 	movl	%eax, %ss
 
-	/* Set up new stack */
-	leal	TRAMPOLINE_32BIT_STACK_END(%ecx), %esp
-
 	/* Disable paging */
 	movl	%cr0, %eax
 	btrl	$X86_CR0_PG_BIT, %eax
@@ -644,7 +660,7 @@ ENTRY(trampoline_32bit_src)
 	.code64
 SYM_FUNC_START_LOCAL_NOALIGN(.Lpaging_enabled)
 	/* Return from the trampoline */
-	jmp	*%rdi
+	retq
 SYM_FUNC_END(.Lpaging_enabled)
 
 	/*



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux