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