$NetBSD: patch-CVE-2013-1918_8,v 1.1 2013/05/03 16:48:38 drochner Exp $

--- xen/arch/x86/x86_64/compat/mm.c.orig	2013-05-03 13:37:44.000000000 +0000
+++ xen/arch/x86/x86_64/compat/mm.c
@@ -222,6 +222,13 @@ int compat_mmuext_op(XEN_GUEST_HANDLE(mm
     int rc = 0;
     XEN_GUEST_HANDLE(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;
 
@@ -319,17 +326,23 @@ int compat_mmuext_op(XEN_GUEST_HANDLE(mm
                                     : mcs->call.args[1];
                 unsigned int left = arg1 & ~MMU_UPDATE_PREEMPTED;
 
-                BUG_ON(left == arg1);
+                BUG_ON(left == arg1 && left != i);
                 BUG_ON(left > count);
                 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);
