Skip to content

Commit 4a13b0e

Browse files
amlutoIngo Molnar
authored andcommitted
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: Borislav Petkov <[email protected]> Signed-off-by: Andy Lutomirski <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: <[email protected]> Signed-off-by: Ingo Molnar <[email protected]>
1 parent 05b042a commit 4a13b0e

File tree

1 file changed

+18
-3
lines changed

1 file changed

+18
-3
lines changed

arch/x86/entry/entry_32.S

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,8 @@
415415

416416
.macro CHECK_AND_APPLY_ESPFIX
417417
#ifdef CONFIG_X86_ESPFIX32
418-
#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + (GDT_ENTRY_ESPFIX_SS * 8)
418+
#define GDT_ESPFIX_OFFSET (GDT_ENTRY_ESPFIX_SS * 8)
419+
#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + GDT_ESPFIX_OFFSET
419420

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

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

0 commit comments

Comments
 (0)