Commit 629913d6 authored by Mikhail Kobuk's avatar Mikhail Kobuk Committed by Hans Verkuil

media: pci: ivtv: Add check for DMA map result

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: 1932dc2f ("media: pci/ivtv: switch from 'pci_' to 'dma_' API")
Signed-off-by: default avatarMikhail Kobuk <m.kobuk@ispras.ru>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
parent dd40472d
......@@ -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);
......
......@@ -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);
......
......@@ -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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment