]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 15 Jan 2019 15:46:37 +0000 (16:46 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 15 Jan 2019 15:46:37 +0000 (16:46 +0100)
added patches:
kvm-arm-arm64-fix-vmid-alloc-race-by-reverting-to-lock-less.patch

queue-4.14/kvm-arm-arm64-fix-vmid-alloc-race-by-reverting-to-lock-less.patch [new file with mode: 0644]
queue-4.14/series

diff --git a/queue-4.14/kvm-arm-arm64-fix-vmid-alloc-race-by-reverting-to-lock-less.patch b/queue-4.14/kvm-arm-arm64-fix-vmid-alloc-race-by-reverting-to-lock-less.patch
new file mode 100644 (file)
index 0000000..a02aa7e
--- /dev/null
@@ -0,0 +1,120 @@
+From fb544d1ca65a89f7a3895f7531221ceeed74ada7 Mon Sep 17 00:00:00 2001
+From: Christoffer Dall <christoffer.dall@arm.com>
+Date: Tue, 11 Dec 2018 13:23:57 +0100
+Subject: KVM: arm/arm64: Fix VMID alloc race by reverting to lock-less
+
+From: Christoffer Dall <christoffer.dall@arm.com>
+
+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.
+
+Cc: stable@vger.kernel.org
+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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ virt/kvm/arm/arm.c |   23 +++++++++++------------
+ 1 file changed, 11 insertions(+), 12 deletions(-)
+
+--- a/virt/kvm/arm/arm.c
++++ b/virt/kvm/arm/arm.c
+@@ -61,7 +61,7 @@ static DEFINE_PER_CPU(struct kvm_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;
+@@ -447,7 +447,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);
+ }
+ /**
+@@ -462,16 +464,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
+@@ -479,7 +476,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;
+       }
+@@ -502,7 +499,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;
+@@ -513,7 +509,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 = 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)
index c4a263302fb9c5562e058ad4a234a135b8209612..2bf937706847ca920b2d263726e68ec016c29eb0 100644 (file)
@@ -24,3 +24,4 @@ ext4-avoid-kernel-warning-when-writing-the-superblock-to-a-dead-device.patch
 ext4-use-ext4_write_inode-when-fsyncing-w-o-a-journal.patch
 ext4-track-writeback-errors-using-the-generic-tracking-infrastructure.patch
 sunrpc-use-after-free-in-svc_process_common.patch
+kvm-arm-arm64-fix-vmid-alloc-race-by-reverting-to-lock-less.patch