x86/asm/entry: Check for syscall exit work with IRQs disabled
We currently have a race: if we're preempted during syscall
exit, we can fail to process syscall return work that is queued
up while we're preempted in ret_from_sys_call after checking
ti.flags.
Fix it by disabling interrupts before checking ti.flags.
Reported-by: Stefan Seyfried <stefan.seyfried@googlemail.com>
Reported-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Andy Lutomirski <luto@kernel.org>
Acked-by: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Cc: Tejun Heo <tj@kernel.org>
Fixes: 96b6352c12
("x86_64, entry: Remove the syscall exit audit")
Link: http://lkml.kernel.org/r/189320d42b4d671df78c10555976bb10af1ffc75.1427137498.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
parent
bc465aa9d0
commit
b3494a4ab2
1 changed files with 14 additions and 4 deletions
|
@ -364,12 +364,21 @@ system_call_fastpath:
|
||||||
* Has incomplete stack frame and undefined top of stack.
|
* Has incomplete stack frame and undefined top of stack.
|
||||||
*/
|
*/
|
||||||
ret_from_sys_call:
|
ret_from_sys_call:
|
||||||
testl $_TIF_ALLWORK_MASK,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
|
|
||||||
jnz int_ret_from_sys_call_fixup /* Go the the slow path */
|
|
||||||
|
|
||||||
LOCKDEP_SYS_EXIT
|
LOCKDEP_SYS_EXIT
|
||||||
DISABLE_INTERRUPTS(CLBR_NONE)
|
DISABLE_INTERRUPTS(CLBR_NONE)
|
||||||
TRACE_IRQS_OFF
|
TRACE_IRQS_OFF
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We must check ti flags with interrupts (or at least preemption)
|
||||||
|
* off because we must *never* return to userspace without
|
||||||
|
* processing exit work that is enqueued if we're preempted here.
|
||||||
|
* In particular, returning to userspace with any of the one-shot
|
||||||
|
* flags (TIF_NOTIFY_RESUME, TIF_USER_RETURN_NOTIFY, etc) set is
|
||||||
|
* very bad.
|
||||||
|
*/
|
||||||
|
testl $_TIF_ALLWORK_MASK,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
|
||||||
|
jnz int_ret_from_sys_call_fixup /* Go the the slow path */
|
||||||
|
|
||||||
CFI_REMEMBER_STATE
|
CFI_REMEMBER_STATE
|
||||||
/*
|
/*
|
||||||
* sysretq will re-enable interrupts:
|
* sysretq will re-enable interrupts:
|
||||||
|
@ -386,7 +395,7 @@ ret_from_sys_call:
|
||||||
|
|
||||||
int_ret_from_sys_call_fixup:
|
int_ret_from_sys_call_fixup:
|
||||||
FIXUP_TOP_OF_STACK %r11, -ARGOFFSET
|
FIXUP_TOP_OF_STACK %r11, -ARGOFFSET
|
||||||
jmp int_ret_from_sys_call
|
jmp int_ret_from_sys_call_irqs_off
|
||||||
|
|
||||||
/* Do syscall tracing */
|
/* Do syscall tracing */
|
||||||
tracesys:
|
tracesys:
|
||||||
|
@ -432,6 +441,7 @@ tracesys_phase2:
|
||||||
GLOBAL(int_ret_from_sys_call)
|
GLOBAL(int_ret_from_sys_call)
|
||||||
DISABLE_INTERRUPTS(CLBR_NONE)
|
DISABLE_INTERRUPTS(CLBR_NONE)
|
||||||
TRACE_IRQS_OFF
|
TRACE_IRQS_OFF
|
||||||
|
int_ret_from_sys_call_irqs_off:
|
||||||
movl $_TIF_ALLWORK_MASK,%edi
|
movl $_TIF_ALLWORK_MASK,%edi
|
||||||
/* edi: mask to check */
|
/* edi: mask to check */
|
||||||
GLOBAL(int_with_check)
|
GLOBAL(int_with_check)
|
||||||
|
|
Loading…
Reference in a new issue