]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
media: pci: ivtv: Add check for DMA map result
authorMikhail Kobuk <m.kobuk@ispras.ru>
Wed, 27 Mar 2024 23:32:23 +0000 (02:32 +0300)
committerHans Verkuil <hverkuil-cisco@xs4all.nl>
Fri, 31 May 2024 11:51:15 +0000 (13:51 +0200)
In case DMA fails, 'dma->SG_length' is 0. This value is later used to
access 'dma->SGarray[dma->SG_length - 1]', which will cause out of
bounds access.

Add check to return early on invalid value. Adjust warnings accordingly.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Fixes: 1932dc2f4cf6 ("media: pci/ivtv: switch from 'pci_' to 'dma_' API")
Signed-off-by: Mikhail Kobuk <m.kobuk@ispras.ru>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
drivers/media/pci/ivtv/ivtv-udma.c
drivers/media/pci/ivtv/ivtv-yuv.c
drivers/media/pci/ivtv/ivtvfb.c

index 99b9f55ca82922c2a2093e5484d46f79c44444a9..f467a00492f4b0e5847abc7ae57f46b7e8385927 100644 (file)
@@ -131,6 +131,8 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
 
        /* Fill SG List with new values */
        if (ivtv_udma_fill_sg_list(dma, &user_dma, 0) < 0) {
+               IVTV_DEBUG_WARN("%s: could not allocate bounce buffers for highmem userspace buffers\n",
+                               __func__);
                unpin_user_pages(dma->map, dma->page_count);
                dma->page_count = 0;
                return -ENOMEM;
@@ -139,6 +141,12 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
        /* Map SG List */
        dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist,
                                    dma->page_count, DMA_TO_DEVICE);
+       if (!dma->SG_length) {
+               IVTV_DEBUG_WARN("%s: DMA map error, SG_length is 0\n", __func__);
+               unpin_user_pages(dma->map, dma->page_count);
+               dma->page_count = 0;
+               return -EINVAL;
+       }
 
        /* Fill SG Array with new values */
        ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1);
index 582146f8d70d5f9c96be91f88ea01dfa1b6f6742..2d9274537725af594f635411c5ba51eab13e3d89 100644 (file)
@@ -114,6 +114,12 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
        }
        dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist,
                                    dma->page_count, DMA_TO_DEVICE);
+       if (!dma->SG_length) {
+               IVTV_DEBUG_WARN("%s: DMA map error, SG_length is 0\n", __func__);
+               unpin_user_pages(dma->map, dma->page_count);
+               dma->page_count = 0;
+               return -EINVAL;
+       }
 
        /* Fill SG Array with new values */
        ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
index 410477e3e621697f40c61fae9a3a1568c6174ab3..d1ab7fee0d05709e6dc2ba2fbc051dc0135da9d4 100644 (file)
@@ -281,10 +281,10 @@ static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
        /* Map User DMA */
        if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
                mutex_unlock(&itv->udma.lock);
-               IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, Error with pin_user_pages: %d bytes, %d pages returned\n",
-                              size_in_bytes, itv->udma.page_count);
+               IVTVFB_WARN("%s, Error in ivtv_udma_setup: %d bytes, %d pages returned\n",
+                              __func__, size_in_bytes, itv->udma.page_count);
 
-               /* pin_user_pages must have failed completely */
+               /* pin_user_pages or DMA must have failed completely */
                return -EIO;
        }