aboutsummaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2012-02-28 10:11:51 -0500
committerLuis Henriques <luis.henriques@canonical.com>2012-03-08 07:23:34 -0500
commit450180c987240cece70a63ef9a28519ba54edfaf (patch)
tree61e09c5bbfa0dfc246c939ad7e608d50ed4753f6 /virt
parent720122239b1f7bdb9330763f413db71299cbd46c (diff)
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> (backported from commit 3d27e23b17010c668db311140b17bbbb70c78fb9) CVE-2011-4347 BugLink: http://bugs.launchpad.net/bugs/897812 Signed-off-by: Andy Whitcroft <apw@canonical.com> Acked-by: Seth Forshee <seth.forshee@canonical.com> Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/assigned-dev.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/virt/kvm/assigned-dev.c b/virt/kvm/assigned-dev.c
index 6cc4b97ec45..2e8c7271009 100644
--- a/virt/kvm/assigned-dev.c
+++ b/virt/kvm/assigned-dev.c
@@ -17,6 +17,8 @@
17#include <linux/pci.h> 17#include <linux/pci.h>
18#include <linux/interrupt.h> 18#include <linux/interrupt.h>
19#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/namei.h>
21#include <linux/fs.h>
20#include "irq.h" 22#include "irq.h"
21 23
22static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head, 24static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head,
@@ -474,12 +476,73 @@ out:
474 return r; 476 return r;
475} 477}
476 478
479/*
480 * We want to test whether the caller has been granted permissions to
481 * use this device. To be able to configure and control the device,
482 * the user needs access to PCI configuration space and BAR resources.
483 * These are accessed through PCI sysfs. PCI config space is often
484 * passed to the process calling this ioctl via file descriptor, so we
485 * can't rely on access to that file. We can check for permissions
486 * on each of the BAR resource files, which is a pretty clear
487 * indicator that the user has been granted access to the device.
488 */
489static int probe_sysfs_permissions(struct pci_dev *dev)
490{
491#ifdef CONFIG_SYSFS
492 int i;
493 bool bar_found = false;
494
495 for (i = PCI_STD_RESOURCES; i <= PCI_STD_RESOURCE_END; i++) {
496 char *kpath, *syspath;
497 struct path path;
498 struct inode *inode;
499 int r;
500
501 if (!pci_resource_len(dev, i))
502 continue;
503
504 kpath = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
505 if (!kpath)
506 return -ENOMEM;
507
508 /* Per sysfs-rules, sysfs is always at /sys */
509 syspath = kasprintf(GFP_KERNEL, "/sys%s/resource%d", kpath, i);
510 kfree(kpath);
511 if (!syspath)
512 return -ENOMEM;
513
514 r = kern_path(syspath, LOOKUP_FOLLOW, &path);
515 kfree(syspath);
516 if (r)
517 return r;
518
519 inode = path.dentry->d_inode;
520
521 r = inode_permission(inode, MAY_READ | MAY_WRITE | MAY_ACCESS);
522 path_put(&path);
523 if (r)
524 return r;
525
526 bar_found = true;
527 }
528
529 /* If no resources, probably something special */
530 if (!bar_found)
531 return -EPERM;
532
533 return 0;
534#else
535 return -EINVAL; /* No way to control the device without sysfs */
536#endif
537}
538
477static int kvm_vm_ioctl_assign_device(struct kvm *kvm, 539static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
478 struct kvm_assigned_pci_dev *assigned_dev) 540 struct kvm_assigned_pci_dev *assigned_dev)
479{ 541{
480 int r = 0, idx; 542 int r = 0, idx;
481 struct kvm_assigned_dev_kernel *match; 543 struct kvm_assigned_dev_kernel *match;
482 struct pci_dev *dev; 544 struct pci_dev *dev;
545 u8 header_type;
483 546
484 mutex_lock(&kvm->lock); 547 mutex_lock(&kvm->lock);
485 idx = srcu_read_lock(&kvm->srcu); 548 idx = srcu_read_lock(&kvm->srcu);
@@ -507,6 +570,18 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
507 r = -EINVAL; 570 r = -EINVAL;
508 goto out_free; 571 goto out_free;
509 } 572 }
573
574 /* Don't allow bridges to be assigned */
575 pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
576 if ((header_type & PCI_HEADER_TYPE) != PCI_HEADER_TYPE_NORMAL) {
577 r = -EPERM;
578 goto out_put;
579 }
580
581 r = probe_sysfs_permissions(dev);
582 if (r)
583 goto out_put;
584
510 if (pci_enable_device(dev)) { 585 if (pci_enable_device(dev)) {
511 printk(KERN_INFO "%s: Could not enable PCI device\n", __func__); 586 printk(KERN_INFO "%s: Could not enable PCI device\n", __func__);
512 r = -EBUSY; 587 r = -EBUSY;