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