|
|
6f6e96c |
x86: make vcpu_reset() preemptible
|
|
|
6f6e96c |
|
|
|
6f6e96c |
... as dropping the old page tables may take significant amounts of
|
|
|
6f6e96c |
time.
|
|
|
6f6e96c |
|
|
|
6f6e96c |
This is part of CVE-2013-1918 / XSA-45.
|
|
|
6f6e96c |
|
|
|
6f6e96c |
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
|
|
6f6e96c |
Acked-by: Tim Deegan <tim@xen.org>
|
|
|
6f6e96c |
|
|
|
6f6e96c |
--- a/xen/arch/x86/domain.c
|
|
|
6f6e96c |
+++ b/xen/arch/x86/domain.c
|
|
|
6f6e96c |
@@ -902,17 +902,16 @@ int arch_set_info_guest(
|
|
|
6f6e96c |
#undef c
|
|
|
6f6e96c |
}
|
|
|
6f6e96c |
|
|
|
6f6e96c |
-void arch_vcpu_reset(struct vcpu *v)
|
|
|
6f6e96c |
+int arch_vcpu_reset(struct vcpu *v)
|
|
|
6f6e96c |
{
|
|
|
6f6e96c |
if ( !is_hvm_vcpu(v) )
|
|
|
6f6e96c |
{
|
|
|
6f6e96c |
destroy_gdt(v);
|
|
|
6f6e96c |
- vcpu_destroy_pagetables(v, 0);
|
|
|
6f6e96c |
- }
|
|
|
6f6e96c |
- else
|
|
|
6f6e96c |
- {
|
|
|
6f6e96c |
- vcpu_end_shutdown_deferral(v);
|
|
|
6f6e96c |
+ return vcpu_destroy_pagetables(v);
|
|
|
6f6e96c |
}
|
|
|
6f6e96c |
+
|
|
|
6f6e96c |
+ vcpu_end_shutdown_deferral(v);
|
|
|
6f6e96c |
+ return 0;
|
|
|
6f6e96c |
}
|
|
|
6f6e96c |
|
|
|
6f6e96c |
/*
|
|
|
6f6e96c |
@@ -1933,7 +1932,7 @@ int domain_relinquish_resources(struct d
|
|
|
6f6e96c |
for_each_vcpu ( d, v )
|
|
|
6f6e96c |
{
|
|
|
6f6e96c |
/* Drop the in-use references to page-table bases. */
|
|
|
6f6e96c |
- ret = vcpu_destroy_pagetables(v, 1);
|
|
|
6f6e96c |
+ ret = vcpu_destroy_pagetables(v);
|
|
|
6f6e96c |
if ( ret )
|
|
|
6f6e96c |
return ret;
|
|
|
6f6e96c |
|
|
|
6f6e96c |
--- a/xen/arch/x86/hvm/hvm.c
|
|
|
6f6e96c |
+++ b/xen/arch/x86/hvm/hvm.c
|
|
|
6f6e96c |
@@ -3083,8 +3083,11 @@ static void hvm_s3_suspend(struct domain
|
|
|
6f6e96c |
|
|
|
6f6e96c |
for_each_vcpu ( d, v )
|
|
|
6f6e96c |
{
|
|
|
6f6e96c |
+ int rc;
|
|
|
6f6e96c |
+
|
|
|
6f6e96c |
vlapic_reset(vcpu_vlapic(v));
|
|
|
6f6e96c |
- vcpu_reset(v);
|
|
|
6f6e96c |
+ rc = vcpu_reset(v);
|
|
|
6f6e96c |
+ ASSERT(!rc);
|
|
|
6f6e96c |
}
|
|
|
6f6e96c |
|
|
|
6f6e96c |
vpic_reset(d);
|
|
|
6f6e96c |
--- a/xen/arch/x86/hvm/vlapic.c
|
|
|
6f6e96c |
+++ b/xen/arch/x86/hvm/vlapic.c
|
|
|
6f6e96c |
@@ -252,10 +252,13 @@ static void vlapic_init_sipi_action(unsi
|
|
|
6f6e96c |
{
|
|
|
6f6e96c |
case APIC_DM_INIT: {
|
|
|
6f6e96c |
bool_t fpu_initialised;
|
|
|
6f6e96c |
+ int rc;
|
|
|
6f6e96c |
+
|
|
|
6f6e96c |
domain_lock(target->domain);
|
|
|
6f6e96c |
/* Reset necessary VCPU state. This does not include FPU state. */
|
|
|
6f6e96c |
fpu_initialised = target->fpu_initialised;
|
|
|
6f6e96c |
- vcpu_reset(target);
|
|
|
6f6e96c |
+ rc = vcpu_reset(target);
|
|
|
6f6e96c |
+ ASSERT(!rc);
|
|
|
6f6e96c |
target->fpu_initialised = fpu_initialised;
|
|
|
6f6e96c |
vlapic_reset(vcpu_vlapic(target));
|
|
|
6f6e96c |
domain_unlock(target->domain);
|
|
|
6f6e96c |
--- a/xen/arch/x86/mm.c
|
|
|
6f6e96c |
+++ b/xen/arch/x86/mm.c
|
|
|
6f6e96c |
@@ -2744,7 +2744,7 @@ static int put_old_guest_table(struct vc
|
|
|
6f6e96c |
return rc;
|
|
|
6f6e96c |
}
|
|
|
6f6e96c |
|
|
|
6f6e96c |
-int vcpu_destroy_pagetables(struct vcpu *v, bool_t preemptible)
|
|
|
6f6e96c |
+int vcpu_destroy_pagetables(struct vcpu *v)
|
|
|
6f6e96c |
{
|
|
|
6f6e96c |
unsigned long mfn = pagetable_get_pfn(v->arch.guest_table);
|
|
|
6f6e96c |
struct page_info *page;
|
|
|
6f6e96c |
@@ -2764,7 +2764,7 @@ int vcpu_destroy_pagetables(struct vcpu
|
|
|
6f6e96c |
if ( paging_mode_refcounts(v->domain) )
|
|
|
6f6e96c |
put_page(page);
|
|
|
6f6e96c |
else
|
|
|
6f6e96c |
- rc = put_page_and_type_preemptible(page, preemptible);
|
|
|
6f6e96c |
+ rc = put_page_and_type_preemptible(page, 1);
|
|
|
6f6e96c |
}
|
|
|
6f6e96c |
|
|
|
6f6e96c |
#ifdef __x86_64__
|
|
|
6f6e96c |
@@ -2790,7 +2790,7 @@ int vcpu_destroy_pagetables(struct vcpu
|
|
|
6f6e96c |
if ( paging_mode_refcounts(v->domain) )
|
|
|
6f6e96c |
put_page(page);
|
|
|
6f6e96c |
else
|
|
|
6f6e96c |
- rc = put_page_and_type_preemptible(page, preemptible);
|
|
|
6f6e96c |
+ rc = put_page_and_type_preemptible(page, 1);
|
|
|
6f6e96c |
}
|
|
|
6f6e96c |
if ( !rc )
|
|
|
6f6e96c |
v->arch.guest_table_user = pagetable_null();
|
|
|
6f6e96c |
--- a/xen/common/domain.c
|
|
|
6f6e96c |
+++ b/xen/common/domain.c
|
|
|
6f6e96c |
@@ -770,14 +770,18 @@ int boot_vcpu(struct domain *d, int vcpu
|
|
|
6f6e96c |
return arch_set_info_guest(v, ctxt);
|
|
|
6f6e96c |
}
|
|
|
6f6e96c |
|
|
|
6f6e96c |
-void vcpu_reset(struct vcpu *v)
|
|
|
6f6e96c |
+int vcpu_reset(struct vcpu *v)
|
|
|
6f6e96c |
{
|
|
|
6f6e96c |
struct domain *d = v->domain;
|
|
|
6f6e96c |
+ int rc;
|
|
|
6f6e96c |
|
|
|
6f6e96c |
vcpu_pause(v);
|
|
|
6f6e96c |
domain_lock(d);
|
|
|
6f6e96c |
|
|
|
6f6e96c |
- arch_vcpu_reset(v);
|
|
|
6f6e96c |
+ set_bit(_VPF_in_reset, &v->pause_flags);
|
|
|
6f6e96c |
+ rc = arch_vcpu_reset(v);
|
|
|
6f6e96c |
+ if ( rc )
|
|
|
6f6e96c |
+ goto out_unlock;
|
|
|
6f6e96c |
|
|
|
6f6e96c |
set_bit(_VPF_down, &v->pause_flags);
|
|
|
6f6e96c |
|
|
|
6f6e96c |
@@ -793,9 +797,13 @@ void vcpu_reset(struct vcpu *v)
|
|
|
6f6e96c |
#endif
|
|
|
6f6e96c |
cpus_clear(v->cpu_affinity_tmp);
|
|
|
6f6e96c |
clear_bit(_VPF_blocked, &v->pause_flags);
|
|
|
6f6e96c |
+ clear_bit(_VPF_in_reset, &v->pause_flags);
|
|
|
6f6e96c |
|
|
|
6f6e96c |
+ out_unlock:
|
|
|
6f6e96c |
domain_unlock(v->domain);
|
|
|
6f6e96c |
vcpu_unpause(v);
|
|
|
6f6e96c |
+
|
|
|
6f6e96c |
+ return rc;
|
|
|
6f6e96c |
}
|
|
|
6f6e96c |
|
|
|
6f6e96c |
|
|
|
6f6e96c |
--- a/xen/common/domctl.c
|
|
|
6f6e96c |
+++ b/xen/common/domctl.c
|
|
|
6f6e96c |
@@ -286,8 +286,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
|
|
|
6f6e96c |
|
|
|
6f6e96c |
if ( guest_handle_is_null(op->u.vcpucontext.ctxt) )
|
|
|
6f6e96c |
{
|
|
|
6f6e96c |
- vcpu_reset(v);
|
|
|
6f6e96c |
- ret = 0;
|
|
|
6f6e96c |
+ ret = vcpu_reset(v);
|
|
|
6f6e96c |
+ if ( ret == -EAGAIN )
|
|
|
6f6e96c |
+ ret = hypercall_create_continuation(
|
|
|
6f6e96c |
+ __HYPERVISOR_domctl, "h", u_domctl);
|
|
|
6f6e96c |
goto svc_out;
|
|
|
6f6e96c |
}
|
|
|
6f6e96c |
|
|
|
6f6e96c |
--- a/xen/include/asm-x86/mm.h
|
|
|
6f6e96c |
+++ b/xen/include/asm-x86/mm.h
|
|
|
6f6e96c |
@@ -555,7 +555,7 @@ void audit_domains(void);
|
|
|
6f6e96c |
int new_guest_cr3(unsigned long pfn);
|
|
|
6f6e96c |
void make_cr3(struct vcpu *v, unsigned long mfn);
|
|
|
6f6e96c |
void update_cr3(struct vcpu *v);
|
|
|
6f6e96c |
-int vcpu_destroy_pagetables(struct vcpu *, bool_t preemptible);
|
|
|
6f6e96c |
+int vcpu_destroy_pagetables(struct vcpu *);
|
|
|
6f6e96c |
void propagate_page_fault(unsigned long addr, u16 error_code);
|
|
|
6f6e96c |
void *do_page_walk(struct vcpu *v, unsigned long addr);
|
|
|
6f6e96c |
|
|
|
6f6e96c |
--- a/xen/include/xen/domain.h
|
|
|
6f6e96c |
+++ b/xen/include/xen/domain.h
|
|
|
6f6e96c |
@@ -15,7 +15,7 @@ struct vcpu *alloc_vcpu(
|
|
|
6f6e96c |
int boot_vcpu(
|
|
|
6f6e96c |
struct domain *d, int vcpuid, vcpu_guest_context_u ctxt);
|
|
|
6f6e96c |
struct vcpu *alloc_dom0_vcpu0(void);
|
|
|
6f6e96c |
-void vcpu_reset(struct vcpu *v);
|
|
|
6f6e96c |
+int vcpu_reset(struct vcpu *);
|
|
|
6f6e96c |
|
|
|
6f6e96c |
struct xen_domctl_getdomaininfo;
|
|
|
6f6e96c |
void getdomaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info);
|
|
|
6f6e96c |
@@ -57,7 +57,7 @@ void arch_dump_vcpu_info(struct vcpu *v)
|
|
|
6f6e96c |
|
|
|
6f6e96c |
void arch_dump_domain_info(struct domain *d);
|
|
|
6f6e96c |
|
|
|
6f6e96c |
-void arch_vcpu_reset(struct vcpu *v);
|
|
|
6f6e96c |
+int arch_vcpu_reset(struct vcpu *);
|
|
|
6f6e96c |
|
|
|
6f6e96c |
bool_t domctl_lock_acquire(void);
|
|
|
6f6e96c |
void domctl_lock_release(void);
|
|
|
6f6e96c |
--- a/xen/include/xen/sched.h
|
|
|
6f6e96c |
+++ b/xen/include/xen/sched.h
|
|
|
6f6e96c |
@@ -597,6 +597,9 @@ extern struct domain *domain_list;
|
|
|
6f6e96c |
/* VCPU is blocked on memory-event ring. */
|
|
|
6f6e96c |
#define _VPF_mem_event 4
|
|
|
6f6e96c |
#define VPF_mem_event (1UL<<_VPF_mem_event)
|
|
|
6f6e96c |
+ /* VCPU is being reset. */
|
|
|
6f6e96c |
+#define _VPF_in_reset 7
|
|
|
6f6e96c |
+#define VPF_in_reset (1UL<<_VPF_in_reset)
|
|
|
6f6e96c |
|
|
|
6f6e96c |
static inline int vcpu_runnable(struct vcpu *v)
|
|
|
6f6e96c |
{
|