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