From 0211e7a7554f0f9ce59f9f8dd740f71cc69b4b17 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 25 Jul 2016 14:19:38 -0600 Subject: [PATCH] PCI: Fix proc mmap on sparc In 8c05cd08a7 ("PCI: fix offset check for sysfs mmapped files"), try to check exposed value with resource start/end in proc mmap path. | start = vma->vm_pgoff; | size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1; | pci_start = (mmap_api == PCI_MMAP_PROCFS) ? | pci_resource_start(pdev, resno) >> PAGE_SHIFT : 0; | if (start >= pci_start && start < pci_start + size && | start + nr <= pci_start + size) vma->vm_pgoff is above code segment is user/BAR value >> PAGE_SHIFT. pci_start is resource->start >> PAGE_SHIFT. For sparc, resource start is different from BAR start aka pci bus address. pci bus address need to add offset to be the resource start. So that commit breaks all arch that exposed value is BAR/user value, and need to be offseted to resource address. test code using: ./test_mmap_proc /proc/bus/pci/0000:00/04.0 0x2000000 test code segment: fd = open(argv[1], O_RDONLY); ... sscanf(argv[2], "0x%lx", &offset); left = offset & (PAGE_SIZE - 1); offset &= PAGE_MASK; ioctl(fd, PCIIOC_MMAP_IS_MEM); addr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd, offset); for (i = 0; i < 8; i++) printf("%x ", addr[i + left]); munmap(addr, PAGE_SIZE); close(fd); Fixes: 8c05cd08a7 ("PCI: fix offset check for sysfs mmapped files") Signed-off-by: Yinghai Lu Orabug: 22855133 Signed-off-by: Khalid Aziz (cherry picked from commit 7bd8ad7855e6ecdac36c6dc7946f5b6beff13ae2) Signed-off-by: Allen Pais --- drivers/pci/pci-sysfs.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 0f1d8479caa3..07271674f3e0 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -973,15 +973,20 @@ void pci_remove_legacy_files(struct pci_bus *b) int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma, enum pci_mmap_api mmap_api) { - unsigned long nr, start, size, pci_start; + unsigned long nr, start, size, pci_start = 0; if (pci_resource_len(pdev, resno) == 0) return 0; nr = vma_pages(vma); start = vma->vm_pgoff; size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1; - pci_start = (mmap_api == PCI_MMAP_PROCFS) ? - pci_resource_start(pdev, resno) >> PAGE_SHIFT : 0; + if (mmap_api == PCI_MMAP_PROCFS) { + resource_size_t user_start, user_end; + + pci_resource_to_user(pdev, resno, &pdev->resource[resno], + &user_start, &user_end); + pci_start = user_start >> PAGE_SHIFT; + } if (start >= pci_start && start < pci_start + size && start + nr <= pci_start + size) return 1; -- 2.50.1