mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
media: pci: tw68: Fix null-ptr-deref bug in buf prepare and finish
[ Upstream commit 1634b7adcc ]
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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
f0a06203f2
commit
dcf632bca4
@@ -437,6 +437,7 @@ static void tw68_buf_queue(struct vb2_buffer *vb)
|
|||||||
*/
|
*/
|
||||||
static int tw68_buf_prepare(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_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
||||||
struct vb2_queue *vq = vb->vb2_queue;
|
struct vb2_queue *vq = vb->vb2_queue;
|
||||||
struct tw68_dev *dev = vb2_get_drv_priv(vq);
|
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;
|
bpl = (dev->width * dev->fmt->depth) >> 3;
|
||||||
switch (dev->field) {
|
switch (dev->field) {
|
||||||
case V4L2_FIELD_TOP:
|
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);
|
0, UNSET, bpl, 0, dev->height);
|
||||||
break;
|
break;
|
||||||
case V4L2_FIELD_BOTTOM:
|
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);
|
UNSET, 0, bpl, 0, dev->height);
|
||||||
break;
|
break;
|
||||||
case V4L2_FIELD_SEQ_TB:
|
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),
|
0, bpl * (dev->height >> 1),
|
||||||
bpl, 0, dev->height >> 1);
|
bpl, 0, dev->height >> 1);
|
||||||
break;
|
break;
|
||||||
case V4L2_FIELD_SEQ_BT:
|
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 * (dev->height >> 1), 0,
|
||||||
bpl, 0, dev->height >> 1);
|
bpl, 0, dev->height >> 1);
|
||||||
break;
|
break;
|
||||||
case V4L2_FIELD_INTERLACED:
|
case V4L2_FIELD_INTERLACED:
|
||||||
default:
|
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);
|
0, bpl, bpl, bpl, dev->height >> 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tw68_buf_finish(struct vb2_buffer *vb)
|
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_dev *dev = vb2_get_drv_priv(vq);
|
||||||
struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb);
|
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)
|
static int tw68_start_streaming(struct vb2_queue *q, unsigned int count)
|
||||||
|
|||||||
Reference in New Issue
Block a user