Skip to contentSkip to conversation

media: omap_vout: potential buffer overflow in vidioc_dqbuf()

PATCH Superseded Dan Carpenter 3 participants 5 messages Apr 9, 2019 – Apr 11, 2019

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 media: omap_vout: potential buffer overflow in vidioc_dqbuf()

The "b->index" is a u32 the comes from the user in the ioctl. It hasn't been checked. We aren't supposed to use it but we're instead supposed to use the value that gets written to it when we call videobuf_dqbuf().

The videobuf_dqbuf() first memsets it to zero and then re-initializes it inside the videobuf_status() function. It's this final value which we want.

Fixes 72915e851da9 ("[media] V4L2: OMAP: VOUT: dma map and unmap v4l2 buffers in qbuf and dqbuf")

---
UNTESTED! I think I understand this code now, but I have struggled to read it correctly in the past. Please review carefully.

 drivers/media/platform/omap/omap_vout.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/omap/omap_vout.c +2 -2
index 37f0d7146dfa..15e38990e85a 100644
@@ -1527,8 +1527,6 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
 	unsigned long size;
 	struct videobuf_buffer *vb;
 
-	vb = q->bufs[b->index];
-
 	if (!vout->streaming)
 		return -EINVAL;
 
@@ -1539,6 +1537,8 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
 		/* Call videobuf_dqbuf for  blocking mode */
 		ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
 
+	vb = q->bufs[b->index];
+
 	addr = (unsigned long) vout->buf_phy_addr[vb->i];
 	size = (unsigned long) vb->size;
 	dma_unmap_single(vout->vid_dev->v4l2_dev.dev,  addr,
Signature · 1 line
2.17.1
#1 lore raw
Quoted 32 lines · Dan Carpenter

The "b->index" is a u32 the comes from the user in the ioctl. It hasn't been checked. We aren't supposed to use it but we're instead supposed to use the value that gets written to it when we call videobuf_dqbuf().

The videobuf_dqbuf() first memsets it to zero and then re-initializes it inside the videobuf_status() function. It's this final value which we want.

Fixes 72915e851da9 ("[media] V4L2: OMAP: VOUT: dma map and unmap v4l2 buffers in qbuf and dqbuf")

---
UNTESTED! I think I understand this code now, but I have struggled to read it correctly in the past. Please review carefully.

 drivers/media/platform/omap/omap_vout.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/omap/omap_vout.c +0 -2
index 37f0d7146dfa..15e38990e85a 100644
@@ -1527,8 +1527,6 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
 	unsigned long size;
 	struct videobuf_buffer *vb;
 
-	vb = q->bufs[b->index];
-
 	if (!vout->streaming)
 		return -EINVAL;
 

drivers/media/platform/omap/omap_vout.c static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) · line 1538

Quoted 2 lines
drivers/media/platform/omap/omap_vout.c +0 -0
@@ -1539,6 +1537,8 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
 		/* Call videobuf_dqbuf for  blocking mode */
 		ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);

We need a:

	if (ret)
		return ret;

here. Or alternatively, add 'if (!ret)' around the next five lines.

b->index is only valid if the videobuf_dqbuf call returned 0.

Regards,

Hans

Quoted 7 lines
drivers/media/platform/omap/omap_vout.c +2 -0
+	vb = q->bufs[b->index];
+
 	addr = (unsigned long) vout->buf_phy_addr[vb->i];
 	size = (unsigned long) vb->size;
 	dma_unmap_single(vout->vid_dev->v4l2_dev.dev,  addr,
 
#2 lore raw
Quoted 20 lines · Hans Verkuil
Quoted 14 lines · Dan Carpenter
drivers/media/platform/omap/omap_vout.c +0 -2
index 37f0d7146dfa..15e38990e85a 100644
@@ -1527,8 +1527,6 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
 	unsigned long size;
 	struct videobuf_buffer *vb;
 
-	vb = q->bufs[b->index];
-
 	if (!vout->streaming)
 		return -EINVAL;
 

drivers/media/platform/omap/omap_vout.c static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) · line 1538

Quoted 2 lines
drivers/media/platform/omap/omap_vout.c +0 -0
@@ -1539,6 +1537,8 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
 		/* Call videobuf_dqbuf for  blocking mode */
 		ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);

We need a:

Quoted 7 lines
	if (ret)
		return ret;

here. Or alternatively, add 'if (!ret)' around the next five lines.

b->index is only valid if the videobuf_dqbuf call returned 0.

Doh. Thanks.

regards,
dan carpenter

#3 lore raw

I think you might have the wrong Amber copied on this email.

Amber

-----Original Message-----
From: Dan Carpenter [mailto:[email protected]]
Sent: Wednesday, April 10, 2019 6:14 AM
To: Hans Verkuil
Cc: Mauro Carvalho Chehab; Scheurer, Amber; Niklas Söderlund; Philipp Zabel; Parrot, Benoit; [email protected]; [email protected]; Andrzej Hajda
Subject: [EXTERNAL] Re: [PATCH] media: omap_vout: potential buffer overflow in vidioc_dqbuf()

Quoted 20 lines · Hans Verkuil
Quoted 14 lines · Dan Carpenter
drivers/media/platform/omap/omap_vout.c +0 -2
index 37f0d7146dfa..15e38990e85a 100644
@@ -1527,8 +1527,6 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
 	unsigned long size;
 	struct videobuf_buffer *vb;
 
-	vb = q->bufs[b->index];
-
 	if (!vout->streaming)
 		return -EINVAL;
 

drivers/media/platform/omap/omap_vout.c static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) · line 1538

Quoted 2 lines
drivers/media/platform/omap/omap_vout.c +0 -0
@@ -1539,6 +1537,8 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
 		/* Call videobuf_dqbuf for  blocking mode */
 		ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);

We need a:

Quoted 7 lines
	if (ret)
		return ret;

here. Or alternatively, add 'if (!ret)' around the next five lines.

b->index is only valid if the videobuf_dqbuf call returned 0.

Doh. Thanks.

regards,
dan carpenter

#4 lore raw

PATCH v2 1/1 media: omap_vout: potential buffer overflow in vidioc_dqbuf()

In reply to Hans Verkuil

The "b->index" is a u32 the comes from the user in the ioctl. It hasn't been checked. We aren't supposed to use it but we're instead supposed to use the value that gets written to it when we call videobuf_dqbuf().

The videobuf_dqbuf() first memsets it to zero and then re-initializes it inside the videobuf_status() function. It's this final value which we want.

Hans Verkuil pointed out that we need to check the return from videobuf_dqbuf(). I ended up doing a little cleanup related to that as well.

Fixes 72915e851da9 ("[media] V4L2: OMAP: VOUT: dma map and unmap v4l2 buffers in qbuf and dqbuf")

---
v2: check videobuf_dqbuf() return

 drivers/media/platform/omap/omap_vout.c | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)
drivers/media/platform/omap/omap_vout.c +6 -9
index 37f0d7146dfa..cb6a9e3946b6 100644
@@ -1527,23 +1527,20 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
 	unsigned long size;
 	struct videobuf_buffer *vb;
 
-	vb = q->bufs[b->index];
-
 	if (!vout->streaming)
 		return -EINVAL;
 
-	if (file->f_flags & O_NONBLOCK)
-		/* Call videobuf_dqbuf for non blocking mode */
-		ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
-	else
-		/* Call videobuf_dqbuf for  blocking mode */
-		ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
+	ret = videobuf_dqbuf(q, b, !!(file->f_flags & O_NONBLOCK));
+	if (ret)
+		return ret;
+
+	vb = q->bufs[b->index];
 
 	addr = (unsigned long) vout->buf_phy_addr[vb->i];
 	size = (unsigned long) vb->size;
 	dma_unmap_single(vout->vid_dev->v4l2_dev.dev,  addr,
 				size, DMA_TO_DEVICE);
-	return ret;
+	return 0;
 }
 
 static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
Signature · 1 line
2.17.1