[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen stable-4.14] xen/evtchn: Add missing barriers when accessing/allocating an event channel
commit f5469067ee0260673ca1e554ff8888512a55ccfc Author: Julien Grall <jgrall@xxxxxxxxxx> AuthorDate: Tue Sep 22 16:13:08 2020 +0200 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Tue Sep 22 16:13:08 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#stable-4.14
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |