diff options
author | Jan Beulich <jbeulich@suse.com> | 2013-05-02 16:39:06 +0200 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2013-05-02 16:39:06 +0200 |
commit | a3e049f8e86fe18e3b87f18dc0c7be665026fd9f (patch) | |
tree | 8916d16e86cdefada74e050c0ffaf145f47439eb /xen/arch/x86/x86_64 | |
parent | 99d2b149915010e986f4d8778708c5891e7b4635 (diff) | |
download | xen-a3e049f8e86fe18e3b87f18dc0c7be665026fd9f.tar.gz xen-a3e049f8e86fe18e3b87f18dc0c7be665026fd9f.tar.bz2 xen-a3e049f8e86fe18e3b87f18dc0c7be665026fd9f.zip |
x86: make page table unpinning preemptible
... as it may take significant amounts of time.
Since we can't re-invoke the operation in a second attempt, the
continuation logic must be slightly tweaked so that we make sure
do_mmuext_op() gets run one more time even when the preempted unpin
operation was the last one in a batch.
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/arch/x86/x86_64')
-rw-r--r-- | xen/arch/x86/x86_64/compat/mm.c | 23 |
1 files changed, 18 insertions, 5 deletions
diff --git a/xen/arch/x86/x86_64/compat/mm.c b/xen/arch/x86/x86_64/compat/mm.c index 9adc4b472b..f01f8ff8a6 100644 --- a/xen/arch/x86/x86_64/compat/mm.c +++ b/xen/arch/x86/x86_64/compat/mm.c @@ -268,6 +268,13 @@ int compat_mmuext_op(XEN_GUEST_HANDLE_PARAM(mmuext_op_compat_t) cmp_uops, int rc = 0; XEN_GUEST_HANDLE_PARAM(mmuext_op_t) nat_ops; + if ( unlikely(count == MMU_UPDATE_PREEMPTED) && + likely(guest_handle_is_null(cmp_uops)) ) + { + set_xen_guest_handle(nat_ops, NULL); + return do_mmuext_op(nat_ops, count, pdone, foreigndom); + } + preempt_mask = count & MMU_UPDATE_PREEMPTED; count ^= preempt_mask; @@ -370,12 +377,18 @@ int compat_mmuext_op(XEN_GUEST_HANDLE_PARAM(mmuext_op_compat_t) cmp_uops, guest_handle_add_offset(nat_ops, i - left); guest_handle_subtract_offset(cmp_uops, left); left = 1; - BUG_ON(!hypercall_xlat_continuation(&left, 0x01, nat_ops, cmp_uops)); - BUG_ON(left != arg1); - if (!test_bit(_MCSF_in_multicall, &mcs->flags)) - regs->_ecx += count - i; + if ( arg1 != MMU_UPDATE_PREEMPTED ) + { + BUG_ON(!hypercall_xlat_continuation(&left, 0x01, nat_ops, + cmp_uops)); + if ( !test_bit(_MCSF_in_multicall, &mcs->flags) ) + regs->_ecx += count - i; + else + mcs->compat_call.args[1] += count - i; + } else - mcs->compat_call.args[1] += count - i; + BUG_ON(hypercall_xlat_continuation(&left, 0)); + BUG_ON(left != arg1); } else BUG_ON(err > 0); |