aboutsummaryrefslogtreecommitdiffstats
path: root/xen
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2013-05-02 16:37:24 +0200
committerJan Beulich <jbeulich@suse.com>2013-05-02 16:37:24 +0200
commit4939f9a6dee4280f38730fd3066e5dce353112f6 (patch)
treef7fc6fa0c8f7b1261706f24a15c6ee9e58534440 /xen
parent918a5f17b447072b40780f4d03a3adc99ff0073b (diff)
downloadxen-4939f9a6dee4280f38730fd3066e5dce353112f6.tar.gz
xen-4939f9a6dee4280f38730fd3066e5dce353112f6.tar.bz2
xen-4939f9a6dee4280f38730fd3066e5dce353112f6.zip
x86: make vcpu_reset() preemptible
... 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>
Diffstat (limited to 'xen')
-rw-r--r--xen/arch/arm/domain.c3
-rw-r--r--xen/arch/x86/domain.c13
-rw-r--r--xen/arch/x86/hvm/hvm.c5
-rw-r--r--xen/arch/x86/hvm/vlapic.c5
-rw-r--r--xen/arch/x86/mm.c6
-rw-r--r--xen/common/domain.c12
-rw-r--r--xen/common/domctl.c13
-rw-r--r--xen/include/asm-x86/mm.h2
-rw-r--r--xen/include/xen/domain.h4
-rw-r--r--xen/include/xen/sched.h3
10 files changed, 42 insertions, 24 deletions
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 2af40a139a..141aa0b482 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -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)
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index bc1a31f7e6..5bf52ff566 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -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;
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index c8487b8ebe..7c3cb15053 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -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);
diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c
index 9e1db88599..8c6a7e234d 100644
--- a/xen/arch/x86/hvm/vlapic.c
+++ b/xen/arch/x86/hvm/vlapic.c
@@ -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);
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index bada0bdd36..10e921780b 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -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();
diff --git a/xen/common/domain.c b/xen/common/domain.c
index ce45d66b45..7cca65507d 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -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;
}
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index 73b12c8a4d..1d00cfc95f 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -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;
diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h
index 0f7297abec..79c526ff62 100644
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -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);
diff --git a/xen/include/xen/domain.h b/xen/include/xen/domain.h
index d4ac50ff0f..504a70fc95 100644
--- a/xen/include/xen/domain.h
+++ b/xen/include/xen/domain.h
@@ -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);
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index beadc429f9..41f749e19e 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -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)
{