]> xenbits.xensource.com Git - xen.git/commitdiff
x86: avoid calling {svm,vmx}_do_resume()
authorJan Beulich <jbeulich@suse.com>
Tue, 15 Dec 2020 13:46:33 +0000 (14:46 +0100)
committerJan Beulich <jbeulich@suse.com>
Tue, 15 Dec 2020 13:46:33 +0000 (14:46 +0100)
These functions follow the following path: hvm_do_resume() ->
handle_hvm_io_completion() -> hvm_wait_for_io() ->
wait_on_xen_event_channel() -> do_softirq() -> schedule() ->
sched_context_switch() -> continue_running() and hence may
recursively invoke themselves. If this ends up happening a couple of
times, a stack overflow would result.

Prevent this by also resetting the stack at the
->arch.ctxt_switch->tail() invocations (in both places for consistency)
and thus jumping to the functions instead of calling them.

This is XSA-348 / CVE-2020-29566.

Reported-by: Julien Grall <jgrall@amazon.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
master commit: e6ebd394385db52855d1517cea829ffff68b34b8
master date: 2020-12-15 13:41:23 +0100

xen/arch/x86/domain.c
xen/arch/x86/hvm/svm/svm.c
xen/arch/x86/hvm/vmx/vmcs.c
xen/arch/x86/pv/domain.c
xen/include/asm-x86/current.h
xen/include/asm-x86/domain.h
xen/include/asm-x86/hvm/vmx/vmx.h

index 7ae7266c5f02e19672df2b9ce9a7ca97197c4504..2c598633420d7c79cdfb8f5d39db5f576c0c2852 100644 (file)
@@ -121,7 +121,7 @@ static void play_dead(void)
     (*dead_idle)();
 }
 
-static void idle_loop(void)
+static void noreturn idle_loop(void)
 {
     unsigned int cpu = smp_processor_id();
 
@@ -161,11 +161,6 @@ void startup_cpu_idle_loop(void)
     reset_stack_and_jump(idle_loop);
 }
 
-static void noreturn continue_idle_domain(struct vcpu *v)
-{
-    reset_stack_and_jump(idle_loop);
-}
-
 void dump_pageframe_info(struct domain *d)
 {
     struct page_info *page;
@@ -560,7 +555,7 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags,
         static const struct arch_csw idle_csw = {
             .from = paravirt_ctxt_switch_from,
             .to   = paravirt_ctxt_switch_to,
-            .tail = continue_idle_domain,
+            .tail = idle_loop,
         };
 
         d->arch.ctxt_switch = &idle_csw;
@@ -1765,20 +1760,12 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
     /* Ensure that the vcpu has an up-to-date time base. */
     update_vcpu_system_time(next);
 
-    /*
-     * Schedule tail *should* be a terminal function pointer, but leave a
-     * bug frame around just in case it returns, to save going back into the
-     * context switching code and leaving a far more subtle crash to diagnose.
-     */
-    nextd->arch.ctxt_switch->tail(next);
-    BUG();
+    reset_stack_and_jump_ind(nextd->arch.ctxt_switch->tail);
 }
 
 void continue_running(struct vcpu *same)
 {
-    /* See the comment above. */
-    same->domain->arch.ctxt_switch->tail(same);
-    BUG();
+    reset_stack_and_jump_ind(same->domain->arch.ctxt_switch->tail);
 }
 
 int __sync_local_execstate(void)
index 25fc9f228873d32b52faa1c51eeea5fe405001a8..0365d6bfc2daef1a590af02662879dbb4f8c54a8 100644 (file)
@@ -1086,8 +1086,9 @@ static void svm_ctxt_switch_to(struct vcpu *v)
         wrmsr_tsc_aux(hvm_msr_tsc_aux(v));
 }
 
