aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2013-05-02 16:36:44 +0200
committerJan Beulich <jbeulich@suse.com>2013-05-02 16:36:44 +0200
commit918a5f17b447072b40780f4d03a3adc99ff0073b (patch)
tree4cf38590948483a3493a22101dc082fed139332c
parente2e6b7b627fec0d7a769ab46441f2985ebccbf04 (diff)
downloadxen-918a5f17b447072b40780f4d03a3adc99ff0073b.tar.gz
xen-918a5f17b447072b40780f4d03a3adc99ff0073b.tar.bz2
xen-918a5f17b447072b40780f4d03a3adc99ff0073b.zip
x86: make MMUEXT_NEW_USER_BASEPTR preemptible
... as it may take significant amounts of time. This is part of CVE-2013-1918 / XSA-45. Signed-off-by: Jan Beulich <jbeulich@suse.com> Acked-by: Tim Deegan <tim@xen.org>
-rw-r--r--xen/arch/x86/mm.c39
1 files changed, 33 insertions, 6 deletions
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index e43a698791..bada0bdd36 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -3037,29 +3037,56 @@ long do_mmuext_op(
break;
}
+ old_mfn = pagetable_get_pfn(curr->arch.guest_table_user);
+ /*
+ * This is particularly important when getting restarted after the
+ * previous attempt got preempted in the put-old-MFN phase.
+ */
+ if ( old_mfn == op.arg1.mfn )
+ break;
+
if ( op.arg1.mfn != 0 )
{
if ( paging_mode_refcounts(d) )
okay = get_page_from_pagenr(op.arg1.mfn, d);
else
- okay = !get_page_and_type_from_pagenr(
- op.arg1.mfn, PGT_root_page_table, d, 0, 0);
+ {
+ rc = get_page_and_type_from_pagenr(
+ op.arg1.mfn, PGT_root_page_table, d, 0, 1);
+ okay = !rc;
+ }
if ( unlikely(!okay) )
{
- MEM_LOG("Error while installing new mfn %lx", op.arg1.mfn);
+ if ( rc == -EINTR )
+ rc = -EAGAIN;
+ else if ( rc != -EAGAIN )
+ MEM_LOG("Error while installing new mfn %lx",
+ op.arg1.mfn);
break;
}
}
- old_mfn = pagetable_get_pfn(curr->arch.guest_table_user);
curr->arch.guest_table_user = pagetable_from_pfn(op.arg1.mfn);
if ( old_mfn != 0 )
{
+ struct page_info *page = mfn_to_page(old_mfn);
+
if ( paging_mode_refcounts(d) )
- put_page(mfn_to_page(old_mfn));
+ put_page(page);
else
- put_page_and_type(mfn_to_page(old_mfn));
+ switch ( rc = put_page_and_type_preemptible(page, 1) )
+ {
+ case -EINTR:
+ rc = -EAGAIN;
+ case -EAGAIN:
+ curr->arch.old_guest_table = page;
+ okay = 0;
+ break;
+ default:
+ BUG_ON(rc);
+ break;
+ }
}
break;