]> xenbits.xensource.com Git - people/aperard/xen-arm.git/commitdiff
x86: make vcpu_reset() preemptible
authorJan Beulich <jbeulich@suse.com>
Thu, 2 May 2013 14:37:24 +0000 (16:37 +0200)
committerJan Beulich <jbeulich@suse.com>
Thu, 2 May 2013 14:37:24 +0000 (16:37 +0200)
... as dropping the old page tables may take significant amounts of
time.

This is part of CVE-2013-1918 / XSA-45.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Tim Deegan <tim@xen.org>
xen/arch/arm/domain.c
xen/arch/x86/domain.c
xen/arch/x86/hvm/hvm.c
xen/arch/x86/hvm/vlapic.c
xen/arch/x86/mm.c
xen/common/domain.c
xen/common/domctl.c
xen/include/asm-x86/mm.h
xen/include/xen/domain.h
xen/include/xen/sched.h

index 2af40a139ae019e1aa7e9fea6812fb0dac687719..141aa0b482dd5b4cc7ec1db1172d666fac974f21 100644 (file)
@@ -566,9 +566,10 @@ int arch_set_info_guest(
     return 0;
 }
 
-void arch_vcpu_reset(struct vcpu *v)
+int arch_vcpu_reset(struct vcpu *v)
 {
     vcpu_end_shutdown_deferral(v);
+    return 0;
 }
 
 static int relinquish_memory(struct domain *d, struct page_list_head *list)
index bc1a31f7e683f7a724af761499c388c653305fd1..5bf52ff5663216ee5c1bc2f6ab3b7bb11a906865 100644 (file)
@@ -939,17 +939,16 @@ int arch_set_info_guest(
 #undef c
 }
 
-void arch_vcpu_reset(struct vcpu *v)
+int arch_vcpu_reset(struct vcpu *v)
 {
     if ( !is_hvm_vcpu(v) )
     {
         destroy_gdt(v);
-        vcpu_destroy_pagetables(v, 0);
-    }
-    else
-    {
-        vcpu_end_shutdown_deferral(v);
+        return vcpu_destroy_pagetables(v);
     }
+
+    vcpu_end_shutdown_deferral(v);
+    return 0;
 }
 
 /* 
@@ -1960,7 +1959,7 @@ int domain_relinquish_resources(struct domain *d)
         /* Drop the in-use references to page-table bases. */
         for_each_vcpu ( d, v )
         {
-            ret = vcpu_destroy_pagetables(v, 1);
+            ret = vcpu_destroy_pagetables(v);
             if ( ret )
                 return ret;
 
index c8487b8ebe97fc273ed2731dd5bd87234d94b3eb..7c3cb15053b0f8854cde4c974d51e43d4dfdc507 100644 (file)
@@ -3555,8 +3555,11 @@ static void hvm_s3_suspend(struct domain *d)
 
     for_each_vcpu ( d, v )
     {
+        int rc;
+
         vlapic_reset(vcpu_vlapic(v));
-        vcpu_reset(v);
+        rc = vcpu_reset(v);
+        ASSERT(!rc);
     }
 
     vpic_reset(d);
index 9e1db885990ddc6da8a6e0438bcf05228d334389..8c6a7e234d522c40bb0e6bddb3487dd12a19b684 100644 (file)
@@ -240,6 +240,8 @@ static void vlapic_init_sipi_one(struct vcpu *target, uint32_t icr)
     {
     case APIC_DM_INIT: {
         bool_t fpu_initialised;
+        int rc;
+
         /* No work on INIT de-assert for P4-type APIC. */
         if ( (icr & (APIC_INT_LEVELTRIG | APIC_INT_ASSERT)) ==
              APIC_INT_LEVELTRIG )
@@ -251,7 +253,8 @@ static void vlapic_init_sipi_one(struct vcpu *target, uint32_t icr)
         domain_lock(target->domain);
         /* Reset necessary VCPU state. This does not include FPU state. */
         fpu_initialised = target->fpu_initialised;
-        vcpu_reset(target);
+        rc = vcpu_reset(target);
+        ASSERT(!rc);
         target->fpu_initialised = fpu_initialised;
         vlapic_reset(vcpu_vlapic(target));
         domain_unlock(target->domain);
index bada0bdd36afe3b42ee29120f184800ecf3d0791..10e921780b6b52bcddaa375b88ed903fef3cac40 100644 (file)
@@ -2598,7 +2598,7 @@ static int put_old_guest_table(struct vcpu *v)
     return rc;
 }
 
-int vcpu_destroy_pagetables(struct vcpu *v, bool_t preemptible)
+int vcpu_destroy_pagetables(struct vcpu *v)
 {
     unsigned long mfn = pagetable_get_pfn(v->arch.guest_table);
     struct page_info *page;
@@ -2620,7 +2620,7 @@ int vcpu_destroy_pagetables(struct vcpu *v, bool_t preemptible)
         if ( paging_mode_refcounts(v->domain) )
             put_page(page);
         else
-            rc = put_page_and_type_preemptible(page, preemptible);
+            rc = put_page_and_type_preemptible(page, 1);
     }
 
     if ( l4tab )
@@ -2641,7 +2641,7 @@ int vcpu_destroy_pagetables(struct vcpu *v, bool_t preemptible)
             if ( paging_mode_refcounts(v->domain) )
                 put_page(page);
             else
-                rc = put_page_and_type_preemptible(page, preemptible);
+                rc = put_page_and_type_preemptible(page, 1);
         }
         if ( !rc )
             v->arch.guest_table_user = pagetable_null();
index ce45d66b455d9439ec431079248ad871b63aaec3..7cca65507d8243d046544b690d5707816d0f0c16 100644 (file)
@@ -868,14 +868,18 @@ void domain_unpause_by_systemcontroller(struct domain *d)
         domain_unpause(d);
 }
 
