]> xenbits.xensource.com Git - xen.git/commitdiff
gnttab: correct maptrack table accesses
authorJan Beulich <jbeulich@suse.com>
Tue, 20 Jun 2017 14:01:24 +0000 (16:01 +0200)
committerJan Beulich <jbeulich@suse.com>
Tue, 20 Jun 2017 14:01:24 +0000 (16:01 +0200)
In order to observe a consistent (limit,pointer-table) pair, the reader
needs to either hold the maptrack lock (in line with documentation) or
both sides need to order their accesses suitably (the writer side
barrier was removed by commit dff515dfea ["gnttab: use per-VCPU
maptrack free lists"], and a read side barrier has never been there).

Make the writer publish a new table page before limit (for bounds
checks to work), and new list head last (for racing maptrack_entry()
invocations to work). At the same time add read barriers to lockless
readers.

Additionally get_maptrack_handle() must not assume ->maptrack_head to
not change behind its back: Another handle may be put (updating only
->maptrack_tail) and then got or stolen (updating ->maptrack_head).

This is part of XSA-218.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: George Dunlap <george.dunlap@citrix.com>
master commit: 4b78efa91c8ae3c42e14b8eaeaad773c5eb3b71a
master date: 2017-06-20 14:34:34 +0200

xen/common/grant_table.c

index f94fa7e2da4a0da778f2c0e96110e5ca8ed34632..b5f74c2c9a1e3f5c8911a2b654d117bb645d7cd3 100644 (file)
@@ -395,7 +395,7 @@ get_maptrack_handle(
     struct grant_table *lgt)
 {
     struct vcpu          *curr = current;
-    int                   i;
+    unsigned int          i, head;
     grant_handle_t        handle;
     struct grant_mapping *new_mt;
 
@@ -451,17 +451,20 @@ get_maptrack_handle(
         new_mt[i].ref = handle + i + 1;
         new_mt[i].vcpu = curr->vcpu_id;
     }
-    new_mt[i - 1].ref = curr->maptrack_head;
 
     /* Set tail directly if this is the first page for this VCPU. */
     if ( curr->maptrack_tail == MAPTRACK_TAIL )
         curr->maptrack_tail = handle + MAPTRACK_PER_PAGE - 1;
 
-    write_atomic(&curr->maptrack_head, handle + 1);
-
     lgt->maptrack[nr_maptrack_frames(lgt)] = new_mt;
+    smp_wmb();
     lgt->maptrack_limit += MAPTRACK_PER_PAGE;
 
+    do {
+        new_mt[i - 1].ref = read_atomic(&curr->maptrack_head);
+        head = cmpxchg(&curr->maptrack_head, new_mt[i - 1].ref, handle + 1);
+    } while ( head != new_mt[i - 1].ref );
+
     spin_unlock(&lgt->maptrack_lock);
 
     return handle;
@@ -727,6 +730,7 @@ static unsigned int mapkind(
     for ( handle = 0; !(kind & MAPKIND_WRITE) &&
                       handle < lgt->maptrack_limit; handle++ )
     {
+        smp_rmb();
         map = &maptrack_entry(lgt, handle);
         if ( !(map->flags & (GNTMAP_device_map|GNTMAP_host_map)) ||
              map->domid != rd->domain_id )
@@ -1094,6 +1098,7 @@ __gnttab_unmap_common(
         return;
     }
 
+    smp_rmb();
     map = &maptrack_entry(lgt, op->handle);
 
     grant_read_lock(lgt);