diff options
| author | Andy Lutomirski <luto@kernel.org> | 2015-03-23 15:32:54 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2015-03-24 16:08:28 -0400 |
| commit | b3494a4ab20f6bdf74cdf2badf7918bb65ee8a00 (patch) | |
| tree | 2875f99133dd8b019b6aee8d0e81c79428630748 | |
| parent | bc465aa9d045feb0e13b4a8f32cc33c1943f62d6 (diff) | |
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: 96b6352c1271 ("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>
| -rw-r--r-- | arch/x86/kernel/entry_64.S | 18 |
1 files changed, 14 insertions, 4 deletions
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 1d74d161687c..2babb393915e 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
| @@ -364,12 +364,21 @@ system_call_fastpath: | |||
| 364 | * Has incomplete stack frame and undefined top of stack. | 364 | * Has incomplete stack frame and undefined top of stack. |
| 365 | */ | 365 | */ |
| 366 | ret_from_sys_call: | 366 | ret_from_sys_call: |
| 367 | testl $_TIF_ALLWORK_MASK,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET) | ||
| 368 | jnz int_ret_from_sys_call_fixup /* Go the the slow path */ | ||
| 369 | |||
| 370 | LOCKDEP_SYS_EXIT | 367 | LOCKDEP_SYS_EXIT |
| 371 | DISABLE_INTERRUPTS(CLBR_NONE) | 368 | DISABLE_INTERRUPTS(CLBR_NONE) |
| 372 | TRACE_IRQS_OFF | 369 | TRACE_IRQS_OFF |
| 370 | |||
| 371 | /* | ||
| 372 | * We must check ti flags with interrupts (or at least preemption) | ||
| 373 | * off because we must *never* return to userspace without | ||
| 374 | * processing exit work that is enqueued if we're preempted here. | ||
| 375 | * In particular, returning to userspace with any of the one-shot | ||
| 376 | * flags (TIF_NOTIFY_RESUME, TIF_USER_RETURN_NOTIFY, etc) set is | ||
| 377 | * very bad. | ||
| 378 | */ | ||
| 379 | testl $_TIF_ALLWORK_MASK,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET) | ||
| 380 | jnz int_ret_from_sys_call_fixup /* Go the the slow path */ | ||
| 381 | |||
| 373 | CFI_REMEMBER_STATE | 382 | CFI_REMEMBER_STATE |
| 374 | /* | 383 | /* |
| 375 | * sysretq will re-enable interrupts: | 384 | * sysretq will re-enable interrupts: |
| @@ -386,7 +395,7 @@ ret_from_sys_call: | |||
| 386 | 395 | ||
| 387 | int_ret_from_sys_call_fixup: | 396 | int_ret_from_sys_call_fixup: |
| 388 | FIXUP_TOP_OF_STACK %r11, -ARGOFFSET | 397 | FIXUP_TOP_OF_STACK %r11, -ARGOFFSET |
| 389 | jmp int_ret_from_sys_call | 398 | jmp int_ret_from_sys_call_irqs_off |
| 390 | 399 | ||
| 391 | /* Do syscall tracing */ | 400 | /* Do syscall tracing */ |
| 392 | tracesys: | 401 | tracesys: |
| @@ -432,6 +441,7 @@ tracesys_phase2: | |||
| 432 | GLOBAL(int_ret_from_sys_call) | 441 | GLOBAL(int_ret_from_sys_call) |
| 433 | DISABLE_INTERRUPTS(CLBR_NONE) | 442 | DISABLE_INTERRUPTS(CLBR_NONE) |
| 434 | TRACE_IRQS_OFF | 443 | TRACE_IRQS_OFF |
| 444 | int_ret_from_sys_call_irqs_off: | ||
| 435 | movl $_TIF_ALLWORK_MASK,%edi | 445 | movl $_TIF_ALLWORK_MASK,%edi |
| 436 | /* edi: mask to check */ | 446 | /* edi: mask to check */ |
| 437 | GLOBAL(int_with_check) | 447 | GLOBAL(int_with_check) |
