[PATCH] KVM: x86/xen: Fix data race on poll event channel

Chengfeng Ye <[email protected]>
Newsgroups org.kernel.vger.kvm,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <[email protected]>
Use READ_ONCE() and WRITE_ONCE() for runtime accesses to poll_evtchn.
This marks the intentionally concurrent scalar accesses and prevents the
compiler from splitting, merging, or inventing accesses.

kvm_xen_schedop_poll() publishes the single port, or -1 for multiple
ports, before setting poll_mask and halting the vCPU.  Event delivery can
call kvm_xen_check_poller() on another CPU while the vCPU thread publishes
that value or resets the field to zero after returning from
kvm_vcpu_halt():

  vCPU thread                         event delivery thread
  -----------                         ---------------------
  poll_evtchn = port
  set_bit(poll_mask)
  kvm_vcpu_halt()
                                      poll_evtchn = READ
  poll_evtchn = 0
  clear_bit(poll_mask)

The plain read and writes therefore race.  KCSAN reported:

  BUG: KCSAN: data-race in kvm_xen_hypercall / kvm_xen_set_evtchn_fast

  read to 0xffff888112f55af0 of 4 bytes by task 98:
   kvm_xen_set_evtchn_fast+0x204/0x7c0
   kvm_xen_hvm_evtchn_send+0xab/0x100
   kvm_arch_vm_ioctl+0xb31/0xd90
   kvm_vm_ioctl+0xf42/0x16c0

  write to 0xffff888112f55af0 of 4 bytes by task 96:
   kvm_xen_hypercall+0xd8d/0xf50
   kvm_emulate_hypercall+0x157/0x1d0
   vmx_handle_exit+0x40f/0xae0
   vcpu_run+0x137f/0x27d0
   kvm_arch_vcpu_ioctl_run+0x5a5/0x970

The field is an aligned int on x86.  Access annotations preserve the
existing matching, callback, and poll-mask control flow while making the
single-copy access requirement explicit.

Fixes: 1a65105a5aba ("KVM: x86/xen: handle PV spinlocks slowpath")
Cc: [email protected]
Signed-off-by: Chengfeng Ye <[email protected]>
---
 arch/x86/kvm/xen.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index eae17141773a..cd15d2379616 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -1536,9 +1536,9 @@ static bool kvm_xen_schedop_poll(struct kvm_vcpu *vcpu, bool longmode,
 	}
 
 	if (sched_poll.nr_ports == 1)
-		vcpu->arch.xen.poll_evtchn = port;
+		WRITE_ONCE(vcpu->arch.xen.poll_evtchn, port);
 	else
-		vcpu->arch.xen.poll_evtchn = -1;
+		WRITE_ONCE(vcpu->arch.xen.poll_evtchn, -1);
 
 	set_bit(vcpu->vcpu_idx, vcpu->kvm->arch.xen.poll_mask);
 
@@ -1557,7 +1557,7 @@ static bool kvm_xen_schedop_poll(struct kvm_vcpu *vcpu, bool longmode,
 		kvm_set_mp_state(vcpu, KVM_MP_STATE_RUNNABLE);
 	}
 
-	vcpu->arch.xen.poll_evtchn = 0;
+	WRITE_ONCE(vcpu->arch.xen.poll_evtchn, 0);
 	*r = 0;
 out:
 	/* Really, this is only needed in case of timeout */
@@ -1773,7 +1773,7 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
 
 static void kvm_xen_check_poller(struct kvm_vcpu *vcpu, int port)
 {
-	int poll_evtchn = vcpu->arch.xen.poll_evtchn;
+	int poll_evtchn = READ_ONCE(vcpu->arch.xen.poll_evtchn);
 
 	if ((poll_evtchn == port || poll_evtchn == -1) &&
 	    test_and_clear_bit(vcpu->vcpu_idx, vcpu->kvm->arch.xen.poll_mask)) {

base-commit: 388b607d107c07aaade04c7f22f344cab6bdccd3
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.