]>
Commit | Line | Data |
---|---|---|
321d628a FG |
1 | From e5688fb8c2c243658f3fe754d33c7250c8aed146 Mon Sep 17 00:00:00 2001 |
2 | From: Juergen Gross <jgross@suse.com> | |
3 | Date: Thu, 31 Aug 2017 19:42:49 +0200 | |
e4cdf2a5 | 4 | Subject: [PATCH 029/241] x86/xen: Get rid of paravirt op |
321d628a FG |
5 | adjust_exception_frame |
6 | MIME-Version: 1.0 | |
7 | Content-Type: text/plain; charset=UTF-8 | |
8 | Content-Transfer-Encoding: 8bit | |
9 | ||
10 | CVE-2017-5754 | |
11 | ||
12 | When running as Xen pv-guest the exception frame on the stack contains | |
13 | %r11 and %rcx additional to the other data pushed by the processor. | |
14 | ||
15 | Instead of having a paravirt op being called for each exception type | |
16 | prepend the Xen specific code to each exception entry. When running as | |
17 | Xen pv-guest just use the exception entry with prepended instructions, | |
18 | otherwise use the entry without the Xen specific code. | |
19 | ||
20 | [ tglx: Merged through tip to avoid ugly merge conflict ] | |
21 | ||
22 | Signed-off-by: Juergen Gross <jgross@suse.com> | |
23 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | |
24 | Cc: xen-devel@lists.xenproject.org | |
25 | Cc: boris.ostrovsky@oracle.com | |
26 | Cc: luto@amacapital.net | |
27 | Link: http://lkml.kernel.org/r/20170831174249.26853-1-jg@pfupf.net | |
28 | (backported from commit 5878d5d6fdef6447d73b0acc121ba445bef37f53) | |
29 | Signed-off-by: Andy Whitcroft <apw@canonical.com> | |
30 | Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> | |
31 | (cherry picked from commit 9a6fb927deb3ebbe831741ca82081714637181a7) | |
32 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
33 | --- | |
34 | arch/x86/include/asm/paravirt.h | 5 -- | |
35 | arch/x86/include/asm/paravirt_types.h | 3 -- | |
36 | arch/x86/include/asm/proto.h | 3 ++ | |
37 | arch/x86/include/asm/traps.h | 28 ++++++++-- | |
38 | arch/x86/xen/xen-ops.h | 1 - | |
39 | arch/x86/kernel/asm-offsets_64.c | 1 - | |
40 | arch/x86/kernel/paravirt.c | 3 -- | |
41 | arch/x86/xen/enlighten_pv.c | 98 +++++++++++++++++++++++------------ | |
42 | arch/x86/xen/irq.c | 3 -- | |
43 | arch/x86/entry/entry_64.S | 23 ++------ | |
44 | arch/x86/entry/entry_64_compat.S | 1 - | |
45 | arch/x86/xen/xen-asm_64.S | 41 +++++++++++++-- | |
46 | 12 files changed, 133 insertions(+), 77 deletions(-) | |
47 | ||
48 | diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h | |
49 | index 9ccac1926587..c25dd22f7c70 100644 | |
50 | --- a/arch/x86/include/asm/paravirt.h | |
51 | +++ b/arch/x86/include/asm/paravirt.h | |
52 | @@ -960,11 +960,6 @@ extern void default_banner(void); | |
53 | #define GET_CR2_INTO_RAX \ | |
54 | call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2) | |
55 | ||
56 | -#define PARAVIRT_ADJUST_EXCEPTION_FRAME \ | |
57 | - PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_adjust_exception_frame), \ | |
58 | - CLBR_NONE, \ | |
59 | - call PARA_INDIRECT(pv_irq_ops+PV_IRQ_adjust_exception_frame)) | |
60 | - | |
61 | #define USERGS_SYSRET64 \ | |
62 | PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret64), \ | |
63 | CLBR_NONE, \ | |
64 | diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h | |
65 | index 9ffc36bfe4cd..6b64fc6367f2 100644 | |
66 | --- a/arch/x86/include/asm/paravirt_types.h | |
67 | +++ b/arch/x86/include/asm/paravirt_types.h | |
68 | @@ -196,9 +196,6 @@ struct pv_irq_ops { | |
69 | void (*safe_halt)(void); | |
70 | void (*halt)(void); | |
71 | ||
72 | -#ifdef CONFIG_X86_64 | |
73 | - void (*adjust_exception_frame)(void); | |
74 | -#endif | |
75 | } __no_randomize_layout; | |
76 | ||
77 | struct pv_mmu_ops { | |
78 | diff --git a/arch/x86/include/asm/proto.h b/arch/x86/include/asm/proto.h | |
79 | index 8d3964fc5f91..b408b1886195 100644 | |
80 | --- a/arch/x86/include/asm/proto.h | |
81 | +++ b/arch/x86/include/asm/proto.h | |
82 | @@ -24,6 +24,9 @@ void entry_SYSENTER_compat(void); | |
83 | void __end_entry_SYSENTER_compat(void); | |
84 | void entry_SYSCALL_compat(void); | |
85 | void entry_INT80_compat(void); | |
86 | +#if defined(CONFIG_X86_64) && defined(CONFIG_XEN_PV) | |
87 | +void xen_entry_INT80_compat(void); | |
88 | +#endif | |
89 | #endif | |
90 | ||
91 | void x86_configure_nx(void); | |
92 | diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h | |
93 | index b4f322d6c95f..feb89dbe359d 100644 | |
94 | --- a/arch/x86/include/asm/traps.h | |
95 | +++ b/arch/x86/include/asm/traps.h | |
96 | @@ -13,9 +13,6 @@ asmlinkage void divide_error(void); | |
97 | asmlinkage void debug(void); | |
98 | asmlinkage void nmi(void); | |
99 | asmlinkage void int3(void); | |
100 | -asmlinkage void xen_debug(void); | |
101 | -asmlinkage void xen_int3(void); | |
102 | -asmlinkage void xen_stack_segment(void); | |
103 | asmlinkage void overflow(void); | |
104 | asmlinkage void bounds(void); | |
105 | asmlinkage void invalid_op(void); | |
106 | @@ -56,6 +53,31 @@ asmlinkage void simd_coprocessor_error(void); | |
107 | #define trace_page_fault page_fault | |
108 | #endif | |
109 | ||
110 | +#if defined(CONFIG_X86_64) && defined(CONFIG_XEN_PV) | |
111 | +asmlinkage void xen_divide_error(void); | |
112 | +asmlinkage void xen_xendebug(void); | |
113 | +asmlinkage void xen_xenint3(void); | |
114 | +asmlinkage void xen_nmi(void); | |
115 | +asmlinkage void xen_overflow(void); | |
116 | +asmlinkage void xen_bounds(void); | |
117 | +asmlinkage void xen_invalid_op(void); | |
118 | +asmlinkage void xen_device_not_available(void); | |
119 | +asmlinkage void xen_double_fault(void); | |
120 | +asmlinkage void xen_coprocessor_segment_overrun(void); | |
121 | +asmlinkage void xen_invalid_TSS(void); | |
122 | +asmlinkage void xen_segment_not_present(void); | |
123 | +asmlinkage void xen_stack_segment(void); | |
124 | +asmlinkage void xen_general_protection(void); | |
125 | +asmlinkage void xen_page_fault(void); | |
126 | +asmlinkage void xen_spurious_interrupt_bug(void); | |
127 | +asmlinkage void xen_coprocessor_error(void); | |
128 | +asmlinkage void xen_alignment_check(void); | |
129 | +#ifdef CONFIG_X86_MCE | |
130 | +asmlinkage void xen_machine_check(void); | |
131 | +#endif /* CONFIG_X86_MCE */ | |
132 | +asmlinkage void xen_simd_coprocessor_error(void); | |
133 | +#endif | |
134 | + | |
135 | dotraplinkage void do_divide_error(struct pt_regs *, long); | |
136 | dotraplinkage void do_debug(struct pt_regs *, long); | |
137 | dotraplinkage void do_nmi(struct pt_regs *, long); | |
138 | diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h | |
139 | index 70301ac0d414..c8a6d224f7ed 100644 | |
140 | --- a/arch/x86/xen/xen-ops.h | |
141 | +++ b/arch/x86/xen/xen-ops.h | |
142 | @@ -138,7 +138,6 @@ __visible void xen_restore_fl_direct(unsigned long); | |
143 | __visible void xen_iret(void); | |
144 | __visible void xen_sysret32(void); | |
145 | __visible void xen_sysret64(void); | |
146 | -__visible void xen_adjust_exception_frame(void); | |
147 | ||
148 | extern int xen_panic_handler_init(void); | |
149 | ||
150 | diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c | |
151 | index 99332f550c48..cf42206926af 100644 | |
152 | --- a/arch/x86/kernel/asm-offsets_64.c | |
153 | +++ b/arch/x86/kernel/asm-offsets_64.c | |
154 | @@ -20,7 +20,6 @@ static char syscalls_ia32[] = { | |
155 | int main(void) | |
156 | { | |
157 | #ifdef CONFIG_PARAVIRT | |
158 | - OFFSET(PV_IRQ_adjust_exception_frame, pv_irq_ops, adjust_exception_frame); | |
159 | OFFSET(PV_CPU_usergs_sysret64, pv_cpu_ops, usergs_sysret64); | |
160 | OFFSET(PV_CPU_swapgs, pv_cpu_ops, swapgs); | |
161 | BLANK(); | |
162 | diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c | |
163 | index bc0a849589bb..a14df9eecfed 100644 | |
164 | --- a/arch/x86/kernel/paravirt.c | |
165 | +++ b/arch/x86/kernel/paravirt.c | |
166 | @@ -319,9 +319,6 @@ __visible struct pv_irq_ops pv_irq_ops = { | |
167 | .irq_enable = __PV_IS_CALLEE_SAVE(native_irq_enable), | |
168 | .safe_halt = native_safe_halt, | |
169 | .halt = native_halt, | |
170 | -#ifdef CONFIG_X86_64 | |
171 | - .adjust_exception_frame = paravirt_nop, | |
172 | -#endif | |
173 | }; | |
174 | ||
175 | __visible struct pv_cpu_ops pv_cpu_ops = { | |
176 | diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c | |
177 | index c76f5ff4d0d7..ae2a2e2d6362 100644 | |
178 | --- a/arch/x86/xen/enlighten_pv.c | |
179 | +++ b/arch/x86/xen/enlighten_pv.c | |
180 | @@ -586,6 +586,70 @@ static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum, | |
181 | preempt_enable(); | |
182 | } | |
183 | ||
184 | +#ifdef CONFIG_X86_64 | |
185 | +struct trap_array_entry { | |
186 | + void (*orig)(void); | |
187 | + void (*xen)(void); | |
188 | + bool ist_okay; | |
189 | +}; | |
190 | + | |
191 | +static struct trap_array_entry trap_array[] = { | |
192 | + { debug, xen_xendebug, true }, | |
193 | + { int3, xen_xenint3, true }, | |
194 | + { double_fault, xen_double_fault, true }, | |
195 | +#ifdef CONFIG_X86_MCE | |
196 | + { machine_check, xen_machine_check, true }, | |
197 | +#endif | |
198 | + { nmi, xen_nmi, true }, | |
199 | + { overflow, xen_overflow, false }, | |
200 | +#ifdef CONFIG_IA32_EMULATION | |
201 | + { entry_INT80_compat, xen_entry_INT80_compat, false }, | |
202 | +#endif | |
203 | + { page_fault, xen_page_fault, false }, | |
204 | + { divide_error, xen_divide_error, false }, | |
205 | + { bounds, xen_bounds, false }, | |
206 | + { invalid_op, xen_invalid_op, false }, | |
207 | + { device_not_available, xen_device_not_available, false }, | |
208 | + { coprocessor_segment_overrun, xen_coprocessor_segment_overrun, false }, | |
209 | + { invalid_TSS, xen_invalid_TSS, false }, | |
210 | + { segment_not_present, xen_segment_not_present, false }, | |
211 | + { stack_segment, xen_stack_segment, false }, | |
212 | + { general_protection, xen_general_protection, false }, | |
213 | + { spurious_interrupt_bug, xen_spurious_interrupt_bug, false }, | |
214 | + { coprocessor_error, xen_coprocessor_error, false }, | |
215 | + { alignment_check, xen_alignment_check, false }, | |
216 | + { simd_coprocessor_error, xen_simd_coprocessor_error, false }, | |
217 | +}; | |
218 | + | |
219 | +static bool get_trap_addr(void **addr, unsigned int ist) | |
220 | +{ | |
221 | + unsigned int nr; | |
222 | + bool ist_okay = false; | |
223 | + | |
224 | + /* | |
225 | + * Replace trap handler addresses by Xen specific ones. | |
226 | + * Check for known traps using IST and whitelist them. | |
227 | + * The debugger ones are the only ones we care about. | |
228 | + * Xen will handle faults like double_fault, * so we should never see | |
229 | + * them. Warn if there's an unexpected IST-using fault handler. | |
230 | + */ | |
231 | + for (nr = 0; nr < ARRAY_SIZE(trap_array); nr++) { | |
232 | + struct trap_array_entry *entry = trap_array + nr; | |
233 | + | |
234 | + if (*addr == entry->orig) { | |
235 | + *addr = entry->xen; | |
236 | + ist_okay = entry->ist_okay; | |
237 | + break; | |
238 | + } | |
239 | + } | |
240 | + | |
241 | + if (WARN_ON(ist != 0 && !ist_okay)) | |
242 | + return false; | |
243 | + | |
244 | + return true; | |
245 | +} | |
246 | +#endif | |
247 | + | |
248 | static int cvt_gate_to_trap(int vector, const gate_desc *val, | |
249 | struct trap_info *info) | |
250 | { | |
251 | @@ -598,40 +662,8 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val, | |
252 | ||
253 | addr = gate_offset(val); | |
254 | #ifdef CONFIG_X86_64 | |
255 | - /* | |
256 | - * Look for known traps using IST, and substitute them | |
257 | - * appropriately. The debugger ones are the only ones we care | |
258 | - * about. Xen will handle faults like double_fault, | |
259 | - * so we should never see them. Warn if | |
260 | - * there's an unexpected IST-using fault handler. | |
261 | - */ | |
262 | - if (addr == (unsigned long)debug) | |
263 | - addr = (unsigned long)xen_debug; | |
264 | - else if (addr == (unsigned long)int3) | |
265 | - addr = (unsigned long)xen_int3; | |
266 | - else if (addr == (unsigned long)stack_segment) | |
267 | - addr = (unsigned long)xen_stack_segment; | |
268 | - else if (addr == (unsigned long)double_fault) { | |
269 | - /* Don't need to handle these */ | |
270 | + if (!get_trap_addr((void **)&addr, val->bits.ist)) | |
271 | return 0; | |
272 | -#ifdef CONFIG_X86_MCE | |
273 | - } else if (addr == (unsigned long)machine_check) { | |
274 | - /* | |
275 | - * when xen hypervisor inject vMCE to guest, | |
276 | - * use native mce handler to handle it | |
277 | - */ | |
278 | - ; | |
279 | -#endif | |
280 | - } else if (addr == (unsigned long)nmi) | |
281 | - /* | |
282 | - * Use the native version as well. | |
283 | - */ | |
284 | - ; | |
285 | - else { | |
286 | - /* Some other trap using IST? */ | |
287 | - if (WARN_ON(val->bits.ist != 0)) | |
288 | - return 0; | |
289 | - } | |
290 | #endif /* CONFIG_X86_64 */ | |
291 | info->address = addr; | |
292 | ||
293 | diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c | |
294 | index 33e92955e09d..d4eff5676cfa 100644 | |
295 | --- a/arch/x86/xen/irq.c | |
296 | +++ b/arch/x86/xen/irq.c | |
297 | @@ -123,9 +123,6 @@ static const struct pv_irq_ops xen_irq_ops __initconst = { | |
298 | ||
299 | .safe_halt = xen_safe_halt, | |
300 | .halt = xen_halt, | |
301 | -#ifdef CONFIG_X86_64 | |
302 | - .adjust_exception_frame = xen_adjust_exception_frame, | |
303 | -#endif | |
304 | }; | |
305 | ||
306 | void __init xen_init_irq_ops(void) | |
307 | diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S | |
308 | index dfabcbf8e813..c12260ef3e4b 100644 | |
309 | --- a/arch/x86/entry/entry_64.S | |
310 | +++ b/arch/x86/entry/entry_64.S | |
311 | @@ -829,7 +829,6 @@ ENTRY(\sym) | |
312 | .endif | |
313 | ||
314 | ASM_CLAC | |
315 | - PARAVIRT_ADJUST_EXCEPTION_FRAME | |
316 | ||
317 | .ifeq \has_error_code | |
318 | pushq $-1 /* ORIG_RAX: no syscall to restart */ | |
319 | @@ -975,7 +974,7 @@ ENTRY(do_softirq_own_stack) | |
320 | ENDPROC(do_softirq_own_stack) | |
321 | ||
322 | #ifdef CONFIG_XEN | |
323 | -idtentry xen_hypervisor_callback xen_do_hypervisor_callback has_error_code=0 | |
324 | +idtentry hypervisor_callback xen_do_hypervisor_callback has_error_code=0 | |
325 | ||
326 | /* | |
327 | * A note on the "critical region" in our callback handler. | |
328 | @@ -1042,8 +1041,6 @@ ENTRY(xen_failsafe_callback) | |
329 | movq 8(%rsp), %r11 | |
330 | addq $0x30, %rsp | |
331 | pushq $0 /* RIP */ | |
332 | - pushq %r11 | |
333 | - pushq %rcx | |
334 | UNWIND_HINT_IRET_REGS offset=8 | |
335 | jmp general_protection | |
336 | 1: /* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */ | |
337 | @@ -1074,9 +1071,8 @@ idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK | |
338 | idtentry stack_segment do_stack_segment has_error_code=1 | |
339 | ||
340 | #ifdef CONFIG_XEN | |
341 | -idtentry xen_debug do_debug has_error_code=0 | |
342 | -idtentry xen_int3 do_int3 has_error_code=0 | |
343 | -idtentry xen_stack_segment do_stack_segment has_error_code=1 | |
344 | +idtentry xendebug do_debug has_error_code=0 | |
345 | +idtentry xenint3 do_int3 has_error_code=0 | |
346 | #endif | |
347 | ||
348 | idtentry general_protection do_general_protection has_error_code=1 | |
349 | @@ -1240,20 +1236,9 @@ ENTRY(error_exit) | |
350 | END(error_exit) | |
351 | ||
352 | /* Runs on exception stack */ | |
353 | +/* XXX: broken on Xen PV */ | |
354 | ENTRY(nmi) | |
355 | UNWIND_HINT_IRET_REGS | |
356 | - /* | |
357 | - * Fix up the exception frame if we're on Xen. | |
358 | - * PARAVIRT_ADJUST_EXCEPTION_FRAME is guaranteed to push at most | |
359 | - * one value to the stack on native, so it may clobber the rdx | |
360 | - * scratch slot, but it won't clobber any of the important | |
361 | - * slots past it. | |
362 | - * | |
363 | - * Xen is a different story, because the Xen frame itself overlaps | |
364 | - * the "NMI executing" variable. | |
365 | - */ | |
366 | - PARAVIRT_ADJUST_EXCEPTION_FRAME | |
367 | - | |
368 | /* | |
369 | * We allow breakpoints in NMIs. If a breakpoint occurs, then | |
370 | * the iretq it performs will take us out of NMI context. | |
371 | diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S | |
372 | index 5314d7b8e5ad..d8468ba24be0 100644 | |
373 | --- a/arch/x86/entry/entry_64_compat.S | |
374 | +++ b/arch/x86/entry/entry_64_compat.S | |
375 | @@ -293,7 +293,6 @@ ENTRY(entry_INT80_compat) | |
376 | /* | |
377 | * Interrupts are off on entry. | |
378 | */ | |
379 | - PARAVIRT_ADJUST_EXCEPTION_FRAME | |
380 | ASM_CLAC /* Do this early to minimize exposure */ | |
381 | SWAPGS | |
382 | ||
383 | diff --git a/arch/x86/xen/xen-asm_64.S b/arch/x86/xen/xen-asm_64.S | |
384 | index 3a3b6a211584..dae2cc33afb5 100644 | |
385 | --- a/arch/x86/xen/xen-asm_64.S | |
386 | +++ b/arch/x86/xen/xen-asm_64.S | |
387 | @@ -16,11 +16,42 @@ | |
388 | ||
389 | #include <linux/linkage.h> | |
390 | ||
391 | -ENTRY(xen_adjust_exception_frame) | |
392 | - mov 8+0(%rsp), %rcx | |
393 | - mov 8+8(%rsp), %r11 | |
394 | - ret $16 | |
395 | -ENDPROC(xen_adjust_exception_frame) | |
396 | +.macro xen_pv_trap name | |
397 | +ENTRY(xen_\name) | |
398 | + pop %rcx | |
399 | + pop %r11 | |
400 | + jmp \name | |
401 | +END(xen_\name) | |
402 | +.endm | |
403 | + | |
404 | +xen_pv_trap divide_error | |
405 | +xen_pv_trap debug | |
406 | +xen_pv_trap xendebug | |
407 | +xen_pv_trap int3 | |
408 | +xen_pv_trap xenint3 | |
409 | +xen_pv_trap nmi | |
410 | +xen_pv_trap overflow | |
411 | +xen_pv_trap bounds | |
412 | +xen_pv_trap invalid_op | |
413 | +xen_pv_trap device_not_available | |
414 | +xen_pv_trap double_fault | |
415 | +xen_pv_trap coprocessor_segment_overrun | |
416 | +xen_pv_trap invalid_TSS | |
417 | +xen_pv_trap segment_not_present | |
418 | +xen_pv_trap stack_segment | |
419 | +xen_pv_trap general_protection | |
420 | +xen_pv_trap page_fault | |
421 | +xen_pv_trap spurious_interrupt_bug | |
422 | +xen_pv_trap coprocessor_error | |
423 | +xen_pv_trap alignment_check | |
424 | +#ifdef CONFIG_X86_MCE | |
425 | +xen_pv_trap machine_check | |
426 | +#endif /* CONFIG_X86_MCE */ | |
427 | +xen_pv_trap simd_coprocessor_error | |
428 | +#ifdef CONFIG_IA32_EMULATION | |
429 | +xen_pv_trap entry_INT80_compat | |
430 | +#endif | |
431 | +xen_pv_trap hypervisor_callback | |
432 | ||
433 | hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32 | |
434 | /* | |
435 | -- | |
436 | 2.14.2 | |
437 |