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
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.
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 */