dbc4a9
From: Matthew Garrett <matthew.garrett@nebula.com>
dbc4a9
Date: Thu, 8 Mar 2012 10:10:38 -0500
dbc4a9
Subject: [PATCH] PCI: Lock down BAR access when module security is enabled
dbc4a9
dbc4a9
Any hardware that can potentially generate DMA has to be locked down from
dbc4a9
userspace in order to avoid it being possible for an attacker to modify
dbc4a9
kernel code, allowing them to circumvent disabled module loading or module
dbc4a9
signing. Default to paranoid - in future we can potentially relax this for
dbc4a9
sufficiently IOMMU-isolated devices.
dbc4a9
dbc4a9
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
dbc4a9
---
dbc4a9
 drivers/pci/pci-sysfs.c | 10 ++++++++++
dbc4a9
 drivers/pci/proc.c      |  8 +++++++-
dbc4a9
 drivers/pci/syscall.c   |  3 ++-
dbc4a9
 3 files changed, 19 insertions(+), 2 deletions(-)
dbc4a9
dbc4a9
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
dbc4a9
index 9ff0a901ecf7..8d0d5d92b8d9 100644
dbc4a9
--- a/drivers/pci/pci-sysfs.c
dbc4a9
+++ b/drivers/pci/pci-sysfs.c
dbc4a9
@@ -30,6 +30,7 @@
dbc4a9
 #include <linux vgaarb.h="">
dbc4a9
 #include <linux pm_runtime.h="">
dbc4a9
 #include <linux of.h="">
dbc4a9
+#include <linux module.h="">
dbc4a9
 #include "pci.h"
dbc4a9
 
dbc4a9
 static int sysfs_initialized;	/* = 0 */
dbc4a9
@@ -704,6 +705,9 @@ static ssize_t pci_write_config(struct file *filp, struct kobject *kobj,
dbc4a9
 	loff_t init_off = off;
dbc4a9
 	u8 *data = (u8 *) buf;
dbc4a9
 
dbc4a9
+	if (secure_modules())
dbc4a9
+		return -EPERM;
dbc4a9
+
dbc4a9
 	if (off > dev->cfg_size)
dbc4a9
 		return 0;
dbc4a9
 	if (off + count > dev->cfg_size) {
dbc4a9
@@ -998,6 +1002,9 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
dbc4a9
 	resource_size_t start, end;
dbc4a9
 	int i;
dbc4a9
 
dbc4a9
+	if (secure_modules())
dbc4a9
+		return -EPERM;
dbc4a9
+
dbc4a9
 	for (i = 0; i < PCI_ROM_RESOURCE; i++)
dbc4a9
 		if (res == &pdev->resource[i])
dbc4a9
 			break;
dbc4a9
@@ -1099,6 +1106,9 @@ static ssize_t pci_write_resource_io(struct file *filp, struct kobject *kobj,
dbc4a9
 				     struct bin_attribute *attr, char *buf,
dbc4a9
 				     loff_t off, size_t count)
dbc4a9
 {
dbc4a9
+	if (secure_modules())
dbc4a9
+		return -EPERM;
dbc4a9
+
dbc4a9
 	return pci_resource_io(filp, kobj, attr, buf, off, count, true);
dbc4a9
 }
dbc4a9
 
dbc4a9
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
dbc4a9
index 3f155e78513f..4265ea07e3b0 100644
dbc4a9
--- a/drivers/pci/proc.c
dbc4a9
+++ b/drivers/pci/proc.c
dbc4a9
@@ -116,6 +116,9 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,
dbc4a9
 	int size = dev->cfg_size;
dbc4a9
 	int cnt;
dbc4a9
 
dbc4a9
+	if (secure_modules())
dbc4a9
+		return -EPERM;
dbc4a9
+
dbc4a9
 	if (pos >= size)
dbc4a9
 		return 0;
dbc4a9
 	if (nbytes >= size)
dbc4a9
@@ -195,6 +198,9 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,
dbc4a9
 #endif /* HAVE_PCI_MMAP */
dbc4a9
 	int ret = 0;
dbc4a9
 
dbc4a9
+	if (secure_modules())
dbc4a9
+		return -EPERM;
dbc4a9
+
dbc4a9
 	switch (cmd) {
dbc4a9
 	case PCIIOC_CONTROLLER:
dbc4a9
 		ret = pci_domain_nr(dev->bus);
dbc4a9
@@ -233,7 +239,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
dbc4a9
 	struct pci_filp_private *fpriv = file->private_data;
dbc4a9
 	int i, ret;
dbc4a9
 
dbc4a9
-	if (!capable(CAP_SYS_RAWIO))
dbc4a9
+	if (!capable(CAP_SYS_RAWIO) || secure_modules())
dbc4a9
 		return -EPERM;
dbc4a9
 
dbc4a9
 	/* Make sure the caller is mapping a real resource for this device */
dbc4a9
diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c
dbc4a9
index b91c4da68365..98f5637304d1 100644
dbc4a9
--- a/drivers/pci/syscall.c
dbc4a9
+++ b/drivers/pci/syscall.c
dbc4a9
@@ -10,6 +10,7 @@
dbc4a9
 #include <linux errno.h="">
dbc4a9
 #include <linux pci.h="">
dbc4a9
 #include <linux syscalls.h="">
dbc4a9
+#include <linux module.h="">
dbc4a9
 #include <asm uaccess.h="">
dbc4a9
 #include "pci.h"
dbc4a9
 
dbc4a9
@@ -92,7 +93,7 @@ SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn,
dbc4a9
 	u32 dword;
dbc4a9
 	int err = 0;
dbc4a9
 
dbc4a9
-	if (!capable(CAP_SYS_ADMIN))
dbc4a9
+	if (!capable(CAP_SYS_ADMIN) || secure_modules())
dbc4a9
 		return -EPERM;
dbc4a9
 
dbc4a9
 	dev = pci_get_bus_and_slot(bus, dfn);
dbc4a9
-- 
dbc4a9
1.9.3
dbc4a9