[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen stable-4.1] x86: make arch_set_info_guest() preemptible
commit 02615aaefd5c6c5856b4f81799bb6ec1ca0d89d0 Author: Jan Beulich <jbeulich@xxxxxxxx> AuthorDate: Thu May 2 17:25:37 2013 +0200 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Thu May 2 17:25:37 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> master commit: 99d2b149915010e986f4d8778708c5891e7b4635 master date: 2013-05-02 16:38:30 +0200 --- xen/arch/x86/domain.c | 108 ++++++++++++++++++++++++++++--------------- xen/common/compat/domain.c | 4 ++ xen/common/domain.c | 5 ++ xen/common/domctl.c | 4 ++ 4 files changed, 83 insertions(+), 38 deletions(-) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 696eff3..9a34488 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -676,6 +676,7 @@ int arch_set_info_guest( { struct domain *d = v->domain; unsigned long cr3_pfn = INVALID_MFN; + struct page_info *cr3_page; unsigned long flags, cr4; int i, rc = 0, compat; @@ -815,72 +816,103 @@ int arch_set_info_guest( if ( rc != 0 ) return rc; + set_bit(_VPF_in_reset, &v->pause_flags); + if ( !compat ) - { cr3_pfn = gmfn_to_mfn(d, xen_cr3_to_pfn(c.nat->ctrlreg[3])); +#ifdef __x86_64__ + else + cr3_pfn = gmfn_to_mfn(d, compat_cr3_to_pfn(c.cmp->ctrlreg[3])); +#endif + cr3_page = mfn_to_page(cr3_pfn); - if ( !mfn_valid(cr3_pfn) || - (paging_mode_refcounts(d) - ? !get_page(mfn_to_page(cr3_pfn), d) - : !get_page_and_type(mfn_to_page(cr3_pfn), d, - PGT_base_page_table)) ) - { - destroy_gdt(v); - return -EINVAL; - } + if ( !mfn_valid(cr3_pfn) || !get_page(cr3_page, d) ) + { + cr3_page = NULL; + 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_pfn(cr3_pfn); #ifdef __x86_64__ if ( c.nat->ctrlreg[1] ) { cr3_pfn = gmfn_to_mfn(d, xen_cr3_to_pfn(c.nat->ctrlreg[1])); + cr3_page = mfn_to_page(cr3_pfn); - if ( !mfn_valid(cr3_pfn) || - (paging_mode_refcounts(d) - ? !get_page(mfn_to_page(cr3_pfn), d) - : !get_page_and_type(mfn_to_page(cr3_pfn), d, - PGT_base_page_table)) ) + if ( !mfn_valid(cr3_pfn) || !get_page(cr3_page, d) ) { - cr3_pfn = pagetable_get_pfn(v->arch.guest_table); - v->arch.guest_table = pagetable_null(); - if ( paging_mode_refcounts(d) ) - put_page(mfn_to_page(cr3_pfn)); - else - put_page_and_type(mfn_to_page(cr3_pfn)); - destroy_gdt(v); - return -EINVAL; + cr3_page = NULL; + rc = -EINVAL; + } + else if ( !paging_mode_refcounts(d) ) + { + 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_pfn(cr3_pfn); + if ( !rc ) + v->arch.guest_table_user = pagetable_from_pfn(cr3_pfn); } else if ( !(flags & VGCF_in_kernel) ) { - destroy_gdt(v); - return -EINVAL; + cr3_page = NULL; + rc = -EINVAL; } } else { l4_pgentry_t *l4tab; - cr3_pfn = gmfn_to_mfn(d, compat_cr3_to_pfn(c.cmp->ctrlreg[3])); - - if ( !mfn_valid(cr3_pfn) || - (paging_mode_refcounts(d) - ? !get_page(mfn_to_page(cr3_pfn), d) - : !get_page_and_type(mfn_to_page(cr3_pfn), d, - PGT_l3_page_table)) ) - { - destroy_gdt(v); - return -EINVAL; - } - l4tab = __va(pagetable_get_paddr(v->arch.guest_table)); *l4tab = l4e_from_pfn( cr3_pfn, _PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED); #endif } + 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 67e0e5e..5fe393f 100644 --- a/xen/common/compat/domain.c +++ b/xen/common/compat/domain.c @@ -52,6 +52,10 @@ int compat_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg) rc = boot_vcpu(d, vcpuid, 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 4f2efe5..5fa045b 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -842,6 +842,11 @@ long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg) domain_unlock(d); xfree(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 65e30df..c3240db 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -318,6 +318,10 @@ long do_domctl(XEN_GUEST_HANDLE(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); } svc_out: -- generated by git-patchbot for /home/xen/git/xen.git#stable-4.1 _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |