diff options
author | Tim Deegan <tim@xen.org> | 2012-12-04 18:38:05 +0000 |
---|---|---|
committer | Tim Deegan <tim@xen.org> | 2012-12-04 18:38:05 +0000 |
commit | 24ff9723e0398e78355ea4b83df50eafb154d4dc (patch) | |
tree | 86ce84a13a30a696e8c0a2008a61a7608758856a /xen/arch/x86/hvm/hvm.c | |
parent | 23d9492080ae7ce6e281b6ccae1ecff9d4d9ea3a (diff) | |
download | xen-24ff9723e0398e78355ea4b83df50eafb154d4dc.tar.gz xen-24ff9723e0398e78355ea4b83df50eafb154d4dc.tar.bz2 xen-24ff9723e0398e78355ea4b83df50eafb154d4dc.zip |
hvm: Limit the size of large HVM op batches
Doing large p2m updates for HVMOP_track_dirty_vram without preemption
ties up the physical processor. Integrating preemption into the p2m
updates is hard so simply limit to 1GB which is sufficient for a 15000
* 15000 * 32bpp framebuffer.
For HVMOP_modified_memory and HVMOP_set_mem_type preemptible add the
necessary machinery to handle preemption.
This is CVE-2012-5511 / XSA-27.
Signed-off-by: Tim Deegan <tim@xen.org>
Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Committed-by: Ian Jackson <ian.jackson.citrix.com>
Diffstat (limited to 'xen/arch/x86/hvm/hvm.c')
-rw-r--r-- | xen/arch/x86/hvm/hvm.c | 38 |
1 files changed, 34 insertions, 4 deletions
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 34da2f5da9..2d46d98626 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -3984,6 +3984,9 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) if ( !is_hvm_domain(d) ) goto param_fail2; + if ( a.nr > GB(1) >> PAGE_SHIFT ) + goto param_fail2; + rc = xsm_hvm_param(d, op); if ( rc ) goto param_fail2; @@ -4010,7 +4013,6 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) { struct xen_hvm_modified_memory a; struct domain *d; - unsigned long pfn; if ( copy_from_guest(&a, arg, 1) ) return -EFAULT; @@ -4037,9 +4039,11 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) if ( !paging_mode_log_dirty(d) ) goto param_fail3; - for ( pfn = a.first_pfn; pfn < a.first_pfn + a.nr; pfn++ ) + while ( a.nr > 0 ) { + unsigned long pfn = a.first_pfn; struct page_info *page; + page = get_page_from_gfn(d, pfn, NULL, P2M_UNSHARE); if ( page ) { @@ -4049,6 +4053,19 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) sh_remove_shadows(d->vcpu[0], _mfn(page_to_mfn(page)), 1, 0); put_page(page); } + + a.first_pfn++; + a.nr--; + + /* Check for continuation if it's not the last interation */ + if ( a.nr > 0 && hypercall_preempt_check() ) + { + if ( copy_to_guest(arg, &a, 1) ) + rc = -EFAULT; + else + rc = -EAGAIN; + break; + } } param_fail3: @@ -4104,7 +4121,6 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) { struct xen_hvm_set_mem_type a; struct domain *d; - unsigned long pfn; /* Interface types to internal p2m types */ p2m_type_t memtype[] = { @@ -4137,8 +4153,9 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) if ( a.hvmmem_type >= ARRAY_SIZE(memtype) ) goto param_fail4; - for ( pfn = a.first_pfn; pfn < a.first_pfn + a.nr; pfn++ ) + while ( a.nr ) { + unsigned long pfn = a.first_pfn; p2m_type_t t; p2m_type_t nt; mfn_t mfn; @@ -4178,6 +4195,19 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) } } put_gfn(d, pfn); + + a.first_pfn++; + a.nr--; + + /* Check for continuation if it's not the last interation */ + if ( a.nr > 0 && hypercall_preempt_check() ) + { + if ( copy_to_guest(arg, &a, 1) ) + rc = -EFAULT; + else + rc = -EAGAIN; + goto param_fail4; + } } rc = 0; |