debuggers.hg

changeset 21196:78488a63bbc2

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>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Apr 12 17:51:56 2010 +0100 (2010-04-12)
parents b010b792c0f8
children 94cae4dfa25b
files xen/arch/x86/mm/shadow/multi.c
line diff
     1.1 --- a/xen/arch/x86/mm/shadow/multi.c	Mon Apr 12 17:47:16 2010 +0100
     1.2 +++ b/xen/arch/x86/mm/shadow/multi.c	Mon Apr 12 17:51:56 2010 +0100
     1.3 @@ -241,6 +241,23 @@ shadow_check_gwalk(struct vcpu *v, unsig
     1.4      return !mismatch;
     1.5  }
     1.6  
     1.7 +static int
     1.8 +shadow_check_gl1e(struct vcpu *v, walk_t *gw)
     1.9 +{
    1.10 +    guest_l1e_t *l1p, nl1e;
    1.11 +
    1.12 +    if ( !mfn_valid(gw->l1mfn) )
    1.13 +        return 0;
    1.14 +
    1.15 +    /* Can't just pull-through because mfn may have changed */
    1.16 +    l1p = map_domain_page(mfn_x(gw->l1mfn));
    1.17 +    nl1e.l1 = l1p[guest_l1_table_offset(gw->va)].l1;
    1.18 +    unmap_domain_page(l1p);
    1.19 +
    1.20 +    return gw->l1e.l1 != nl1e.l1;
    1.21 +}
    1.22 +
    1.23 +
    1.24  /* Remove write access permissions from a gwalk_t in a batch, and
    1.25   * return OR-ed result for TLB flush hint and need to rewalk the guest
    1.26   * pages.
    1.27 @@ -3237,6 +3254,15 @@ static int sh_page_fault(struct vcpu *v,
    1.28          shadow_unlock(d);
    1.29          return 0;
    1.30      }
    1.31 +
    1.32 +    /* Final check: if someone has synced a page, it's possible that
    1.33 +     * our l1e is stale.  Compare the entries, and rewalk if necessary. */
    1.34 +    if ( shadow_check_gl1e(v, &gw)  )
    1.35 +    {
    1.36 +        perfc_incr(shadow_inconsistent_gwalk);
    1.37 +        shadow_unlock(d);
    1.38 +        goto rewalk;
    1.39 +    }
    1.40  #endif /* OOS */
    1.41  
    1.42      /* Calculate the shadow entry and write it */