All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH,stable-v4.19] KVM: arm/arm64: Fix VMID alloc race by reverting to lock-less
@ 2019-01-09 11:35 Christoffer Dall
  2019-01-15 15:39 ` Greg KH
  0 siblings, 1 reply; 2+ messages in thread
From: Christoffer Dall @ 2019-01-09 11:35 UTC (permalink / raw)
  To: stable; +Cc: Christoffer Dall, Marc Zyngier

Commit fb544d1ca65a89f7a3895f7531221ceeed74ada7 upstream.

We recently addressed a VMID generation race by introducing a read/write
lock around accesses and updates to the vmid generation values.

However, kvm_arch_vcpu_ioctl_run() also calls need_new_vmid_gen() but
does so without taking the read lock.

As far as I can tell, this can lead to the same kind of race:

  VM 0, VCPU 0			VM 0, VCPU 1
  ------------			------------
  update_vttbr (vmid 254)
  				update_vttbr (vmid 1) // roll over
				read_lock(kvm_vmid_lock);
				force_vm_exit()
  local_irq_disable
  need_new_vmid_gen == false //because vmid gen matches

  enter_guest (vmid 254)
  				kvm_arch.vttbr = <PGD>:<VMID 1>
				read_unlock(kvm_vmid_lock);

  				enter_guest (vmid 1)

Which results in running two VCPUs in the same VM with different VMIDs
and (even worse) other VCPUs from other VMs could now allocate clashing
VMID 254 from the new generation as long as VCPU 0 is not exiting.

Attempt to solve this by making sure vttbr is updated before another CPU
can observe the updated VMID generation.

Change-Id: I40aae6e89a3c8a496e13fcd8ae6bb663d16b057c
Cc: stable@vger.kernel.org # v4.19
Fixes: f0cf47d939d0 "KVM: arm/arm64: Close VMID generation race"
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/arm.c | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 8fb31a7cc22c..91495045ad5a 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -66,7 +66,7 @@ static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_arm_running_vcpu);
 static atomic64_t kvm_vmid_gen = ATOMIC64_INIT(1);
 static u32 kvm_next_vmid;
 static unsigned int kvm_vmid_bits __read_mostly;
-static DEFINE_RWLOCK(kvm_vmid_lock);
+static DEFINE_SPINLOCK(kvm_vmid_lock);
 
 static bool vgic_present;
 
@@ -482,7 +482,9 @@ void force_vm_exit(const cpumask_t *mask)
  */
 static bool need_new_vmid_gen(struct kvm *kvm)
 {
-	return unlikely(kvm->arch.vmid_gen != atomic64_read(&kvm_vmid_gen));
+	u64 current_vmid_gen = atomic64_read(&kvm_vmid_gen);
+	smp_rmb(); /* Orders read of kvm_vmid_gen and kvm->arch.vmid */
+	return unlikely(READ_ONCE(kvm->arch.vmid_gen) != current_vmid_gen);
 }
 
 /**
@@ -497,16 +499,11 @@ static void update_vttbr(struct kvm *kvm)
 {
 	phys_addr_t pgd_phys;
 	u64 vmid;
-	bool new_gen;
 
-	read_lock(&kvm_vmid_lock);
-	new_gen = need_new_vmid_gen(kvm);
-	read_unlock(&kvm_vmid_lock);
-
-	if (!new_gen)
+	if (!need_new_vmid_gen(kvm))
 		return;
 
-	write_lock(&kvm_vmid_lock);
+	spin_lock(&kvm_vmid_lock);
 
 	/*
 	 * We need to re-check the vmid_gen here to ensure that if another vcpu
@@ -514,7 +511,7 @@ static void update_vttbr(struct kvm *kvm)
 	 * use the same vmid.
 	 */
 	if (!need_new_vmid_gen(kvm)) {
-		write_unlock(&kvm_vmid_lock);
+		spin_unlock(&kvm_vmid_lock);
 		return;
 	}
 
@@ -537,7 +534,6 @@ static void update_vttbr(struct kvm *kvm)
 		kvm_call_hyp(__kvm_flush_vm_context);
 	}
 
-	kvm->arch.vmid_gen = atomic64_read(&kvm_vmid_gen);
 	kvm->arch.vmid = kvm_next_vmid;
 	kvm_next_vmid++;
 	kvm_next_vmid &= (1 << kvm_vmid_bits) - 1;
@@ -548,7 +544,10 @@ static void update_vttbr(struct kvm *kvm)
 	vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK(kvm_vmid_bits);
 	kvm->arch.vttbr = kvm_phys_to_vttbr(pgd_phys) | vmid;
 
-	write_unlock(&kvm_vmid_lock);
+	smp_wmb();
+	WRITE_ONCE(kvm->arch.vmid_gen, atomic64_read(&kvm_vmid_gen));
+
+	spin_unlock(&kvm_vmid_lock);
 }
 
 static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH,stable-v4.19] KVM: arm/arm64: Fix VMID alloc race by reverting to lock-less
  2019-01-09 11:35 [PATCH,stable-v4.19] KVM: arm/arm64: Fix VMID alloc race by reverting to lock-less Christoffer Dall
@ 2019-01-15 15:39 ` Greg KH
  0 siblings, 0 replies; 2+ messages in thread
From: Greg KH @ 2019-01-15 15:39 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: stable, Marc Zyngier

On Wed, Jan 09, 2019 at 12:35:11PM +0100, Christoffer Dall wrote:
> Commit fb544d1ca65a89f7a3895f7531221ceeed74ada7 upstream.
> 
> We recently addressed a VMID generation race by introducing a read/write
> lock around accesses and updates to the vmid generation values.
> 
> However, kvm_arch_vcpu_ioctl_run() also calls need_new_vmid_gen() but
> does so without taking the read lock.
> 
> As far as I can tell, this can lead to the same kind of race:
> 
>   VM 0, VCPU 0			VM 0, VCPU 1
>   ------------			------------
>   update_vttbr (vmid 254)
>   				update_vttbr (vmid 1) // roll over
> 				read_lock(kvm_vmid_lock);
> 				force_vm_exit()
>   local_irq_disable
>   need_new_vmid_gen == false //because vmid gen matches
> 
>   enter_guest (vmid 254)
>   				kvm_arch.vttbr = <PGD>:<VMID 1>
> 				read_unlock(kvm_vmid_lock);
> 
>   				enter_guest (vmid 1)
> 
> Which results in running two VCPUs in the same VM with different VMIDs
> and (even worse) other VCPUs from other VMs could now allocate clashing
> VMID 254 from the new generation as long as VCPU 0 is not exiting.
> 
> Attempt to solve this by making sure vttbr is updated before another CPU
> can observe the updated VMID generation.
> 
> Change-Id: I40aae6e89a3c8a496e13fcd8ae6bb663d16b057c
> Cc: stable@vger.kernel.org # v4.19
> Fixes: f0cf47d939d0 "KVM: arm/arm64: Close VMID generation race"
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  virt/kvm/arm/arm.c | 23 +++++++++++------------
>  1 file changed, 11 insertions(+), 12 deletions(-)

Both patches now queued up, thanks.

greg k-h

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2019-01-15 15:39 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-09 11:35 [PATCH,stable-v4.19] KVM: arm/arm64: Fix VMID alloc race by reverting to lock-less Christoffer Dall
2019-01-15 15:39 ` Greg KH

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.