|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] x86: make arch_set_info_guest() preemptible
commit 99d2b149915010e986f4d8778708c5891e7b4635
Author: Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Thu May 2 16:38:30 2013 +0200
Commit: Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Thu May 2 16:38:30 2013 +0200
x86: make arch_set_info_guest() preemptible
.. as the root page table validation (and the dropping of an eventual
old one) can require meaningful amounts of time.
This is part of CVE-2013-1918 / XSA-45.
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
Acked-by: Tim Deegan <tim@xxxxxxx>
---
xen/arch/x86/domain.c | 113 ++++++++++++++++++++++++--------------------
xen/common/compat/domain.c | 4 ++
xen/common/domain.c | 5 ++
xen/common/domctl.c | 4 ++
4 files changed, 74 insertions(+), 52 deletions(-)
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 5bf52ff..0baaa95 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -752,6 +752,9 @@ int arch_set_info_guest(
if ( !v->is_initialised )
{
+ if ( !compat && !(flags & VGCF_in_kernel) && !c.nat->ctrlreg[1] )
+ return -EINVAL;
+
v->arch.pv_vcpu.ldt_base = c(ldt_base);
v->arch.pv_vcpu.ldt_ents = c(ldt_ents);
}
@@ -844,80 +847,86 @@ int arch_set_info_guest(
if ( rc != 0 )
return rc;
+ set_bit(_VPF_in_reset, &v->pause_flags);
+
if ( !compat )
- {
cr3_gfn = xen_cr3_to_pfn(c.nat->ctrlreg[3]);
- cr3_page = get_page_from_gfn(d, cr3_gfn, NULL, P2M_ALLOC);
-
- if ( !cr3_page )
- {
- destroy_gdt(v);
- return -EINVAL;
- }
- if ( !paging_mode_refcounts(d)
- && !get_page_type(cr3_page, PGT_base_page_table) )
- {
- put_page(cr3_page);
- destroy_gdt(v);
- return -EINVAL;
- }
+ else
+ cr3_gfn = compat_cr3_to_pfn(c.cmp->ctrlreg[3]);
+ cr3_page = get_page_from_gfn(d, cr3_gfn, NULL, P2M_ALLOC);
+ if ( !cr3_page )
+ rc = -EINVAL;
+ else if ( paging_mode_refcounts(d) )
+ /* nothing */;
+ else if ( cr3_page == v->arch.old_guest_table )
+ {
+ v->arch.old_guest_table = NULL;
+ put_page(cr3_page);
+ }
+ else
+ {
+ /*
+ * Since v->arch.guest_table{,_user} are both NULL, this effectively
+ * is just a call to put_old_guest_table().
+ */
+ if ( !compat )
+ rc = vcpu_destroy_pagetables(v);
+ if ( !rc )
+ rc = get_page_type_preemptible(cr3_page,
+ !compat ? PGT_root_page_table
+ : PGT_l3_page_table);
+ if ( rc == -EINTR )
+ rc = -EAGAIN;
+ }
+ if ( rc )
+ /* handled below */;
+ else if ( !compat )
+ {
v->arch.guest_table = pagetable_from_page(cr3_page);
if ( c.nat->ctrlreg[1] )
{
cr3_gfn = xen_cr3_to_pfn(c.nat->ctrlreg[1]);
cr3_page = get_page_from_gfn(d, cr3_gfn, NULL, P2M_ALLOC);
- if ( !cr3_page ||
- (!paging_mode_refcounts(d)
- && !get_page_type(cr3_page, PGT_base_page_table)) )
+ if ( !cr3_page )
+ rc = -EINVAL;
+ else if ( !paging_mode_refcounts(d) )
{
- if (cr3_page)
- put_page(cr3_page);
- cr3_page = pagetable_get_page(v->arch.guest_table);
- v->arch.guest_table = pagetable_null();
- if ( paging_mode_refcounts(d) )
- put_page(cr3_page);
- else
- put_page_and_type(cr3_page);
- destroy_gdt(v);
- return -EINVAL;
+ rc = get_page_type_preemptible(cr3_page, PGT_root_page_table);
+ switch ( rc )
+ {
+ case -EINTR:
+ rc = -EAGAIN;
+ case -EAGAIN:
+ v->arch.old_guest_table =
+ pagetable_get_page(v->arch.guest_table);
+ v->arch.guest_table = pagetable_null();
+ break;
+ }
}
-
- v->arch.guest_table_user = pagetable_from_page(cr3_page);
- }
- else if ( !(flags & VGCF_in_kernel) )
- {
- destroy_gdt(v);
- return -EINVAL;
+ if ( !rc )
+ v->arch.guest_table_user = pagetable_from_page(cr3_page);
}
}
else
{
l4_pgentry_t *l4tab;
- cr3_gfn = compat_cr3_to_pfn(c.cmp->ctrlreg[3]);
- cr3_page = get_page_from_gfn(d, cr3_gfn, NULL, P2M_ALLOC);
-
- if ( !cr3_page)
- {
- destroy_gdt(v);
- return -EINVAL;
- }
-
- if (!paging_mode_refcounts(d)
- && !get_page_type(cr3_page, PGT_l3_page_table) )
- {
- put_page(cr3_page);
- destroy_gdt(v);
- return -EINVAL;
- }
-
l4tab = map_domain_page(pagetable_get_pfn(v->arch.guest_table));
*l4tab = l4e_from_pfn(page_to_mfn(cr3_page),
_PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED);
unmap_domain_page(l4tab);
}
+ if ( rc )
+ {
+ if ( cr3_page )
+ put_page(cr3_page);
+ destroy_gdt(v);
+ return rc;
+ }
+
+ clear_bit(_VPF_in_reset, &v->pause_flags);
if ( v->vcpu_id == 0 )
update_domain_wallclock_time(d);
diff --git a/xen/common/compat/domain.c b/xen/common/compat/domain.c
index aac8f46..44ba78d 100644
--- a/xen/common/compat/domain.c
+++ b/xen/common/compat/domain.c
@@ -50,6 +50,10 @@ int compat_vcpu_op(int cmd, int vcpuid,
XEN_GUEST_HANDLE_PARAM(void) arg)
rc = v->is_initialised ? -EEXIST : arch_set_info_guest(v, cmp_ctxt);
domain_unlock(d);
+ if ( rc == -EAGAIN )
+ rc = hypercall_create_continuation(__HYPERVISOR_vcpu_op, "iih",
+ cmd, vcpuid, arg);
+
xfree(cmp_ctxt);
break;
}
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 7cca655..b5d44d4 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -938,6 +938,11 @@ long do_vcpu_op(int cmd, int vcpuid,
XEN_GUEST_HANDLE_PARAM(void) arg)
domain_unlock(d);
free_vcpu_guest_context(ctxt);
+
+ if ( rc == -EAGAIN )
+ rc = hypercall_create_continuation(__HYPERVISOR_vcpu_op, "iih",
+ cmd, vcpuid, arg);
+
break;
case VCPUOP_up: {
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index 1d00cfc..9bd8f80 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -368,6 +368,10 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t)
u_domctl)
domain_pause(d);
ret = arch_set_info_guest(v, c);
domain_unpause(d);
+
+ if ( ret == -EAGAIN )
+ ret = hypercall_create_continuation(
+ __HYPERVISOR_domctl, "h", u_domctl);
}
free_vcpu_guest_context(c.nat);
--
generated by git-patchbot for /home/xen/git/xen.git#master
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |