207 lines
6.0 KiB
Diff
207 lines
6.0 KiB
Diff
|
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
|
||
|
|