CVE-2011-4347 kvm: device assignment DoS (rhbz 770096)
This commit is contained in:
parent
4537a47c89
commit
0456a2e199
|
@ -0,0 +1,206 @@
|
|||
From 423873736b78f549fbfa2f715f2e4de7e6c5e1e9 Mon Sep 17 00:00:00 2001
|
||||
From: Alex Williamson <alex.williamson@redhat.com>
|
||||
Date: Tue, 20 Dec 2011 21:59:03 -0700
|
||||
Subject: [PATCH 1/2] KVM: Remove ability to assign a device without iommu
|
||||
support
|
||||
|
||||
This option has no users and it exposes a security hole that we
|
||||
can allow devices to be assigned without iommu protection. Make
|
||||
KVM_DEV_ASSIGN_ENABLE_IOMMU a mandatory option.
|
||||
|
||||
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
|
||||
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
|
||||
---
|
||||
virt/kvm/assigned-dev.c | 18 +++++++++---------
|
||||
1 files changed, 9 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/virt/kvm/assigned-dev.c b/virt/kvm/assigned-dev.c
|
||||
index 3ad0925..a251a28 100644
|
||||
--- a/virt/kvm/assigned-dev.c
|
||||
+++ b/virt/kvm/assigned-dev.c
|
||||
@@ -487,6 +487,9 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
|
||||
struct kvm_assigned_dev_kernel *match;
|
||||
struct pci_dev *dev;
|
||||
|
||||
+ if (!(assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
mutex_lock(&kvm->lock);
|
||||
idx = srcu_read_lock(&kvm->srcu);
|
||||
|
||||
@@ -544,16 +547,14 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
|
||||
|
||||
list_add(&match->list, &kvm->arch.assigned_dev_head);
|
||||
|
||||
- if (assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU) {
|
||||
- if (!kvm->arch.iommu_domain) {
|
||||
- r = kvm_iommu_map_guest(kvm);
|
||||
- if (r)
|
||||
- goto out_list_del;
|
||||
- }
|
||||
- r = kvm_assign_device(kvm, match);
|
||||
+ if (!kvm->arch.iommu_domain) {
|
||||
+ r = kvm_iommu_map_guest(kvm);
|
||||
if (r)
|
||||
goto out_list_del;
|
||||
}
|
||||
+ r = kvm_assign_device(kvm, match);
|
||||
+ if (r)
|
||||
+ goto out_list_del;
|
||||
|
||||
out:
|
||||
srcu_read_unlock(&kvm->srcu, idx);
|
||||
@@ -593,8 +594,7 @@ static int kvm_vm_ioctl_deassign_device(struct kvm *kvm,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- if (match->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU)
|
||||
- kvm_deassign_device(kvm, match);
|
||||
+ kvm_deassign_device(kvm, match);
|
||||
|
||||
kvm_free_assigned_device(kvm, match);
|
||||
|
||||
--
|
||||
1.7.7.5
|
||||
|
||||
|
||||
From 3d27e23b17010c668db311140b17bbbb70c78fb9 Mon Sep 17 00:00:00 2001
|
||||
From: Alex Williamson <alex.williamson@redhat.com>
|
||||
Date: Tue, 20 Dec 2011 21:59:09 -0700
|
||||
Subject: [PATCH 2/2] KVM: Device assignment permission checks
|
||||
|
||||
Only allow KVM device assignment to attach to devices which:
|
||||
|
||||
- Are not bridges
|
||||
- Have BAR resources (assume others are special devices)
|
||||
- The user has permissions to use
|
||||
|
||||
Assigning a bridge is a configuration error, it's not supported, and
|
||||
typically doesn't result in the behavior the user is expecting anyway.
|
||||
Devices without BAR resources are typically chipset components that
|
||||
also don't have host drivers. We don't want users to hold such devices
|
||||
captive or cause system problems by fencing them off into an iommu
|
||||
domain. We determine "permission to use" by testing whether the user
|
||||
has access to the PCI sysfs resource files. By default a normal user
|
||||
will not have access to these files, so it provides a good indication
|
||||
that an administration agent has granted the user access to the device.
|
||||
|
||||
[Yang Bai: add missing #include]
|
||||
[avi: fix comment style]
|
||||
|
||||
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
|
||||
Signed-off-by: Yang Bai <hamo.by@gmail.com>
|
||||
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
|
||||
---
|
||||
virt/kvm/assigned-dev.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 files changed, 75 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/virt/kvm/assigned-dev.c b/virt/kvm/assigned-dev.c
|
||||
index a251a28..758e3b3 100644
|
||||
--- a/virt/kvm/assigned-dev.c
|
||||
+++ b/virt/kvm/assigned-dev.c
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
+#include <linux/namei.h>
|
||||
+#include <linux/fs.h>
|
||||
#include "irq.h"
|
||||
|
||||
static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head,
|
||||
@@ -480,12 +482,73 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * We want to test whether the caller has been granted permissions to
|
||||
+ * use this device. To be able to configure and control the device,
|
||||
+ * the user needs access to PCI configuration space and BAR resources.
|
||||
+ * These are accessed through PCI sysfs. PCI config space is often
|
||||
+ * passed to the process calling this ioctl via file descriptor, so we
|
||||
+ * can't rely on access to that file. We can check for permissions
|
||||
+ * on each of the BAR resource files, which is a pretty clear
|
||||
+ * indicator that the user has been granted access to the device.
|
||||
+ */
|
||||
+static int probe_sysfs_permissions(struct pci_dev *dev)
|
||||
+{
|
||||
+#ifdef CONFIG_SYSFS
|
||||
+ int i;
|
||||
+ bool bar_found = false;
|
||||
+
|
||||
+ for (i = PCI_STD_RESOURCES; i <= PCI_STD_RESOURCE_END; i++) {
|
||||
+ char *kpath, *syspath;
|
||||
+ struct path path;
|
||||
+ struct inode *inode;
|
||||
+ int r;
|
||||
+
|
||||
+ if (!pci_resource_len(dev, i))
|
||||
+ continue;
|
||||
+
|
||||
+ kpath = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
|
||||
+ if (!kpath)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ /* Per sysfs-rules, sysfs is always at /sys */
|
||||
+ syspath = kasprintf(GFP_KERNEL, "/sys%s/resource%d", kpath, i);
|
||||
+ kfree(kpath);
|
||||
+ if (!syspath)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ r = kern_path(syspath, LOOKUP_FOLLOW, &path);
|
||||
+ kfree(syspath);
|
||||
+ if (r)
|
||||
+ return r;
|
||||
+
|
||||
+ inode = path.dentry->d_inode;
|
||||
+
|
||||
+ r = inode_permission(inode, MAY_READ | MAY_WRITE | MAY_ACCESS);
|
||||
+ path_put(&path);
|
||||
+ if (r)
|
||||
+ return r;
|
||||
+
|
||||
+ bar_found = true;
|
||||
+ }
|
||||
+
|
||||
+ /* If no resources, probably something special */
|
||||
+ if (!bar_found)
|
||||
+ return -EPERM;
|
||||
+
|
||||
+ return 0;
|
||||
+#else
|
||||
+ return -EINVAL; /* No way to control the device without sysfs */
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
|
||||
struct kvm_assigned_pci_dev *assigned_dev)
|
||||
{
|
||||
int r = 0, idx;
|
||||
struct kvm_assigned_dev_kernel *match;
|
||||
struct pci_dev *dev;
|
||||
+ u8 header_type;
|
||||
|
||||
if (!(assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU))
|
||||
return -EINVAL;
|
||||
@@ -516,6 +579,18 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
|
||||
r = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
+
|
||||
+ /* Don't allow bridges to be assigned */
|
||||
+ pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
|
||||
+ if ((header_type & PCI_HEADER_TYPE) != PCI_HEADER_TYPE_NORMAL) {
|
||||
+ r = -EPERM;
|
||||
+ goto out_put;
|
||||
+ }
|
||||
+
|
||||
+ r = probe_sysfs_permissions(dev);
|
||||
+ if (r)
|
||||
+ goto out_put;
|
||||
+
|
||||
if (pci_enable_device(dev)) {
|
||||
printk(KERN_INFO "%s: Could not enable PCI device\n", __func__);
|
||||
r = -EBUSY;
|
||||
--
|
||||
1.7.7.5
|
||||
|
11
kernel.spec
11
kernel.spec
|
@ -42,7 +42,7 @@ Summary: The Linux kernel
|
|||
# When changing real_sublevel below, reset this by hand to 1
|
||||
# (or to 0 and then use rpmdev-bumpspec).
|
||||
#
|
||||
%global baserelease 1
|
||||
%global baserelease 2
|
||||
%global fedora_build %{baserelease}
|
||||
|
||||
# real_sublevel is the 3.x kernel version we're starting with
|
||||
|
@ -730,6 +730,9 @@ Patch21050: thp-reduce-khugepaged-freezing-latency.patch
|
|||
#rhbz 770102
|
||||
Patch21055: KVM-x86-Prevent-starting-PIT-timers-in-the-absence-of.patch
|
||||
|
||||
#rhbz 770096
|
||||
Patch21056: KVM-fix-device-assignment-permissions.patch
|
||||
|
||||
#rhbz 770233
|
||||
Patch21065: Bluetooth-Add-support-for-BCM20702A0.patch
|
||||
|
||||
|
@ -1365,6 +1368,9 @@ ApplyPatch KVM-x86-Prevent-starting-PIT-timers-in-the-absence-of.patch
|
|||
#rhbz 770233
|
||||
ApplyPatch Bluetooth-Add-support-for-BCM20702A0.patch
|
||||
|
||||
#rhbz 770096
|
||||
ApplyPatch KVM-fix-device-assignment-permissions.patch
|
||||
|
||||
# END OF PATCH APPLICATIONS
|
||||
|
||||
%endif
|
||||
|
@ -2012,6 +2018,9 @@ fi
|
|||
# and build.
|
||||
|
||||
%changelog
|
||||
* Wed Jan 04 2012 Josh Boyer <jwboyer@redhat.com>
|
||||
- CVE-2011-4347 kvm: device assignment DoS (rhbz 770096)
|
||||
|
||||
* Tue Jan 03 2012 Josh Boyer <jwboyer@redhat.com> 2.6.41.7-1
|
||||
- Linux 3.1.7
|
||||
|
||||
|
|
Loading…
Reference in New Issue