-static void noreturn svm_do_resume(struct vcpu *v)
+static void noreturn svm_do_resume(void)
 {
+    struct vcpu *v = current;
     struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
     bool_t debug_state = v->domain->debugger_attached;
     bool_t vcpu_guestmode = 0;
index e18ebbae9e2140154340b9fa0344718e6129a1de..a50011778179ec6b823e7c9a3df8b36ef70f8603 100644 (file)
@@ -1785,8 +1785,9 @@ void vmx_vmentry_failure(void)
     domain_crash_synchronous();
 }
 
-void vmx_do_resume(struct vcpu *v)
+void vmx_do_resume(void)
 {
+    struct vcpu *v = current;
     bool_t debug_state;
 
     if ( v->arch.hvm_vmx.active_cpu == smp_processor_id() )
index 22269023bfefcdf4969b150498486ba5d892e6b9..8834190febc56887e3c8d20012408473e1c7d864 100644 (file)
@@ -64,7 +64,7 @@ custom_runtime_param("pcid", parse_pcid);
 #undef page_to_mfn
 #define page_to_mfn(pg) _mfn(__page_to_mfn(pg))
 
-static void noreturn continue_nonidle_domain(struct vcpu *v)
+static void noreturn continue_nonidle_domain(void)
 {
     check_wakeup_from_wait();
     reset_stack_and_jump(ret_from_intr);
index b7860a772fe3823fe4cb5debd90c065fc2f3001a..2c15df54bdbe81d99249f7aaec663e30f142c314 100644 (file)
@@ -124,16 +124,23 @@ unsigned long get_stack_dump_bottom (unsigned long sp);
 # define CHECK_FOR_LIVEPATCH_WORK ""
 #endif
 
-#define reset_stack_and_jump(__fn)                                      \
+#define switch_stack_and_jump(fn, instr, constr)                        \
     ({                                                                  \
         __asm__ __volatile__ (                                          \
             "mov %0,%%"__OP"sp;"                                        \
-            CHECK_FOR_LIVEPATCH_WORK                                      \
-             "jmp %c1"                                                  \
-            : : "r" (guest_cpu_user_regs()), "i" (__fn) : "memory" );   \
+            CHECK_FOR_LIVEPATCH_WORK                                    \
+            instr "1"                                                   \
+            : : "r" (guest_cpu_user_regs()), constr (fn) : "memory" );  \
         unreachable();                                                  \
     })
 
+#define reset_stack_and_jump(fn)                                        \
+    switch_stack_and_jump(fn, "jmp %c", "i")
+
+/* The constraint may only specify non-call-clobbered registers. */
+#define reset_stack_and_jump_ind(fn)                                    \
+    switch_stack_and_jump(fn, "INDIRECT_JMP %", "b")
+
 /*
  * Which VCPU's state is currently running on each CPU?
  * This is not necesasrily the same as 'current' as a CPU may be
index 5afaf6b9de47df23b8f3019f5220dfef18c32235..bd31fada498c8beaf6d57b01d301b2ad7f5061cd 100644 (file)
@@ -330,7 +330,7 @@ struct arch_domain
     const struct arch_csw {
         void (*from)(struct vcpu *);
         void (*to)(struct vcpu *);
-        void (*tail)(struct vcpu *);
+        void noreturn (*tail)(void);
     } *ctxt_switch;
 
     /* nestedhvm: translate l2 guest physical to host physical */
index aad25335eb1eb503b885f9a5e1e646c73b78640f..a05a0d4d626a340f00a27c69d8287bc7cee18a76 100644 (file)
@@ -95,7 +95,7 @@ typedef enum {
 void vmx_asm_vmexit_handler(struct cpu_user_regs);
 void vmx_asm_do_vmentry(void);
 void vmx_intr_assist(void);
-void noreturn vmx_do_resume(struct vcpu *);
+void noreturn vmx_do_resume(void);
 void vmx_vlapic_msr_changed(struct vcpu *v);
 void vmx_realmode_emulate_one(struct hvm_emulate_ctxt *hvmemul_ctxt);
 void vmx_realmode(struct cpu_user_regs *regs);