]> git.ipfire.org Git - thirdparty/kernel/stable.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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 19 Oct 2025 14:21:55 +0000 (16:21 +0200)
commit 629913d6d79508b166c66e07e4857e20233d85a9 upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/media/pci/ivtv/ivtv-udma.c
drivers/media/pci/ivtv/ivtv-yuv.c
drivers/media/pci/ivtv/ivtvfb.c

index 210be8290f24dddd95c330780c3d7a80895b2994..fd76f88975ae3a76fe2548e5f812c153ae0adbc5 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 0e6014f95178b8930935ddd9fc9e19e3285f324d..c6573859843ef5dc301e00c307659187d662758d 100644 (file)
@@ -115,6 +115,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 5ad03b2a50bdbba0d4de27a4e13f244373d9a2b4..1f8b8caa69bdd3b26c8aa67b6270711ae4c22681 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;
        }