77 lines
2.7 KiB
Diff
77 lines
2.7 KiB
Diff
|
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>
|
||
|
|
||
|
Index: xen-4.2.1-testing/xen/arch/x86/mm.c
|
||
|
===================================================================
|
||
|
--- xen-4.2.1-testing.orig/xen/arch/x86/mm.c
|
||
|
+++ xen-4.2.1-testing/xen/arch/x86/mm.c
|
||
|
@@ -3313,29 +3313,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;
|