diff options
author | Andy Lutomirski <luto@kernel.org> | 2015-10-05 20:48:11 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-10-09 03:41:09 -0400 |
commit | a474e67c913d3ebaf02ba9d7835d5299d226c3ed (patch) | |
tree | 6b9ec92426db8a6e453c3748f34eda2f7cd070da | |
parent | 710246df58041106b7de645f4b45770f8a59a269 (diff) |
x86/vdso/compat: Wire up SYSENTER and SYSCSALL for compat userspace
What, you didn't realize that SYSENTER and SYSCALL were actually
the same thing? :)
Unlike the old code, this actually passes the ptrace_syscall_32
test on AMD systems.
Signed-off-by: Andy Lutomirski <luto@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Link: http://lkml.kernel.org/r/b74615af58d785aa02d917213ec64e2022a2c796.1444091585.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/entry/entry_64_compat.S | 90 | ||||
-rw-r--r-- | arch/x86/entry/vdso/vdso32/system_call.S | 8 |
2 files changed, 62 insertions, 36 deletions
diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S index 63ef9fa29002..8f109de51d03 100644 --- a/arch/x86/entry/entry_64_compat.S +++ b/arch/x86/entry/entry_64_compat.S | |||
@@ -52,15 +52,18 @@ ENTRY(entry_SYSENTER_compat) | |||
52 | SWAPGS_UNSAFE_STACK | 52 | SWAPGS_UNSAFE_STACK |
53 | movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp | 53 | movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp |
54 | 54 | ||
55 | /* Zero-extending 32-bit regs, do not remove */ | 55 | /* |
56 | movl %ebp, %ebp | 56 | * User tracing code (ptrace or signal handlers) might assume that |
57 | * the saved RAX contains a 32-bit number when we're invoking a 32-bit | ||
58 | * syscall. Just in case the high bits are nonzero, zero-extend | ||
59 | * the syscall number. (This could almost certainly be deleted | ||
60 | * with no ill effects.) | ||
61 | */ | ||
57 | movl %eax, %eax | 62 | movl %eax, %eax |
58 | 63 | ||
59 | movl ASM_THREAD_INFO(TI_sysenter_return, %rsp, 0), %r10d | ||
60 | |||
61 | /* Construct struct pt_regs on stack */ | 64 | /* Construct struct pt_regs on stack */ |
62 | pushq $__USER32_DS /* pt_regs->ss */ | 65 | pushq $__USER32_DS /* pt_regs->ss */ |
63 | pushq %rbp /* pt_regs->sp */ | 66 | pushq %rcx /* pt_regs->sp */ |
64 | 67 | ||
65 | /* | 68 | /* |
66 | * Push flags. This is nasty. First, interrupts are currently | 69 | * Push flags. This is nasty. First, interrupts are currently |
@@ -70,17 +73,28 @@ ENTRY(entry_SYSENTER_compat) | |||
70 | */ | 73 | */ |
71 | pushfq /* pt_regs->flags (except IF = 0) */ | 74 | pushfq /* pt_regs->flags (except IF = 0) */ |
72 | orl $X86_EFLAGS_IF, (%rsp) /* Fix saved flags */ | 75 | orl $X86_EFLAGS_IF, (%rsp) /* Fix saved flags */ |
76 | ASM_CLAC /* Clear AC after saving FLAGS */ | ||
73 | 77 | ||
74 | pushq $__USER32_CS /* pt_regs->cs */ | 78 | pushq $__USER32_CS /* pt_regs->cs */ |
75 | pushq %r10 /* pt_regs->ip = thread_info->sysenter_return */ | 79 | xorq %r8,%r8 |
80 | pushq %r8 /* pt_regs->ip = 0 (placeholder) */ | ||
76 | pushq %rax /* pt_regs->orig_ax */ | 81 | pushq %rax /* pt_regs->orig_ax */ |
77 | pushq %rdi /* pt_regs->di */ | 82 | pushq %rdi /* pt_regs->di */ |
78 | pushq %rsi /* pt_regs->si */ | 83 | pushq %rsi /* pt_regs->si */ |
79 | pushq %rdx /* pt_regs->dx */ | 84 | pushq %rdx /* pt_regs->dx */ |
80 | pushq %rcx /* pt_regs->cx */ | 85 | pushq %rcx /* pt_regs->cx (will be overwritten) */ |
81 | pushq $-ENOSYS /* pt_regs->ax */ | 86 | pushq $-ENOSYS /* pt_regs->ax */ |
87 | pushq %r8 /* pt_regs->r8 = 0 */ | ||
88 | pushq %r8 /* pt_regs->r9 = 0 */ | ||
89 | pushq %r8 /* pt_regs->r10 = 0 */ | ||
90 | pushq %r8 /* pt_regs->r11 = 0 */ | ||
91 | pushq %rbx /* pt_regs->rbx */ | ||
92 | pushq %rbp /* pt_regs->rbp */ | ||
93 | pushq %r8 /* pt_regs->r12 = 0 */ | ||
94 | pushq %r8 /* pt_regs->r13 = 0 */ | ||
95 | pushq %r8 /* pt_regs->r14 = 0 */ | ||
96 | pushq %r8 /* pt_regs->r15 = 0 */ | ||
82 | cld | 97 | cld |
83 | sub $(10*8), %rsp /* pt_regs->r8-11, bp, bx, r12-15 not saved */ | ||
84 | 98 | ||
85 | /* | 99 | /* |
86 | * Sysenter doesn't filter flags, so we need to clear NT | 100 | * Sysenter doesn't filter flags, so we need to clear NT |
@@ -93,16 +107,15 @@ ENTRY(entry_SYSENTER_compat) | |||
93 | jnz sysenter_fix_flags | 107 | jnz sysenter_fix_flags |
94 | sysenter_flags_fixed: | 108 | sysenter_flags_fixed: |
95 | 109 | ||
96 | /* Temporary: SYSENTER is disabled. */ | 110 | /* |
97 | #ifdef CONFIG_CONTEXT_TRACKING | 111 | * User mode is traced as though IRQs are on, and SYSENTER |
98 | call enter_from_user_mode | 112 | * turned them off. |
99 | #endif | 113 | */ |
100 | ENABLE_INTERRUPTS(CLBR_NONE) | 114 | TRACE_IRQS_OFF |
101 | movl $11, %edi | ||
102 | call do_exit | ||
103 | 115 | ||
104 | /* Unreachable. */ | 116 | movq %rsp, %rdi |
105 | ud2 | 117 | call do_fast_syscall_32 |
118 | jmp .Lsyscall_32_done | ||
106 | 119 | ||
107 | sysenter_fix_flags: | 120 | sysenter_fix_flags: |
108 | pushq $X86_EFLAGS_FIXED | 121 | pushq $X86_EFLAGS_FIXED |
@@ -135,26 +148,14 @@ ENDPROC(entry_SYSENTER_compat) | |||
135 | * edi arg5 | 148 | * edi arg5 |
136 | * esp user stack | 149 | * esp user stack |
137 | * 0(%esp) arg6 | 150 | * 0(%esp) arg6 |
138 | * | ||
139 | * This is purely a fast path. For anything complicated we use the int 0x80 | ||
140 | * path below. We set up a complete hardware stack frame to share code | ||
141 | * with the int 0x80 path. | ||
142 | */ | 151 | */ |
143 | ENTRY(entry_SYSCALL_compat) | 152 | ENTRY(entry_SYSCALL_compat) |
144 | /* | 153 | /* Interrupts are off on entry. */ |
145 | * Interrupts are off on entry. | ||
146 | * We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON, | ||
147 | * it is too small to ever cause noticeable irq latency. | ||
148 | */ | ||
149 | SWAPGS_UNSAFE_STACK | 154 | SWAPGS_UNSAFE_STACK |
150 | 155 | ||
151 | /* Temporary: SYSCALL32 is disabled. */ | 156 | /* Stash user ESP and switch to the kernel stack. */ |
152 | movl $-ENOSYS, %eax | ||
153 | USERGS_SYSRET32 | ||
154 | |||
155 | movl %esp, %r8d | 157 | movl %esp, %r8d |
156 | movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp | 158 | movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp |
157 | ENABLE_INTERRUPTS(CLBR_NONE) | ||
158 | 159 | ||
159 | /* Zero-extending 32-bit regs, do not remove */ | 160 | /* Zero-extending 32-bit regs, do not remove */ |
160 | movl %eax, %eax | 161 | movl %eax, %eax |
@@ -169,13 +170,29 @@ ENTRY(entry_SYSCALL_compat) | |||
169 | pushq %rdi /* pt_regs->di */ | 170 | pushq %rdi /* pt_regs->di */ |
170 | pushq %rsi /* pt_regs->si */ | 171 | pushq %rsi /* pt_regs->si */ |
171 | pushq %rdx /* pt_regs->dx */ | 172 | pushq %rdx /* pt_regs->dx */ |
172 | pushq %rbp /* pt_regs->cx */ | 173 | pushq %rcx /* pt_regs->cx (will be overwritten) */ |
173 | movl %ebp, %ecx | ||
174 | pushq $-ENOSYS /* pt_regs->ax */ | 174 | pushq $-ENOSYS /* pt_regs->ax */ |
175 | sub $(10*8), %rsp /* pt_regs->r8-11, bp, bx, r12-15 not saved */ | 175 | xorq %r8,%r8 |
176 | pushq %r8 /* pt_regs->r8 = 0 */ | ||
177 | pushq %r8 /* pt_regs->r9 = 0 */ | ||
178 | pushq %r8 /* pt_regs->r10 = 0 */ | ||
179 | pushq %r8 /* pt_regs->r11 = 0 */ | ||
180 | pushq %rbx /* pt_regs->rbx */ | ||
181 | pushq %rbp /* pt_regs->rbp */ | ||
182 | pushq %r8 /* pt_regs->r12 = 0 */ | ||
183 | pushq %r8 /* pt_regs->r13 = 0 */ | ||
184 | pushq %r8 /* pt_regs->r14 = 0 */ | ||
185 | pushq %r8 /* pt_regs->r15 = 0 */ | ||
176 | 186 | ||
177 | /* Unreachable. */ | 187 | /* |
178 | ud2 | 188 | * User mode is traced as though IRQs are on, and SYSENTER |
189 | * turned them off. | ||
190 | */ | ||
191 | TRACE_IRQS_OFF | ||
192 | |||
193 | movq %rsp, %rdi | ||
194 | call do_fast_syscall_32 | ||
195 | jmp .Lsyscall_32_done | ||
179 | END(entry_SYSCALL_compat) | 196 | END(entry_SYSCALL_compat) |
180 | 197 | ||
181 | /* | 198 | /* |
@@ -243,6 +260,7 @@ ENTRY(entry_INT80_compat) | |||
243 | 260 | ||
244 | movq %rsp, %rdi | 261 | movq %rsp, %rdi |
245 | call do_int80_syscall_32 | 262 | call do_int80_syscall_32 |
263 | .Lsyscall_32_done: | ||
246 | 264 | ||
247 | /* Go back to user mode. */ | 265 | /* Go back to user mode. */ |
248 | TRACE_IRQS_ON | 266 | TRACE_IRQS_ON |
diff --git a/arch/x86/entry/vdso/vdso32/system_call.S b/arch/x86/entry/vdso/vdso32/system_call.S index d591fe93e93a..00157cae71e0 100644 --- a/arch/x86/entry/vdso/vdso32/system_call.S +++ b/arch/x86/entry/vdso/vdso32/system_call.S | |||
@@ -3,6 +3,8 @@ | |||
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include <asm/dwarf2.h> | 5 | #include <asm/dwarf2.h> |
6 | #include <asm/cpufeature.h> | ||
7 | #include <asm/alternative-asm.h> | ||
6 | 8 | ||
7 | /* | 9 | /* |
8 | * First get the common code for the sigreturn entry points. | 10 | * First get the common code for the sigreturn entry points. |
@@ -28,6 +30,12 @@ __kernel_vsyscall: | |||
28 | CFI_REL_OFFSET ecx, 0 | 30 | CFI_REL_OFFSET ecx, 0 |
29 | movl %esp, %ecx | 31 | movl %esp, %ecx |
30 | 32 | ||
33 | #ifdef CONFIG_X86_64 | ||
34 | /* If SYSENTER (Intel) or SYSCALL32 (AMD) is available, use it. */ | ||
35 | ALTERNATIVE_2 "", "sysenter", X86_FEATURE_SYSENTER32, \ | ||
36 | "syscall", X86_FEATURE_SYSCALL32 | ||
37 | #endif | ||
38 | |||
31 | /* Enter using int $0x80 */ | 39 | /* Enter using int $0x80 */ |
32 | movl (%esp), %ecx | 40 | movl (%esp), %ecx |
33 | int $0x80 | 41 | int $0x80 |