diff options
author | Christoph Hellwig <hch@lst.de> | 2019-07-08 11:51:56 -0700 |
---|---|---|
committer | Sasha Levin <sashal@kernel.org> | 2019-08-25 10:10:25 -0400 |
commit | 3d0ed0e4fafd9255fbb338c3cf22cdb123ef7645 (patch) | |
tree | cd69da88dbab91932c631f8c70d827d6b9d7346d | |
parent | 1c9de345f7dafbd9c211407c1483d08fc564b09d (diff) | |
download | linux-stable-3d0ed0e4fafd9255fbb338c3cf22cdb123ef7645.tar.gz linux-stable-3d0ed0e4fafd9255fbb338c3cf22cdb123ef7645.tar.bz2 linux-stable-3d0ed0e4fafd9255fbb338c3cf22cdb123ef7645.zip |
dma-mapping: check pfn validity in dma_common_{mmap,get_sgtable}
[ Upstream commit 66d7780f18eae0232827fcffeaded39a6a168236 ]
Check that the pfn returned from arch_dma_coherent_to_pfn refers to
a valid page and reject the mmap / get_sgtable requests otherwise.
Based on the arm implementation of the mmap and get_sgtable methods.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Tested-by: Vignesh Raghavendra <vigneshr@ti.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r-- | kernel/dma/mapping.c | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c index f7afdadb6770..3401382bbca2 100644 --- a/kernel/dma/mapping.c +++ b/kernel/dma/mapping.c @@ -116,11 +116,16 @@ int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, int ret; if (!dev_is_dma_coherent(dev)) { + unsigned long pfn; + if (!IS_ENABLED(CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN)) return -ENXIO; - page = pfn_to_page(arch_dma_coherent_to_pfn(dev, cpu_addr, - dma_addr)); + /* If the PFN is not valid, we do not have a struct page */ + pfn = arch_dma_coherent_to_pfn(dev, cpu_addr, dma_addr); + if (!pfn_valid(pfn)) + return -ENXIO; + page = pfn_to_page(pfn); } else { page = virt_to_page(cpu_addr); } @@ -170,7 +175,11 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, if (!dev_is_dma_coherent(dev)) { if (!IS_ENABLED(CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN)) return -ENXIO; + + /* If the PFN is not valid, we do not have a struct page */ pfn = arch_dma_coherent_to_pfn(dev, cpu_addr, dma_addr); + if (!pfn_valid(pfn)) + return -ENXIO; } else { pfn = page_to_pfn(virt_to_page(cpu_addr)); } |