summaryrefslogtreecommitdiff
path: root/virt
diff options
context:
space:
mode:
authorJann Horn <jannh@google.com>2019-01-26 01:54:33 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-02-12 19:47:25 +0100
commit24b027d2b1386da03aafb2aaac69d4fa67ee7d9c (patch)
tree7d3d90823c821e4c086cc5dfa50b8a361acdcea8 /virt
parent5a45d3720b5437515f8c094f1c3d61f6afe211c1 (diff)
downloadlinux-rpi3-24b027d2b1386da03aafb2aaac69d4fa67ee7d9c.tar.gz
linux-rpi3-24b027d2b1386da03aafb2aaac69d4fa67ee7d9c.tar.bz2
linux-rpi3-24b027d2b1386da03aafb2aaac69d4fa67ee7d9c.zip
kvm: fix kvm_ioctl_create_device() reference counting (CVE-2019-6974)
commit cfa39381173d5f969daf43582c95ad679189cbc9 upstream. kvm_ioctl_create_device() does the following: 1. creates a device that holds a reference to the VM object (with a borrowed reference, the VM's refcount has not been bumped yet) 2. initializes the device 3. transfers the reference to the device to the caller's file descriptor table 4. calls kvm_get_kvm() to turn the borrowed reference to the VM into a real reference The ownership transfer in step 3 must not happen before the reference to the VM becomes a proper, non-borrowed reference, which only happens in step 4. After step 3, an attacker can close the file descriptor and drop the borrowed reference, which can cause the refcount of the kvm object to drop to zero. This means that we need to grab a reference for the device before anon_inode_getfd(), otherwise the VM can disappear from under us. Fixes: 852b6d57dc7f ("kvm: add device control API") Cc: stable@kernel.org Signed-off-by: Jann Horn <jannh@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/kvm_main.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 0ddf81dea6fd..0ffb02ff5234 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2913,8 +2913,10 @@ static int kvm_ioctl_create_device(struct kvm *kvm,
if (ops->init)
ops->init(dev);
+ kvm_get_kvm(kvm);
ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR | O_CLOEXEC);
if (ret < 0) {
+ kvm_put_kvm(kvm);
mutex_lock(&kvm->lock);
list_del(&dev->vm_node);
mutex_unlock(&kvm->lock);
@@ -2922,7 +2924,6 @@ static int kvm_ioctl_create_device(struct kvm *kvm,
return ret;
}
- kvm_get_kvm(kvm);
cd->fd = ret;
return 0;
}