[kernel/f15] CVE-2011-4347 kvm: device assignment DoS (rhbz 770096)

Josh Boyer jwboyer at fedoraproject.org
Wed Jan 4 15:38:59 UTC 2012


commit 0456a2e1990982cfba0f600fd5e6fe49c4c612a6
Author: Josh Boyer <jwboyer at redhat.com>
Date:   Wed Jan 4 10:36:23 2012 -0500

    CVE-2011-4347 kvm: device assignment DoS (rhbz 770096)

 KVM-fix-device-assignment-permissions.patch |  206 +++++++++++++++++++++++++++
 kernel.spec                                 |   11 ++-
 2 files changed, 216 insertions(+), 1 deletions(-)
---
diff --git a/KVM-fix-device-assignment-permissions.patch b/KVM-fix-device-assignment-permissions.patch
new file mode 100644
index 0000000..2089482
--- /dev/null
+++ b/KVM-fix-device-assignment-permissions.patch
@@ -0,0 +1,206 @@
+From 423873736b78f549fbfa2f715f2e4de7e6c5e1e9 Mon Sep 17 00:00:00 2001
+From: Alex Williamson <alex.williamson at 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 at redhat.com>
+Signed-off-by: Marcelo Tosatti <mtosatti at 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 at 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 at redhat.com>
+Signed-off-by: Yang Bai <hamo.by at gmail.com>
+Signed-off-by: Marcelo Tosatti <mtosatti at 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
+
diff --git a/kernel.spec b/kernel.spec
index b22d4d5..a4db929 100644
--- a/kernel.spec
+++ b/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 at redhat.com>
+- CVE-2011-4347 kvm: device assignment DoS (rhbz 770096)
+
 * Tue Jan 03 2012 Josh Boyer <jwboyer at redhat.com> 2.6.41.7-1
 - Linux 3.1.7
 


More information about the scm-commits mailing list