There are race conditions possible due to kvm_gfn_to_pfn_cache_init()'s ability to _re_initialize gfn_to_pfn_cache.lock. For example: a race between ioctl(KVM_XEN_HVM_EVTCHN_SEND) and kvm_gfn_to_pfn_cache_init() leads to a corrupted shinfo gpc lock. (thread 1) | (thread 2) | kvm_xen_set_evtchn_fast | read_lock_irqsave(&gpc->lock, ...) | | kvm_gfn_to_pfn_cache_init | rwlock_init(&gpc->lock) read_unlock_irqrestore(&gpc->lock, ...) | Introduce bool locks_initialized. Signed-off-by: Michal Luczaj <mhal@xxxxxxx> --- include/linux/kvm_types.h | 1 + virt/kvm/pfncache.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h index 3ca3db020e0e..7e7b7667cd9e 100644 --- a/include/linux/kvm_types.h +++ b/include/linux/kvm_types.h @@ -74,6 +74,7 @@ struct gfn_to_pfn_cache { void *khva; kvm_pfn_t pfn; enum pfn_cache_usage usage; + bool locks_initialized; bool active; bool valid; }; diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 68ff41d39545..564607e10586 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -354,8 +354,11 @@ int kvm_gfn_to_pfn_cache_init(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, WARN_ON_ONCE(!usage || (usage & KVM_GUEST_AND_HOST_USE_PFN) != usage); if (!gpc->active) { - rwlock_init(&gpc->lock); - mutex_init(&gpc->refresh_lock); + if (!gpc->locks_initialized) { + rwlock_init(&gpc->lock); + mutex_init(&gpc->refresh_lock); + gpc->locks_initialized = true; + } gpc->khva = NULL; gpc->pfn = KVM_PFN_ERR_FAULT; -- 2.37.2