Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sh: mm: Fix unprotected access to struct device

With commit ce88313069c36eef80f21fd7 ("arch/sh: make the DMA mapping
operations observe dev->dma_pfn_offset") the generic DMA allocation
function on which the SH 'dma_alloc_coherent()' function relies on,
accesses the 'dma_pfn_offset' field of struct device.

Unfortunately the 'dma_generic_alloc_coherent()' function is called from
several places with a NULL struct device argument, halting the CPU
during the boot process.

This patch fixes the issue by protecting access to dev->dma_pfn_offset,
with a trivial check for validity. It also passes a valid 'struct device'
in the 'platform_resource_setup_memory()' function which is the main user
of 'dma_alloc_coherent()', and inserts a WARN_ON() check to remind to future
(and existing) bogus users of this function to provide a valid 'struct device'
whenever possible.

Fixes: ce88313069c36eef80f21fd7 ("arch/sh: make the DMA mapping operations observe dev->dma_pfn_offset")
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
Signed-off-by: Rich Felker <dalias@libc.org>

authored by

Jacopo Mondi and committed by
Rich Felker
b9826a49 6cb46597

+8 -3
+8 -3
arch/sh/mm/consistent.c
··· 59 59 60 60 split_page(pfn_to_page(virt_to_phys(ret) >> PAGE_SHIFT), order); 61 61 62 - *dma_handle = virt_to_phys(ret) - PFN_PHYS(dev->dma_pfn_offset); 62 + *dma_handle = virt_to_phys(ret); 63 + if (!WARN_ON(!dev)) 64 + *dma_handle -= PFN_PHYS(dev->dma_pfn_offset); 63 65 64 66 return ret_nocache; 65 67 } ··· 71 69 unsigned long attrs) 72 70 { 73 71 int order = get_order(size); 74 - unsigned long pfn = (dma_handle >> PAGE_SHIFT) + dev->dma_pfn_offset; 72 + unsigned long pfn = dma_handle >> PAGE_SHIFT; 75 73 int k; 74 + 75 + if (!WARN_ON(!dev)) 76 + pfn += dev->dma_pfn_offset; 76 77 77 78 for (k = 0; k < (1 << order); k++) 78 79 __free_pages(pfn_to_page(pfn + k), 0); ··· 148 143 if (!memsize) 149 144 return 0; 150 145 151 - buf = dma_alloc_coherent(NULL, memsize, &dma_handle, GFP_KERNEL); 146 + buf = dma_alloc_coherent(&pdev->dev, memsize, &dma_handle, GFP_KERNEL); 152 147 if (!buf) { 153 148 pr_warning("%s: unable to allocate memory\n", name); 154 149 return -ENOMEM;