-void vcpu_reset(struct vcpu *v)
+int vcpu_reset(struct vcpu *v)
 {
     struct domain *d = v->domain;
+    int rc;
 
     vcpu_pause(v);
     domain_lock(d);
 
-    arch_vcpu_reset(v);
+    set_bit(_VPF_in_reset, &v->pause_flags);
+    rc = arch_vcpu_reset(v);
+    if ( rc )
+        goto out_unlock;
 
     set_bit(_VPF_down, &v->pause_flags);
 
@@ -891,9 +895,13 @@ void vcpu_reset(struct vcpu *v)
 #endif
     cpumask_clear(v->cpu_affinity_tmp);
     clear_bit(_VPF_blocked, &v->pause_flags);
+    clear_bit(_VPF_in_reset, &v->pause_flags);
 
+ out_unlock:
     domain_unlock(v->domain);
     vcpu_unpause(v);
+
+    return rc;
 }
 
 
index 73b12c8a4df3b1816c6ead29ea9b1d95d453c549..1d00cfc95f08f762d7a96fba0d9e2d1f90243fd4 100644 (file)
@@ -332,13 +332,15 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
         ret = -EINVAL;
         if ( (d == current->domain) || /* no domain_pause() */
              (vcpu >= d->max_vcpus) || ((v = d->vcpu[vcpu]) == NULL) )
-            goto svc_out;
+            break;
 
         if ( guest_handle_is_null(op->u.vcpucontext.ctxt) )
         {
-            vcpu_reset(v);
-            ret = 0;
-            goto svc_out;
+            ret = vcpu_reset(v);
+            if ( ret == -EAGAIN )
+                ret = hypercall_create_continuation(
+                          __HYPERVISOR_domctl, "h", u_domctl);
+            break;
         }
 
 #ifdef CONFIG_COMPAT
@@ -347,7 +349,7 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
 #endif
         ret = -ENOMEM;
         if ( (c.nat = alloc_vcpu_guest_context()) == NULL )
-            goto svc_out;
+            break;
 
 #ifdef CONFIG_COMPAT
         if ( !is_pv_32on64_vcpu(v) )
@@ -368,7 +370,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
             domain_unpause(d);
         }
 
-    svc_out:
         free_vcpu_guest_context(c.nat);
     }
     break;
index 0f7297abec848382feb5b5325af8ed6ac3805b0f..79c526ff62ae73216bd6dad7932da2f59f6020fa 100644 (file)
@@ -556,7 +556,7 @@ void audit_domains(void);
 int new_guest_cr3(unsigned long pfn);
 void make_cr3(struct vcpu *v, unsigned long mfn);
 void update_cr3(struct vcpu *v);
-int vcpu_destroy_pagetables(struct vcpu *, bool_t preemptible);
+int vcpu_destroy_pagetables(struct vcpu *);
 void propagate_page_fault(unsigned long addr, u16 error_code);
 void *do_page_walk(struct vcpu *v, unsigned long addr);
 
index d4ac50ff0fcdac8650a1166fb9408d4f6851d9c6..504a70fc958b37cba5088881857f0aced53c0770 100644 (file)
@@ -13,7 +13,7 @@ typedef union {
 struct vcpu *alloc_vcpu(
     struct domain *d, unsigned int vcpu_id, unsigned int cpu_id);
 struct vcpu *alloc_dom0_vcpu0(void);
-void vcpu_reset(struct vcpu *v);
+int vcpu_reset(struct vcpu *);
 
 struct xen_domctl_getdomaininfo;
 void getdomaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info);
@@ -67,7 +67,7 @@ void arch_dump_vcpu_info(struct vcpu *v);
 
 void arch_dump_domain_info(struct domain *d);
 
-void arch_vcpu_reset(struct vcpu *v);
+int arch_vcpu_reset(struct vcpu *);
 
 extern spinlock_t vcpu_alloc_lock;
 bool_t domctl_lock_acquire(void);
index beadc429f91d549777879e944ca31e73ecbf0754..41f749e19ecf352f380f74d74dfe3098fcdb5361 100644 (file)
@@ -682,6 +682,9 @@ static inline struct domain *next_domain_in_cpupool(
  /* VCPU is blocked due to missing mem_sharing ring. */
 #define _VPF_mem_sharing     6
 #define VPF_mem_sharing      (1UL<<_VPF_mem_sharing)
+ /* VCPU is being reset. */
+#define _VPF_in_reset        7
+#define VPF_in_reset         (1UL<<_VPF_in_reset)
 
 static inline int vcpu_runnable(struct vcpu *v)
 {