[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen staging-4.12] xen/evtchn: Add missing barriers when accessing/allocating an event channel



commit 253a1e64d30e09ae089a060e364a01b4d442d550
Author:     Julien Grall <jgrall@xxxxxxxxxx>
AuthorDate: Tue Sep 22 17:08:00 2020 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Tue Sep 22 17:08:00 2020 +0200

    xen/evtchn: Add missing barriers when accessing/allocating an event channel
    
    While the allocation of a bucket is always performed with the per-domain
    lock, the bucket may be accessed without the lock taken (for instance, see
    evtchn_send()).
    
    Instead such sites relies on port_is_valid() to return a non-zero value
    when the port has a struct evtchn associated to it. The function will
    mostly check whether the port is less than d->valid_evtchns as all the
    buckets/event channels should be allocated up to that point.
    
    Unfortunately a compiler is free to re-order the assignment in
    evtchn_allocate_port() so it would be possible to have d->valid_evtchns
    updated before the new bucket has finish to allocate.
    
    Additionally on Arm, even if this was compiled "correctly", the
    processor can still re-order the memory access.
    
    Add a write memory barrier in the allocation side and a read memory
    barrier when the port is valid to prevent any re-ordering issue.
    
    This is XSA-340.
    
    Reported-by: Julien Grall <jgrall@xxxxxxxxxx>
    Signed-off-by: Julien Grall <jgrall@xxxxxxxxxx>
    Reviewed-by: Stefano Stabellini <sstabellini@xxxxxxxxxx>
---
 xen/common/event_channel.c |  7 +++++++
 xen/include/xen/event.h    | 12 +++++++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index a8d182b584..53c17bd354 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -178,6 +178,13 @@ int evtchn_allocate_port(struct domain *d, evtchn_port_t 
port)
             return -ENOMEM;
         bucket_from_port(d, port) = chn;
 
+        /*
+         * d->valid_evtchns is used to check whether the bucket can be
+         * accessed without the per-domain lock. Therefore,
+         * d->valid_evtchns should be seen *after* the new bucket has
+         * been setup.
+         */
+        smp_wmb();
         write_atomic(&d->valid_evtchns, d->valid_evtchns + EVTCHNS_PER_BUCKET);
     }
 
diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h
index ce45298377..c35f4b23b6 100644
--- a/xen/include/xen/event.h
+++ b/xen/include/xen/event.h
@@ -107,7 +107,17 @@ void notify_via_xen_event_channel(struct domain *ld, int 
lport);
 
 static inline bool_t port_is_valid(struct domain *d, unsigned int p)
 {
-    return p < read_atomic(&d->valid_evtchns);
+    if ( p >= read_atomic(&d->valid_evtchns) )
+        return false;
+
+    /*
+     * The caller will usually access the event channel afterwards and
+     * may be done without taking the per-domain lock. The barrier is
+     * going in pair the smp_wmb() barrier in evtchn_allocate_port().
+     */
+    smp_rmb();
+
+    return true;
 }
 
 static inline struct evtchn *evtchn_from_port(struct domain *d, unsigned int p)
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.12



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.