]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: s390: Fix unlikely NULL gmap dereference
authorClaudio Imbrenda <imbrenda@linux.ibm.com>
Mon, 3 Aug 2026 12:40:28 +0000 (14:40 +0200)
committerClaudio Imbrenda <imbrenda@linux.ibm.com>
Mon, 3 Aug 2026 13:39:05 +0000 (15:39 +0200)
When creating a new vCPU, kvm_vm_ioctl_create_vcpu() will call
kvm_arch_vcpu_postcreate() after the file descriptor for the new vCPU
has been created. The new file descriptor has not been returned yet,
but a malicious userspace program could try to guess it.

If a malicious userspace program manages to start the newly created vCPU
before kvm_arch_vcpu_postcreate() is called, __vcpu_run() will try to
dereference vcpu->arch.gmap and trigger a NULL pointer dereference.

Fix this by adding a new field to struct kvm_vcpu_arch to keep track of
the initialization status of the vCPU. Refuse to run a vCPU that is not
fully initialized.

Fixes: dafd032a15f8 ("KVM: s390: move vcpu specific initalization to a later point")
Fixes: e38c884df921 ("KVM: s390: Switch to new gmap")
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260803124040.126471-2-imbrenda@linux.ibm.com>

arch/s390/include/asm/kvm_host.h
arch/s390/kvm/kvm-s390.c

index c172f9b212d18e23642b94c712e439bf79e4edb8..b4182ca4435fb81daac87d60614aedac292ae5ad 100644 (file)
@@ -440,6 +440,7 @@ struct kvm_vcpu_arch {
        bool skey_enabled;
        /* Indicator if the access registers have been loaded from guest */
        bool acrs_loaded;
+       bool initialized;
        struct kvm_s390_pv_vcpu pv;
        union diag318_info diag318_info;
        struct kvm_s390_mmu_cache *mc;
index 150b5dd2170e2fe9b1d23bed79242f3eaf6fba38..f86b4b0b356f42a294b5d73f7ae90f193a92c281 100644 (file)
@@ -3613,6 +3613,9 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
        if (test_kvm_facility(vcpu->kvm, 74) || vcpu->kvm->arch.user_instr0 ||
            vcpu->kvm->arch.user_operexec)
                vcpu->arch.sie_block->ictl |= ICTL_OPEREXC;
+
+       /* Pairs with smp_load_acquire() in kvm_arch_vcpu_ioctl_run() and kvm_arch_vcpu_ioctl() */
+       smp_store_release(&vcpu->arch.initialized, true);
 }
 
 static bool kvm_has_pckmo_subfunc(struct kvm *kvm, unsigned long nr)
@@ -5039,6 +5042,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
            kvm_run->kvm_dirty_regs & ~KVM_SYNC_S390_VALID_FIELDS)
                return -EINVAL;
 
+       /* Pairs with smp_store_release() in kvm_arch_vcpu_postcreate() */
+       if (!smp_load_acquire(&vcpu->arch.initialized))
+               return -EINVAL;
+
        vcpu_load(vcpu);
 
        if (guestdbg_exit_pending(vcpu)) {
@@ -5523,6 +5530,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
        long r;
        u16 rc, rrc;
 
+       /* Pairs with smp_store_release() in kvm_arch_vcpu_postcreate() */
+       if (!smp_load_acquire(&vcpu->arch.initialized))
+               return -EINVAL;
+
        vcpu_load(vcpu);
 
        switch (ioctl) {