[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 |