Skip to content

Commit 286c21d

Browse files
Kevin GrandemangeChristoph Hellwig
authored andcommitted
dma-coherent: fix integer overflow in the reserved-memory dma allocation
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 <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent 11a48a5 commit 286c21d

File tree

1 file changed

+7
-6
lines changed

1 file changed

+7
-6
lines changed

kernel/dma/coherent.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ static void *__dma_alloc_from_coherent(struct device *dev,
134134

135135
spin_lock_irqsave(&mem->spinlock, flags);
136136

137-
if (unlikely(size > (mem->size << PAGE_SHIFT)))
137+
if (unlikely(size > ((dma_addr_t)mem->size << PAGE_SHIFT)))
138138
goto err;
139139

140140
pageno = bitmap_find_free_region(mem->bitmap, mem->size, order);
@@ -144,8 +144,9 @@ static void *__dma_alloc_from_coherent(struct device *dev,
144144
/*
145145
* Memory was found in the coherent area.
146146
*/
147-
*dma_handle = dma_get_device_base(dev, mem) + (pageno << PAGE_SHIFT);
148-
ret = mem->virt_base + (pageno << PAGE_SHIFT);
147+
*dma_handle = dma_get_device_base(dev, mem) +
148+
((dma_addr_t)pageno << PAGE_SHIFT);
149+
ret = mem->virt_base + ((dma_addr_t)pageno << PAGE_SHIFT);
149150
spin_unlock_irqrestore(&mem->spinlock, flags);
150151
memset(ret, 0, size);
151152
return ret;
@@ -194,7 +195,7 @@ static int __dma_release_from_coherent(struct dma_coherent_mem *mem,
194195
int order, void *vaddr)
195196
{
196197
if (mem && vaddr >= mem->virt_base && vaddr <
197-
(mem->virt_base + (mem->size << PAGE_SHIFT))) {
198+
(mem->virt_base + ((dma_addr_t)mem->size << PAGE_SHIFT))) {
198199
int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
199200
unsigned long flags;
200201

@@ -238,10 +239,10 @@ static int __dma_mmap_from_coherent(struct dma_coherent_mem *mem,
238239
struct vm_area_struct *vma, void *vaddr, size_t size, int *ret)
239240
{
240241
if (mem && vaddr >= mem->virt_base && vaddr + size <=
241-
(mem->virt_base + (mem->size << PAGE_SHIFT))) {
242+
(mem->virt_base + ((dma_addr_t)mem->size << PAGE_SHIFT))) {
242243
unsigned long off = vma->vm_pgoff;
243244
int start = (vaddr - mem->virt_base) >> PAGE_SHIFT;
244-
int user_count = vma_pages(vma);
245+
unsigned long user_count = vma_pages(vma);
245246
int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
246247

247248
*ret = -ENXIO;

0 commit comments

Comments
 (0)