dma-coherent: fix integer overflow in the reserved-memory dma allocation
[ Upstream commit 286c21de32b904131f8cf6a36ce40b8b0c9c5da3 ] pageno is an int and the PAGE_SHIFT shift is done on an int, overflowing if the memory is bigger than 2G This can be reproduced using for example a reserved-memory of 4G reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; reserved_dma: buffer@0 { compatible = "shared-dma-pool"; no-map; reg = <0x5 0x00000000 0x1 0x0>; }; }; Signed-off-by: Kevin Grandemange <kevin.grandemange@allegrodvt.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
960bf4e436
commit
56aaa0e8c9
@ -134,7 +134,7 @@ static void *__dma_alloc_from_coherent(struct device *dev,
|
|||||||
|
|
||||||
spin_lock_irqsave(&mem->spinlock, flags);
|
spin_lock_irqsave(&mem->spinlock, flags);
|
||||||
|
|
||||||
if (unlikely(size > (mem->size << PAGE_SHIFT)))
|
if (unlikely(size > ((dma_addr_t)mem->size << PAGE_SHIFT)))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
pageno = bitmap_find_free_region(mem->bitmap, mem->size, order);
|
pageno = bitmap_find_free_region(mem->bitmap, mem->size, order);
|
||||||
@ -144,8 +144,9 @@ static void *__dma_alloc_from_coherent(struct device *dev,
|
|||||||
/*
|
/*
|
||||||
* Memory was found in the coherent area.
|
* Memory was found in the coherent area.
|
||||||
*/
|
*/
|
||||||
*dma_handle = dma_get_device_base(dev, mem) + (pageno << PAGE_SHIFT);
|
*dma_handle = dma_get_device_base(dev, mem) +
|
||||||
ret = mem->virt_base + (pageno << PAGE_SHIFT);
|
((dma_addr_t)pageno << PAGE_SHIFT);
|
||||||
|
ret = mem->virt_base + ((dma_addr_t)pageno << PAGE_SHIFT);
|
||||||
spin_unlock_irqrestore(&mem->spinlock, flags);
|
spin_unlock_irqrestore(&mem->spinlock, flags);
|
||||||
memset(ret, 0, size);
|
memset(ret, 0, size);
|
||||||
return ret;
|
return ret;
|
||||||
@ -194,7 +195,7 @@ static int __dma_release_from_coherent(struct dma_coherent_mem *mem,
|
|||||||
int order, void *vaddr)
|
int order, void *vaddr)
|
||||||
{
|
{
|
||||||
if (mem && vaddr >= mem->virt_base && vaddr <
|
if (mem && vaddr >= mem->virt_base && vaddr <
|
||||||
(mem->virt_base + (mem->size << PAGE_SHIFT))) {
|
(mem->virt_base + ((dma_addr_t)mem->size << PAGE_SHIFT))) {
|
||||||
int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
|
int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
@ -238,10 +239,10 @@ static int __dma_mmap_from_coherent(struct dma_coherent_mem *mem,
|
|||||||
struct vm_area_struct *vma, void *vaddr, size_t size, int *ret)
|
struct vm_area_struct *vma, void *vaddr, size_t size, int *ret)
|
||||||
{
|
{
|
||||||
if (mem && vaddr >= mem->virt_base && vaddr + size <=
|
if (mem && vaddr >= mem->virt_base && vaddr + size <=
|
||||||
(mem->virt_base + (mem->size << PAGE_SHIFT))) {
|
(mem->virt_base + ((dma_addr_t)mem->size << PAGE_SHIFT))) {
|
||||||
unsigned long off = vma->vm_pgoff;
|
unsigned long off = vma->vm_pgoff;
|
||||||
int start = (vaddr - mem->virt_base) >> PAGE_SHIFT;
|
int start = (vaddr - mem->virt_base) >> PAGE_SHIFT;
|
||||||
int user_count = vma_pages(vma);
|
unsigned long user_count = vma_pages(vma);
|
||||||
int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
||||||
|
|
||||||
*ret = -ENXIO;
|
*ret = -ENXIO;
|
||||||
|
Loading…
Reference in New Issue
Block a user