Commit 4a13b0e3 authored by Andy Lutomirski's avatar Andy Lutomirski Committed by Ingo Molnar
Browse files

x86/entry/32: Fix FIXUP_ESPFIX_STACK with user CR3



UNWIND_ESPFIX_STACK needs to read the GDT, and the GDT mapping that
can be accessed via %fs is not mapped in the user pagetables.  Use
SGDT to find the cpu_entry_area mapping and read the espfix offset
from that instead.

Reported-and-tested-by: default avatarBorislav Petkov <bp@alien8.de>
Signed-off-by: default avatarAndy Lutomirski <luto@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 05b042a1
Loading
Loading
Loading
Loading
+18 −3
Original line number Diff line number Diff line
@@ -415,7 +415,8 @@

.macro CHECK_AND_APPLY_ESPFIX
#ifdef CONFIG_X86_ESPFIX32
#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + (GDT_ENTRY_ESPFIX_SS * 8)
#define GDT_ESPFIX_OFFSET (GDT_ENTRY_ESPFIX_SS * 8)
#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + GDT_ESPFIX_OFFSET

	ALTERNATIVE	"jmp .Lend_\@", "", X86_BUG_ESPFIX

@@ -1147,12 +1148,26 @@ ENDPROC(entry_INT80_32)
 * We can't call C functions using the ESPFIX stack. This code reads
 * the high word of the segment base from the GDT and swiches to the
 * normal stack and adjusts ESP with the matching offset.
 *
 * We might be on user CR3 here, so percpu data is not mapped and we can't
 * access the GDT through the percpu segment.  Instead, use SGDT to find
 * the cpu_entry_area alias of the GDT.
 */
#ifdef CONFIG_X86_ESPFIX32
	/* fixup the stack */
	mov	GDT_ESPFIX_SS + 4, %al /* bits 16..23 */
	mov	GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */
	pushl	%ecx
	subl	$2*4, %esp
	sgdt	(%esp)
	movl	2(%esp), %ecx				/* GDT address */
	/*
	 * Careful: ECX is a linear pointer, so we need to force base
	 * zero.  %cs is the only known-linear segment we have right now.
	 */
	mov	%cs:GDT_ESPFIX_OFFSET + 4(%ecx), %al	/* bits 16..23 */
	mov	%cs:GDT_ESPFIX_OFFSET + 7(%ecx), %ah	/* bits 24..31 */
	shl	$16, %eax
	addl	$2*4, %esp
	popl	%ecx
	addl	%esp, %eax			/* the adjusted stack pointer */
	pushl	$__KERNEL_DS
	pushl	%eax