]> xenbits.xensource.com Git - people/vhanquez/xen.git/commitdiff
x86, shadow: Fix read-to-use race condition
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 12 Apr 2010 17:13:26 +0000 (18:13 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 12 Apr 2010 17:13:26 +0000 (18:13 +0100)
If OOS mode is enabled, after last possible resync, read the guest l1e
one last time.  If it's different than the original read, start over
again.

This fixes a race which can result in inconsistent in-sync shadow
tables, leading to corruption:

v1: take page fault, read gl1e from an out-of-sync PT.
v2: modify gl1e, lowering permissions
[v1,v3]: resync l1 which was just read.
v1: propagate change to l1 shadow using stale gl1e

Now we have an in-sync shadow with more permissions than the guest.

The resync can happen either as a result of a 3rd vcpu doing a cr3
update, or under certain conditions by v1 itself.

Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com>
xen-unstable changeset:   21150:78488a63bbc2
xen-unstable date:        Mon Apr 12 17:51:56 2010 +0100

xen/arch/x86/mm/shadow/multi.c

index 0be7179afb2dbc9c4379090b3c3e952d5cfef3b0..08384b581d61628becf415191af3ea00eec2dcdc 100644 (file)
@@ -240,6 +240,23 @@ shadow_check_gwalk(struct vcpu *v, unsigned long va, walk_t *gw, int version)
     return !mismatch;
 }
 
+static int
+shadow_check_gl1e(struct vcpu *v, walk_t *gw)
+{
+    guest_l1e_t *l1p, nl1e;
+
+    if ( !mfn_valid(gw->l1mfn) )
+        return 0;
+
+    /* Can't just pull-through because mfn may have changed */
+    l1p = map_domain_page(mfn_x(gw->l1mfn));
+    nl1e.l1 = l1p[guest_l1_table_offset(gw->va)].l1;
+    unmap_domain_page(l1p);
+
+    return gw->l1e.l1 != nl1e.l1;
+}
+
+
 /* Remove write access permissions from a gwalk_t in a batch, and
  * return OR-ed result for TLB flush hint and need to rewalk the guest
  * pages.
@@ -3210,6 +3227,15 @@ static int sh_page_fault(struct vcpu *v,
         shadow_unlock(d);
         return 0;
     }
+
+    /* Final check: if someone has synced a page, it's possible that
+     * our l1e is stale.  Compare the entries, and rewalk if necessary. */
+    if ( shadow_check_gl1e(v, &gw)  )
+    {
+        perfc_incr(shadow_inconsistent_gwalk);
+        shadow_unlock(d);
+        goto rewalk;
+    }
 #endif /* OOS */
 
     /* Calculate the shadow entry and write it */