| From cebbert@redhat.com Thu Oct 16 16:09:36 2008 |
| From: Linus Torvalds <torvalds@linux-foundation.org> |
| Date: Wed, 15 Oct 2008 18:09:14 -0400 |
| Subject: Check mapped ranges on sysfs resource files |
| To: stable@kernel.org |
| Cc: Jesse Barnes <jbarnes@virtuousgeek.org> |
| Message-ID: <20081015180914.0e44fdb6@redhat.com> |
| |
| From: Linus Torvalds <torvalds@linux-foundation.org> |
| |
| commit b5ff7df3df9efab511244d5a299fce706c71af48 upstream |
| |
| Check mapped ranges on sysfs resource files |
| |
| This is loosely based on a patch by Jesse Barnes to check the user-space |
| PCI mappings though the sysfs interfaces. Quoting Jesse's original |
| explanation: |
| |
| It's fairly common for applications to map PCI resources through sysfs. |
| However, with the current implementation, it's possible for an application |
| to map far more than the range corresponding to the resourceN file it |
| opened. This patch plugs that hole by checking the range at mmap time, |
| similar to what is done on platforms like sparc64 in their lower level |
| PCI remapping routines. |
| |
| It was initially put together to help debug the e1000e NVRAM corruption |
| problem, since we initially thought an X driver might be walking past the |
| end of one of its mappings and clobbering the NVRAM. It now looks like |
| that's not the case, but doing the check is still important for obvious |
| reasons. |
| |
| and this version of the patch differs in that it uses a helper function |
| to clarify the code, and does all the checks in pages (instead of bytes) |
| in order to avoid overflows when doing "<< PAGE_SHIFT" etc. |
| |
| [cebbert@redhat.com: backport, changing WARN() to printk()] |
| |
| Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Cc: Chuck Ebbert <cebbert@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/pci/pci-sysfs.c | 19 +++++++++++++++++++ |
| 1 file changed, 19 insertions(+) |
| |
| --- a/drivers/pci/pci-sysfs.c |
| +++ b/drivers/pci/pci-sysfs.c |
| @@ -16,6 +16,7 @@ |
| |
| |
| #include <linux/kernel.h> |
| +#include <linux/sched.h> |
| #include <linux/pci.h> |
| #include <linux/stat.h> |
| #include <linux/topology.h> |
| @@ -484,6 +485,21 @@ pci_mmap_legacy_mem(struct kobject *kobj |
| #endif /* HAVE_PCI_LEGACY */ |
| |
| #ifdef HAVE_PCI_MMAP |
| + |
| +static int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma) |
| +{ |
| + unsigned long nr, start, size; |
| + |
| + nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; |
| + start = vma->vm_pgoff; |
| + size = pci_resource_len(pdev, resno) >> PAGE_SHIFT; |
| + if (start < size && size - start >= nr) |
| + return 1; |
| + printk(KERN_WARNING "WARNING: process \"%s\" tried to map 0x%08lx-0x%08lx on %s BAR %d (size 0x%08lx)\n", |
| + current->comm, start, start+nr, pci_name(pdev), resno, size); |
| + return 0; |
| +} |
| + |
| /** |
| * pci_mmap_resource - map a PCI resource into user memory space |
| * @kobj: kobject for mapping |
| @@ -510,6 +526,9 @@ pci_mmap_resource(struct kobject *kobj, |
| if (i >= PCI_ROM_RESOURCE) |
| return -ENODEV; |
| |
| + if (!pci_mmap_fits(pdev, i, vma)) |
| + return -EINVAL; |
| + |
| /* pci_mmap_page_range() expects the same kind of entry as coming |
| * from /proc/bus/pci/ which is a "user visible" value. If this is |
| * different from the resource itself, arch will do necessary fixup. |