aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/include
diff options
context:
space:
mode:
authorBrian Gerst <brgerst@gmail.com>2015-03-21 18:54:21 -0400
committerIngo Molnar <mingo@kernel.org>2015-03-23 03:52:46 -0400
commit1daeaa315164c60b937f56fe3848d4328c358eba (patch)
tree07db9e9d5b52cc23c2a839a597832136afca2c24 /arch/x86/include
parentc38e503804b0402c510f82437069f7769fa0cea9 (diff)
x86/asm/entry: Fix execve() and sigreturn() syscalls to always return via IRET
Both the execve() and sigreturn() family of syscalls have the ability to change registers in ways that may not be compatabile with the syscall path they were called from. In particular, SYSRET and SYSEXIT can't handle non-default %cs and %ss, and some bits in eflags. These syscalls have stubs that are hardcoded to jump to the IRET path, and not return to the original syscall path. The following commit: 76f5df43cab5e76 ("Always allocate a complete "struct pt_regs" on the kernel stack") recently changed this for some 32-bit compat syscalls, but introduced a bug where execve from a 32-bit program to a 64-bit program would fail because it still returned via SYSRETL. This caused Wine to fail when built for both 32-bit and 64-bit. This patch sets TIF_NOTIFY_RESUME for execve() and sigreturn() so that the IRET path is always taken on exit to userspace. Signed-off-by: Brian Gerst <brgerst@gmail.com> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Borislav Petkov <bp@alien8.de> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Link: http://lkml.kernel.org/r/1426978461-32089-1-git-send-email-brgerst@gmail.com [ Improved the changelog and comments. ] Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/include')
-rw-r--r--arch/x86/include/asm/ptrace.h2
-rw-r--r--arch/x86/include/asm/thread_info.h10
2 files changed, 11 insertions, 1 deletions
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
index 74bb2e0f3030..83b874da2762 100644
--- a/arch/x86/include/asm/ptrace.h
+++ b/arch/x86/include/asm/ptrace.h
@@ -251,7 +251,7 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
251 */ 251 */
252#define arch_ptrace_stop_needed(code, info) \ 252#define arch_ptrace_stop_needed(code, info) \
253({ \ 253({ \
254 set_thread_flag(TIF_NOTIFY_RESUME); \ 254 force_iret(); \
255 false; \ 255 false; \
256}) 256})
257 257
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index ba115eb6fbcf..0abf7ab20ce2 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -260,6 +260,16 @@ static inline bool is_ia32_task(void)
260#endif 260#endif
261 return false; 261 return false;
262} 262}
263
264/*
265 * Force syscall return via IRET by making it look as if there was
266 * some work pending. IRET is our most capable (but slowest) syscall
267 * return path, which is able to restore modified SS, CS and certain
268 * EFLAGS values that other (fast) syscall return instructions
269 * are not able to restore properly.
270 */
271#define force_iret() set_thread_flag(TIF_NOTIFY_RESUME)
272
263#endif /* !__ASSEMBLY__ */ 273#endif /* !__ASSEMBLY__ */
264 274
265#ifndef __ASSEMBLY__ 275#ifndef __ASSEMBLY__