955345f274
OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=e3fceb77b1b54518068f30a555f7535a
69 lines
2.0 KiB
Diff
69 lines
2.0 KiB
Diff
# HG changeset patch
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
# Date 1271091116 -3600
|
|
# Node ID 78488a63bbc200095413824cc146134b54635da9
|
|
# Parent b010b792c0f814de725f669d8a6bee738df68963
|
|
x86, shadow: Fix read-to-use race condition
|
|
|
|
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>
|
|
|
|
--- a/xen/arch/x86/mm/shadow/multi.c
|
|
+++ b/xen/arch/x86/mm/shadow/multi.c
|
|
@@ -240,6 +240,23 @@ shadow_check_gwalk(struct vcpu *v, unsig
|
|
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.
|
|
@@ -3235,6 +3252,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 */
|