lkml.org 
[lkml]   [2020]   [Apr]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.4 048/118] dma-coherent: fix integer overflow in the reserved-memory dma allocation
    Date
    From: Kevin Grandemange <kevin.grandemange@allegrodvt.com>

    [ 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>
    ---
    kernel/dma/coherent.c | 13 +++++++------
    1 file changed, 7 insertions(+), 6 deletions(-)

    diff --git a/kernel/dma/coherent.c b/kernel/dma/coherent.c
    index 551b0eb7028a3..2a0c4985f38e4 100644
    --- a/kernel/dma/coherent.c
    +++ b/kernel/dma/coherent.c
    @@ -134,7 +134,7 @@ static void *__dma_alloc_from_coherent(struct device *dev,

    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;

    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.
    */
    - *dma_handle = dma_get_device_base(dev, mem) + (pageno << PAGE_SHIFT);
    - ret = mem->virt_base + (pageno << PAGE_SHIFT);
    + *dma_handle = dma_get_device_base(dev, mem) +
    + ((dma_addr_t)pageno << PAGE_SHIFT);
    + ret = mem->virt_base + ((dma_addr_t)pageno << PAGE_SHIFT);
    spin_unlock_irqrestore(&mem->spinlock, flags);
    memset(ret, 0, size);
    return ret;
    @@ -194,7 +195,7 @@ static int __dma_release_from_coherent(struct dma_coherent_mem *mem,
    int order, void *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;
    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)
    {
    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;
    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;

    *ret = -ENXIO;
    --
    2.20.1


    \
     
     \ /
      Last update: 2020-04-22 12:19    [W:2.717 / U:0.020 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site