kvm_xen_set_evtchn_fast() assumes the port range check in max_evtchn_port() and the bitmap layout selection observe the same long_mode, but each reads kvm->arch.xen.long_mode separately. If the guest changes long_mode in between, a port accepted by the 64-bit range check is handled with the 32-bit layout, and port_word_bit falls outside evtchn_pending_sel. Read long_mode once on entry so the range check and both layout computations use the same value. Since max_evtchn_port() reads long_mode as well, compute the bound directly from the latched value. Fixes: 14243b387137 ("KVM: x86/xen: Add KVM_IRQ_ROUTING_XEN_EVTCHN and event channel delivery") Signed-off-by: Hyunwoo Kim --- arch/x86/kvm/xen.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 91fd3673c09a..4d8337abf0fa 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -1798,6 +1798,7 @@ int kvm_xen_set_evtchn_fast(struct kvm_xen_evtchn *xe, struct kvm *kvm) int port_word_bit; bool kick_vcpu = false; int vcpu_idx, idx, rc; + bool long_mode; vcpu_idx = READ_ONCE(xe->vcpu_idx); if (vcpu_idx >= 0) @@ -1809,7 +1810,10 @@ int kvm_xen_set_evtchn_fast(struct kvm_xen_evtchn *xe, struct kvm *kvm) WRITE_ONCE(xe->vcpu_idx, vcpu->vcpu_idx); } - if (xe->port >= max_evtchn_port(kvm)) + long_mode = IS_ENABLED(CONFIG_64BIT) && READ_ONCE(kvm->arch.xen.long_mode); + + if (xe->port >= (long_mode ? EVTCHN_2L_NR_CHANNELS : + COMPAT_EVTCHN_2L_NR_CHANNELS)) return -EINVAL; rc = -EWOULDBLOCK; @@ -1820,7 +1824,7 @@ int kvm_xen_set_evtchn_fast(struct kvm_xen_evtchn *xe, struct kvm *kvm) if (!kvm_gpc_check(gpc, PAGE_SIZE)) goto out_rcu; - if (IS_ENABLED(CONFIG_64BIT) && kvm->arch.xen.long_mode) { + if (long_mode) { struct shared_info *shinfo = gpc->khva; pending_bits = (unsigned long *)&shinfo->evtchn_pending; mask_bits = (unsigned long *)&shinfo->evtchn_mask; @@ -1861,7 +1865,7 @@ int kvm_xen_set_evtchn_fast(struct kvm_xen_evtchn *xe, struct kvm *kvm) goto out_rcu; } - if (IS_ENABLED(CONFIG_64BIT) && kvm->arch.xen.long_mode) { + if (long_mode) { struct vcpu_info *vcpu_info = gpc->khva; if (!test_and_set_bit(port_word_bit, &vcpu_info->evtchn_pending_sel)) { WRITE_ONCE(vcpu_info->evtchn_upcall_pending, 1); -- 2.43.0