diff options
author | harperchen <harperchen1110@gmail.com> | 2023-03-03 18:30:11 +0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@kernel.org> | 2023-03-20 00:56:45 +0300 |
commit | 1634b7adcc5bef645b3666fdd564e5952a9e24e0 (patch) | |
tree | ebdf9d9cca8f90b0c5962f9a18d2df29dda216c1 /drivers/media/pci/tw68/tw68-video.c | |
parent | 3af805f70c83525305c1096ec15c64f50d9efa05 (diff) | |
download | linux-1634b7adcc5bef645b3666fdd564e5952a9e24e0.tar.xz |
media: pci: tw68: Fix null-ptr-deref bug in buf prepare and finish
When the driver calls tw68_risc_buffer() to prepare the buffer, the
function call dma_alloc_coherent may fail, resulting in a empty buffer
buf->cpu. Later when we free the buffer or access the buffer, null ptr
deref is triggered.
This bug is similar to the following one:
https://git.linuxtv.org/media_stage.git/commit/?id=2b064d91440b33fba5b452f2d1b31f13ae911d71.
We believe the bug can be also dynamically triggered from user side.
Similarly, we fix this by checking the return value of tw68_risc_buffer()
and the value of buf->cpu before buffer free.
Signed-off-by: harperchen <harperchen1110@gmail.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Diffstat (limited to 'drivers/media/pci/tw68/tw68-video.c')
-rw-r--r-- | drivers/media/pci/tw68/tw68-video.c | 16 |
1 files changed, 9 insertions, 7 deletions
diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 0cbc5b038073..773a18702d36 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -437,6 +437,7 @@ static void tw68_buf_queue(struct vb2_buffer *vb) */ static int tw68_buf_prepare(struct vb2_buffer *vb) { + int ret; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vb2_queue *vq = vb->vb2_queue; struct tw68_dev *dev = vb2_get_drv_priv(vq); @@ -452,30 +453,30 @@ static int tw68_buf_prepare(struct vb2_buffer *vb) bpl = (dev->width * dev->fmt->depth) >> 3; switch (dev->field) { case V4L2_FIELD_TOP: - tw68_risc_buffer(dev->pci, buf, dma->sgl, + ret = tw68_risc_buffer(dev->pci, buf, dma->sgl, 0, UNSET, bpl, 0, dev->height); break; case V4L2_FIELD_BOTTOM: - tw68_risc_buffer(dev->pci, buf, dma->sgl, + ret = tw68_risc_buffer(dev->pci, buf, dma->sgl, UNSET, 0, bpl, 0, dev->height); break; case V4L2_FIELD_SEQ_TB: - tw68_risc_buffer(dev->pci, buf, dma->sgl, + ret = tw68_risc_buffer(dev->pci, buf, dma->sgl, 0, bpl * (dev->height >> 1), bpl, 0, dev->height >> 1); break; case V4L2_FIELD_SEQ_BT: - tw68_risc_buffer(dev->pci, buf, dma->sgl, + ret = tw68_risc_buffer(dev->pci, buf, dma->sgl, bpl * (dev->height >> 1), 0, bpl, 0, dev->height >> 1); break; case V4L2_FIELD_INTERLACED: default: - tw68_risc_buffer(dev->pci, buf, dma->sgl, + ret = tw68_risc_buffer(dev->pci, buf, dma->sgl, 0, bpl, bpl, bpl, dev->height >> 1); break; } - return 0; + return ret; } static void tw68_buf_finish(struct vb2_buffer *vb) @@ -485,7 +486,8 @@ static void tw68_buf_finish(struct vb2_buffer *vb) struct tw68_dev *dev = vb2_get_drv_priv(vq); struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb); - dma_free_coherent(&dev->pci->dev, buf->size, buf->cpu, buf->dma); + if (buf->cpu) + dma_free_coherent(&dev->pci->dev, buf->size, buf->cpu, buf->dma); } static int tw68_start_streaming(struct vb2_queue *q, unsigned int count) |