|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen stable-4.10] xen/evtchn: Add missing barriers when accessing/allocating an event channel
commit baf80b695da1ac6ad455535ddf9030fc288513ec
Author: Julien Grall <jgrall@xxxxxxxxxx>
AuthorDate: Tue Sep 22 17:32:42 2020 +0200
Commit: Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Tue Sep 22 17:32:42 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 07ef45a140..82e42c7e32 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -185,6 +185,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 2006ba9252..70bd63423e 100644
--- a/xen/include/xen/event.h
+++ b/xen/include/xen/event.h
@@ -99,7 +99,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#stable-4.10
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |