]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
KVM: Remove CREATE_IRQCHIP/SET_PIT2 race
authorSteve Rutherford <srutherford@google.com>
Thu, 16 Apr 2020 19:11:52 +0000 (12:11 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 1 Oct 2020 11:17:55 +0000 (13:17 +0200)
[ Upstream commit 7289fdb5dcdbc5155b5531529c44105868a762f2 ]

Fixes a NULL pointer dereference, caused by the PIT firing an interrupt
before the interrupt table has been initialized.

SET_PIT2 can race with the creation of the IRQchip. In particular,
if SET_PIT2 is called with a low PIT timer period (after the creation of
the IOAPIC, but before the instantiation of the irq routes), the PIT can
fire an interrupt at an uninitialized table.

Signed-off-by: Steve Rutherford <srutherford@google.com>
Signed-off-by: Jon Cargille <jcargill@google.com>
Reviewed-by: Jim Mattson <jmattson@google.com>
Message-Id: <20200416191152.259434-1-jcargill@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
arch/x86/kvm/x86.c

index 8920ee7b2881131654ff580e504b5dd7eda4cad0..67ad417a29ca4a01359f3f7c0b82b82ac902f118 100644 (file)
@@ -5050,10 +5050,13 @@ set_identity_unlock:
                r = -EFAULT;
                if (copy_from_user(&u.ps, argp, sizeof(u.ps)))
                        goto out;
+               mutex_lock(&kvm->lock);
                r = -ENXIO;
                if (!kvm->arch.vpit)
-                       goto out;
+                       goto set_pit_out;
                r = kvm_vm_ioctl_set_pit(kvm, &u.ps);
+set_pit_out:
+               mutex_unlock(&kvm->lock);
                break;
        }
        case KVM_GET_PIT2: {
@@ -5073,10 +5076,13 @@ set_identity_unlock:
                r = -EFAULT;
                if (copy_from_user(&u.ps2, argp, sizeof(u.ps2)))
                        goto out;
+               mutex_lock(&kvm->lock);
                r = -ENXIO;
                if (!kvm->arch.vpit)
-                       goto out;
+                       goto set_pit2_out;
                r = kvm_vm_ioctl_set_pit2(kvm, &u.ps2);
+set_pit2_out:
+               mutex_unlock(&kvm->lock);
                break;
        }
        case KVM_REINJECT_CONTROL: {