]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: s390: Fix race in __do_essa()
authorClaudio Imbrenda <imbrenda@linux.ibm.com>
Mon, 3 Aug 2026 12:40:34 +0000 (14:40 +0200)
committerClaudio Imbrenda <imbrenda@linux.ibm.com>
Mon, 3 Aug 2026 14:51:34 +0000 (16:51 +0200)
An unlikely race between __do_essa() and kvm_s390_vm_start_migration(),
kvm_s390_vm_stop_migration(), or dat_get_cmma() was possible.

Fix by locking kvm->slots_arch_lock. Since this is not a hot path, the
overhead of an additional mutex is negligible.

Fixes: e38c884df921 ("KVM: s390: Switch to new gmap")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260803124040.126471-8-imbrenda@linux.ibm.com>

arch/s390/kvm/kvm-s390.c
arch/s390/kvm/priv.c

index e162efaa35b8fe06de5da6f48ce3ec37931bb50c..e5c5e9f61cb24b220d12a5a962f2d9cd5aae1de8 100644 (file)
@@ -1219,8 +1219,8 @@ static void kvm_s390_sync_request_broadcast(struct kvm *kvm, int req)
 
 /*
  * Must be called with kvm->srcu held to avoid races on memslots, and with
- * kvm->slots_lock to avoid races with ourselves, kvm_s390_vm_stop_migration(),
- * and kvm_s390_get_cmma_bits().
+ * kvm->slots_arch_lock to avoid races with ourselves,
+ * kvm_s390_vm_stop_migration(), and kvm_s390_get_cmma_bits().
  */
 static int kvm_s390_vm_start_migration(struct kvm *kvm)
 {
@@ -1265,7 +1265,7 @@ static int kvm_s390_vm_start_migration(struct kvm *kvm)
 }
 
 /*
- * Must be called with kvm->slots_lock to avoid races with ourselves,
+ * Must be called with kvm->slots_arch_lock to avoid races with ourselves,
  * kvm_s390_vm_start_migration() and kvm_s390_get_cmma_bits().
  */
 static int kvm_s390_vm_stop_migration(struct kvm *kvm)
@@ -1300,7 +1300,9 @@ static int kvm_s390_vm_set_migration(struct kvm *kvm,
 {
        int res = -ENXIO;
 
-       mutex_lock(&kvm->slots_lock);
+       guard(srcu)(&kvm->srcu);
+       guard(mutex)(&kvm->slots_arch_lock);
+
        switch (attr->attr) {
        case KVM_S390_VM_MIGRATION_START:
                res = kvm_s390_vm_start_migration(kvm);
@@ -1311,7 +1313,6 @@ static int kvm_s390_vm_set_migration(struct kvm *kvm,
        default:
                break;
        }
-       mutex_unlock(&kvm->slots_lock);
 
        return res;
 }
@@ -3001,9 +3002,8 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
                r = -EFAULT;
                if (copy_from_user(&args, argp, sizeof(args)))
                        break;
-               mutex_lock(&kvm->slots_lock);
-               r = kvm_s390_get_cmma_bits(kvm, &args);
-               mutex_unlock(&kvm->slots_lock);
+               scoped_guard(mutex, &kvm->slots_arch_lock)
+                       r = kvm_s390_get_cmma_bits(kvm, &args);
                if (!r) {
                        r = copy_to_user(argp, &args, sizeof(args));
                        if (r)
@@ -3017,9 +3017,9 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
                r = -EFAULT;
                if (copy_from_user(&args, argp, sizeof(args)))
                        break;
-               mutex_lock(&kvm->slots_lock);
+               mutex_lock(&kvm->slots_arch_lock);
                r = kvm_s390_set_cmma_bits(kvm, &args);
-               mutex_unlock(&kvm->slots_lock);
+               mutex_unlock(&kvm->slots_arch_lock);
                break;
        }
        case KVM_S390_PV_COMMAND: {
index ea5a99537346eb998a3f49c52abd578b87754676..b1ba24c346efa1034b7f050d31d2df82cd352ab5 100644 (file)
@@ -1261,8 +1261,9 @@ static int handle_essa(struct kvm_vcpu *vcpu)
                /* Retry the ESSA instruction */
                kvm_s390_retry_instr(vcpu);
        } else {
-               scoped_guard(read_lock, &vcpu->kvm->mmu_lock)
-                       i = __do_essa(vcpu, orc);
+               scoped_guard(mutex, &vcpu->kvm->slots_arch_lock)
+                       scoped_guard(read_lock, &vcpu->kvm->mmu_lock)
+                               i = __do_essa(vcpu, orc);
                if (i < 0)
                        return i;
                /* Account for the possible extra cbrl entry */