Commit a1a338e5 authored by Andy Lutomirski's avatar Andy Lutomirski Committed by Peter Zijlstra

x86/entry/32: Unwind the ESPFIX stack earlier on exception entry

Right now, we do some fancy parts of the exception entry path while SS
might have a nonzero base: we fill in regs->ss and regs->sp, and we
consider switching to the kernel stack. This results in regs->ss and
regs->sp referring to a non-flat stack and it may result in
overflowing the entry stack. The former issue means that we can try to
call iret_exc on a non-flat stack, which doesn't work.

Tested with selftests/x86/sigreturn_32.

Fixes: 45d7b255 ("x86/entry/32: Enter the kernel via trampoline stack")
Signed-off-by: default avatarAndy Lutomirski <luto@kernel.org>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: stable@kernel.org
parent 82cb8a0b
...@@ -210,8 +210,6 @@ ...@@ -210,8 +210,6 @@
/* /*
* The high bits of the CS dword (__csh) are used for CS_FROM_*. * The high bits of the CS dword (__csh) are used for CS_FROM_*.
* Clear them in case hardware didn't do this for us. * Clear them in case hardware didn't do this for us.
*
* Be careful: we may have nonzero SS base due to ESPFIX.
*/ */
andl $0x0000ffff, 4*4(%esp) andl $0x0000ffff, 4*4(%esp)
...@@ -307,12 +305,21 @@ ...@@ -307,12 +305,21 @@
.Lfinished_frame_\@: .Lfinished_frame_\@:
.endm .endm
.macro SAVE_ALL pt_regs_ax=%eax switch_stacks=0 skip_gs=0 .macro SAVE_ALL pt_regs_ax=%eax switch_stacks=0 skip_gs=0 unwind_espfix=0
cld cld
.if \skip_gs == 0 .if \skip_gs == 0
PUSH_GS PUSH_GS
.endif .endif
pushl %fs pushl %fs
pushl %eax
movl $(__KERNEL_PERCPU), %eax
movl %eax, %fs
.if \unwind_espfix > 0
UNWIND_ESPFIX_STACK
.endif
popl %eax
FIXUP_FRAME FIXUP_FRAME
pushl %es pushl %es
pushl %ds pushl %ds
...@@ -326,8 +333,6 @@ ...@@ -326,8 +333,6 @@
movl $(__USER_DS), %edx movl $(__USER_DS), %edx
movl %edx, %ds movl %edx, %ds
movl %edx, %es movl %edx, %es
movl $(__KERNEL_PERCPU), %edx
movl %edx, %fs
.if \skip_gs == 0 .if \skip_gs == 0
SET_KERNEL_GS %edx SET_KERNEL_GS %edx
.endif .endif
...@@ -1153,18 +1158,17 @@ ENDPROC(entry_INT80_32) ...@@ -1153,18 +1158,17 @@ ENDPROC(entry_INT80_32)
lss (%esp), %esp /* switch to the normal stack segment */ lss (%esp), %esp /* switch to the normal stack segment */
#endif #endif
.endm .endm
.macro UNWIND_ESPFIX_STACK .macro UNWIND_ESPFIX_STACK
/* It's safe to clobber %eax, all other regs need to be preserved */
#ifdef CONFIG_X86_ESPFIX32 #ifdef CONFIG_X86_ESPFIX32
movl %ss, %eax movl %ss, %eax
/* see if on espfix stack */ /* see if on espfix stack */
cmpw $__ESPFIX_SS, %ax cmpw $__ESPFIX_SS, %ax
jne 27f jne .Lno_fixup_\@
movl $__KERNEL_DS, %eax
movl %eax, %ds
movl %eax, %es
/* switch to normal stack */ /* switch to normal stack */
FIXUP_ESPFIX_STACK FIXUP_ESPFIX_STACK
27: .Lno_fixup_\@:
#endif #endif
.endm .endm
...@@ -1458,10 +1462,9 @@ END(page_fault) ...@@ -1458,10 +1462,9 @@ END(page_fault)
common_exception_read_cr2: common_exception_read_cr2:
/* the function address is in %gs's slot on the stack */ /* the function address is in %gs's slot on the stack */
SAVE_ALL switch_stacks=1 skip_gs=1 SAVE_ALL switch_stacks=1 skip_gs=1 unwind_espfix=1
ENCODE_FRAME_POINTER ENCODE_FRAME_POINTER
UNWIND_ESPFIX_STACK
/* fixup %gs */ /* fixup %gs */
GS_TO_REG %ecx GS_TO_REG %ecx
...@@ -1483,9 +1486,8 @@ END(common_exception_read_cr2) ...@@ -1483,9 +1486,8 @@ END(common_exception_read_cr2)
common_exception: common_exception:
/* the function address is in %gs's slot on the stack */ /* the function address is in %gs's slot on the stack */
SAVE_ALL switch_stacks=1 skip_gs=1 SAVE_ALL switch_stacks=1 skip_gs=1 unwind_espfix=1
ENCODE_FRAME_POINTER ENCODE_FRAME_POINTER
UNWIND_ESPFIX_STACK
/* fixup %gs */ /* fixup %gs */
GS_TO_REG %ecx GS_TO_REG %ecx
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment