aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@kernel.org>2015-12-17 02:18:48 -0500
committerThomas Gleixner <tglx@linutronix.de>2015-12-21 10:05:01 -0500
commit30bfa7b3488bfb1bb75c9f50a5fcac1832970c60 (patch)
treeaf1e7d3bb55f826b936c7a292b8f0f389b641222
parent6a613ac6bc015f8ef75806d397d69dbac4a8d8c4 (diff)
x86/entry: Restore traditional SYSENTER calling convention
It turns out that some Android versions hardcode the SYSENTER calling convention. This is buggy and will cause problems no matter what the kernel does. Nonetheless, we should try to support it. Credit goes to Linus for pointing out a clean way to handle the SYSENTER/SYSCALL clobber differences while preserving straightforward DWARF annotations. I believe that the original offending Android commit was: https://android.googlesource.com/platform%2Fbionic/+/7dc3684d7a2587e43e6d2a8e0e3f39bf759bd535 Reported-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com> Signed-off-by: Andy Lutomirski <luto@kernel.org> Reviewed-and-tested-by: Borislav Petkov <bp@alien8.de> Cc: <mark.gross@intel.com> Cc: Su Tao <tao.su@intel.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: <frank.wang@intel.com> Cc: <borun.fu@intel.com> Cc: Brian Gerst <brgerst@gmail.com> Cc: Mingwei Shi <mingwei.shi@intel.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/entry/common.c6
-rw-r--r--arch/x86/entry/entry_32.S2
-rw-r--r--arch/x86/entry/entry_64_compat.S10
-rw-r--r--arch/x86/entry/vdso/vdso32/system_call.S52
4 files changed, 51 insertions, 19 deletions
diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c
index a89fdbc1f0be..03663740c866 100644
--- a/arch/x86/entry/common.c
+++ b/arch/x86/entry/common.c
@@ -421,7 +421,7 @@ __visible long do_fast_syscall_32(struct pt_regs *regs)
421 regs->ip = landing_pad; 421 regs->ip = landing_pad;
422 422
423 /* 423 /*
424 * Fetch ECX from where the vDSO stashed it. 424 * Fetch EBP from where the vDSO stashed it.
425 * 425 *
426 * WARNING: We are in CONTEXT_USER and RCU isn't paying attention! 426 * WARNING: We are in CONTEXT_USER and RCU isn't paying attention!
427 */ 427 */
@@ -432,10 +432,10 @@ __visible long do_fast_syscall_32(struct pt_regs *regs)
432 * Micro-optimization: the pointer we're following is explicitly 432 * Micro-optimization: the pointer we're following is explicitly
433 * 32 bits, so it can't be out of range. 433 * 32 bits, so it can't be out of range.
434 */ 434 */
435 __get_user(*(u32 *)&regs->cx, 435 __get_user(*(u32 *)&regs->bp,
436 (u32 __user __force *)(unsigned long)(u32)regs->sp) 436 (u32 __user __force *)(unsigned long)(u32)regs->sp)
437#else 437#else
438 get_user(*(u32 *)&regs->cx, 438 get_user(*(u32 *)&regs->bp,
439 (u32 __user __force *)(unsigned long)(u32)regs->sp) 439 (u32 __user __force *)(unsigned long)(u32)regs->sp)
440#endif 440#endif
441 ) { 441 ) {
diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S
index fcad8ac30a8e..f3b6d54e0042 100644
--- a/arch/x86/entry/entry_32.S
+++ b/arch/x86/entry/entry_32.S
@@ -292,7 +292,7 @@ ENTRY(entry_SYSENTER_32)
292 movl TSS_sysenter_sp0(%esp), %esp 292 movl TSS_sysenter_sp0(%esp), %esp
293sysenter_past_esp: 293sysenter_past_esp:
294 pushl $__USER_DS /* pt_regs->ss */ 294 pushl $__USER_DS /* pt_regs->ss */
295 pushl %ecx /* pt_regs->sp (stashed in cx) */ 295 pushl %ebp /* pt_regs->sp (stashed in bp) */
296 pushfl /* pt_regs->flags (except IF = 0) */ 296 pushfl /* pt_regs->flags (except IF = 0) */
297 orl $X86_EFLAGS_IF, (%esp) /* Fix IF */ 297 orl $X86_EFLAGS_IF, (%esp) /* Fix IF */
298 pushl $__USER_CS /* pt_regs->cs */ 298 pushl $__USER_CS /* pt_regs->cs */
diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S
index 402e34a21559..6a1ae3751e82 100644
--- a/arch/x86/entry/entry_64_compat.S
+++ b/arch/x86/entry/entry_64_compat.S
@@ -63,7 +63,7 @@ ENTRY(entry_SYSENTER_compat)
63 63
64 /* Construct struct pt_regs on stack */ 64 /* Construct struct pt_regs on stack */
65 pushq $__USER32_DS /* pt_regs->ss */ 65 pushq $__USER32_DS /* pt_regs->ss */
66 pushq %rcx /* pt_regs->sp */ 66 pushq %rbp /* pt_regs->sp (stashed in bp) */
67 67
68 /* 68 /*
69 * Push flags. This is nasty. First, interrupts are currently 69 * Push flags. This is nasty. First, interrupts are currently
@@ -82,14 +82,14 @@ ENTRY(entry_SYSENTER_compat)
82 pushq %rdi /* pt_regs->di */ 82 pushq %rdi /* pt_regs->di */
83 pushq %rsi /* pt_regs->si */ 83 pushq %rsi /* pt_regs->si */
84 pushq %rdx /* pt_regs->dx */ 84 pushq %rdx /* pt_regs->dx */
85 pushq %rcx /* pt_regs->cx (will be overwritten) */ 85 pushq %rcx /* pt_regs->cx */
86 pushq $-ENOSYS /* pt_regs->ax */ 86 pushq $-ENOSYS /* pt_regs->ax */
87 pushq %r8 /* pt_regs->r8 = 0 */ 87 pushq %r8 /* pt_regs->r8 = 0 */
88 pushq %r8 /* pt_regs->r9 = 0 */ 88 pushq %r8 /* pt_regs->r9 = 0 */
89 pushq %r8 /* pt_regs->r10 = 0 */ 89 pushq %r8 /* pt_regs->r10 = 0 */
90 pushq %r8 /* pt_regs->r11 = 0 */ 90 pushq %r8 /* pt_regs->r11 = 0 */
91 pushq %rbx /* pt_regs->rbx */ 91 pushq %rbx /* pt_regs->rbx */
92 pushq %rbp /* pt_regs->rbp */ 92 pushq %rbp /* pt_regs->rbp (will be overwritten) */
93 pushq %r8 /* pt_regs->r12 = 0 */ 93 pushq %r8 /* pt_regs->r12 = 0 */
94 pushq %r8 /* pt_regs->r13 = 0 */ 94 pushq %r8 /* pt_regs->r13 = 0 */
95 pushq %r8 /* pt_regs->r14 = 0 */ 95 pushq %r8 /* pt_regs->r14 = 0 */
@@ -179,7 +179,7 @@ ENTRY(entry_SYSCALL_compat)
179 pushq %rdi /* pt_regs->di */ 179 pushq %rdi /* pt_regs->di */
180 pushq %rsi /* pt_regs->si */ 180 pushq %rsi /* pt_regs->si */
181 pushq %rdx /* pt_regs->dx */ 181 pushq %rdx /* pt_regs->dx */
182 pushq %rcx /* pt_regs->cx (will be overwritten) */ 182 pushq %rbp /* pt_regs->cx (stashed in bp) */
183 pushq $-ENOSYS /* pt_regs->ax */ 183 pushq $-ENOSYS /* pt_regs->ax */
184 xorq %r8,%r8 184 xorq %r8,%r8
185 pushq %r8 /* pt_regs->r8 = 0 */ 185 pushq %r8 /* pt_regs->r8 = 0 */
@@ -187,7 +187,7 @@ ENTRY(entry_SYSCALL_compat)
187 pushq %r8 /* pt_regs->r10 = 0 */ 187 pushq %r8 /* pt_regs->r10 = 0 */
188 pushq %r8 /* pt_regs->r11 = 0 */ 188 pushq %r8 /* pt_regs->r11 = 0 */
189 pushq %rbx /* pt_regs->rbx */ 189 pushq %rbx /* pt_regs->rbx */
190 pushq %rbp /* pt_regs->rbp */ 190 pushq %rbp /* pt_regs->rbp (will be overwritten) */
191 pushq %r8 /* pt_regs->r12 = 0 */ 191 pushq %r8 /* pt_regs->r12 = 0 */
192 pushq %r8 /* pt_regs->r13 = 0 */ 192 pushq %r8 /* pt_regs->r13 = 0 */
193 pushq %r8 /* pt_regs->r14 = 0 */ 193 pushq %r8 /* pt_regs->r14 = 0 */
diff --git a/arch/x86/entry/vdso/vdso32/system_call.S b/arch/x86/entry/vdso/vdso32/system_call.S
index 8f42b1b9e8df..3a1d9297074b 100644
--- a/arch/x86/entry/vdso/vdso32/system_call.S
+++ b/arch/x86/entry/vdso/vdso32/system_call.S
@@ -21,35 +21,67 @@ __kernel_vsyscall:
21 /* 21 /*
22 * Reshuffle regs so that all of any of the entry instructions 22 * Reshuffle regs so that all of any of the entry instructions
23 * will preserve enough state. 23 * will preserve enough state.
24 *
25 * A really nice entry sequence would be:
26 * pushl %edx
27 * pushl %ecx
28 * movl %esp, %ecx
29 *
30 * Unfortunately, naughty Android versions between July and December
31 * 2015 actually hardcode the traditional Linux SYSENTER entry
32 * sequence. That is severely broken for a number of reasons (ask
33 * anyone with an AMD CPU, for example). Nonetheless, we try to keep
34 * it working approximately as well as it ever worked.
35 *
36 * This link may eludicate some of the history:
37 * https://android-review.googlesource.com/#/q/Iac3295376d61ef83e713ac9b528f3b50aa780cd7
38 * personally, I find it hard to understand what's going on there.
39 *
40 * Note to future user developers: DO NOT USE SYSENTER IN YOUR CODE.
41 * Execute an indirect call to the address in the AT_SYSINFO auxv
42 * entry. That is the ONLY correct way to make a fast 32-bit system
43 * call on Linux. (Open-coding int $0x80 is also fine, but it's
44 * slow.)
24 */ 45 */
46 pushl %ecx
47 CFI_ADJUST_CFA_OFFSET 4
48 CFI_REL_OFFSET ecx, 0
25 pushl %edx 49 pushl %edx
26 CFI_ADJUST_CFA_OFFSET 4 50 CFI_ADJUST_CFA_OFFSET 4
27 CFI_REL_OFFSET edx, 0 51 CFI_REL_OFFSET edx, 0
28 pushl %ecx 52 pushl %ebp
29 CFI_ADJUST_CFA_OFFSET 4 53 CFI_ADJUST_CFA_OFFSET 4
30 CFI_REL_OFFSET ecx, 0 54 CFI_REL_OFFSET ebp, 0
31 movl %esp, %ecx 55
56 #define SYSENTER_SEQUENCE "movl %esp, %ebp; sysenter"
57 #define SYSCALL_SEQUENCE "movl %ecx, %ebp; syscall"
32 58
33#ifdef CONFIG_X86_64 59#ifdef CONFIG_X86_64
34 /* If SYSENTER (Intel) or SYSCALL32 (AMD) is available, use it. */ 60 /* If SYSENTER (Intel) or SYSCALL32 (AMD) is available, use it. */
35 ALTERNATIVE_2 "", "sysenter", X86_FEATURE_SYSENTER32, \ 61 ALTERNATIVE_2 "", SYSENTER_SEQUENCE, X86_FEATURE_SYSENTER32, \
36 "syscall", X86_FEATURE_SYSCALL32 62 SYSCALL_SEQUENCE, X86_FEATURE_SYSCALL32
37#else 63#else
38 ALTERNATIVE "", "sysenter", X86_FEATURE_SEP 64 ALTERNATIVE "", SYSENTER_SEQUENCE, X86_FEATURE_SEP
39#endif 65#endif
40 66
41 /* Enter using int $0x80 */ 67 /* Enter using int $0x80 */
42 movl (%esp), %ecx
43 int $0x80 68 int $0x80
44GLOBAL(int80_landing_pad) 69GLOBAL(int80_landing_pad)
45 70
46 /* Restore ECX and EDX in case they were clobbered. */ 71 /*
47 popl %ecx 72 * Restore EDX and ECX in case they were clobbered. EBP is not
48 CFI_RESTORE ecx 73 * clobbered (the kernel restores it), but it's cleaner and
74 * probably faster to pop it than to adjust ESP using addl.
75 */
76 popl %ebp
77 CFI_RESTORE ebp
49 CFI_ADJUST_CFA_OFFSET -4 78 CFI_ADJUST_CFA_OFFSET -4
50 popl %edx 79 popl %edx
51 CFI_RESTORE edx 80 CFI_RESTORE edx
52 CFI_ADJUST_CFA_OFFSET -4 81 CFI_ADJUST_CFA_OFFSET -4
82 popl %ecx
83 CFI_RESTORE ecx
84 CFI_ADJUST_CFA_OFFSET -4
53 ret 85 ret
54 CFI_ENDPROC 86 CFI_ENDPROC
55 87