Sophie

Sophie

distrib > Fedora > 16 > i386 > by-pkgid > b10490245063b25104ad1d93e768d6a1 > files > 13

v4l-utils-0.8.8-2.fc16.src.rpm

From 6662f9f04e529ddeae3828fe18b49f7b239fdb10 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Mon, 9 Jul 2012 10:13:11 +0200
Subject: [PATCH 13/14] libv4l2: Ensure we always set buf->length when
 converting

Some apps blindly use buf->length when calling munmap, even if a previous
call (ie dqbuf) on the buffer failed. We used to not set buf->length to
our conversion buffer length when the actual ioctl call to the device, or
the format conversion failed.

When a dqbuf succeeded and the conversion failed this which would cause
us to leave buf->length set to the real buffer length rather then the
conversion buffer length, if the app then wrongly uses buf->length (*)
for a munmap we would not recognize this as munmap of the conversion
buffer and pass it through to the real munmap unmapping a part of
our conversion buf without being aware of this!

*) After from the point of the app a failed dqbuf, so it should not trust the
contents of buf at all.

This patch makes things work even for buggy apps, by always setting
buf->length when converting even if things fail.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>

Conflicts:
	lib/libv4l2/libv4l2.c
---
 lib/libv4l2/libv4l2.c |   52 +++++++++++++++++++++++++++++--------------------
 1 file changed, 31 insertions(+), 21 deletions(-)

diff --git a/lib/libv4l2/libv4l2.c b/lib/libv4l2/libv4l2.c
index 089fc38..a8f17ed 100644
--- a/lib/libv4l2/libv4l2.c
+++ b/lib/libv4l2/libv4l2.c
@@ -486,6 +486,23 @@ static int v4l2_needs_conversion(int index)
 	return 0;
 }
 
+static void v4l2_set_conversion_buf_params(int index, struct v4l2_buffer *buf)
+{
+	if (!v4l2_needs_conversion(index))
+		return;
+
+	/* This may happen if the ioctl failed */
+	if (buf->index >= devices[index].no_frames)
+		buf->index = 0;
+
+	buf->m.offset = V4L2_MMAP_OFFSET_MAGIC | buf->index;
+	buf->length = V4L2_FRAME_BUF_SIZE;
+	if (devices[index].frame_map_count[buf->index])
+		buf->flags |= V4L2_BUF_FLAG_MAPPED;
+	else
+		buf->flags &= ~V4L2_BUF_FLAG_MAPPED;
+}
+
 static int v4l2_buffers_mapped(int index)
 {
 	unsigned int i;
@@ -1182,19 +1199,14 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
 		/* Do a real query even when converting to let the driver fill in
 		   things like buf->field */
 		result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF, buf);
-		if (result || !v4l2_needs_conversion(index))
-			break;
 
-		buf->m.offset = V4L2_MMAP_OFFSET_MAGIC | buf->index;
-		buf->length = V4L2_FRAME_BUF_SIZE;
-		if (devices[index].frame_map_count[buf->index])
-			buf->flags |= V4L2_BUF_FLAG_MAPPED;
-		else
-			buf->flags &= ~V4L2_BUF_FLAG_MAPPED;
+		v4l2_set_conversion_buf_params(index, buf);
 		break;
 	}
 
-	case VIDIOC_QBUF:
+	case VIDIOC_QBUF: {
+		struct v4l2_buffer *buf = arg;
+
 		if (devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ) {
 			result = v4l2_deactivate_read_stream(index);
 			if (result)
@@ -1209,7 +1221,10 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
 		}
 
 		result = SYS_IOCTL(devices[index].fd, VIDIOC_QBUF, arg);
+
+		v4l2_set_conversion_buf_params(index, buf);
 		break;
+	}
 
 	case VIDIOC_DQBUF: {
 		struct v4l2_buffer *buf = arg;
@@ -1248,19 +1263,14 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
 			}
 		}
 
-		result = v4l2_dequeue_and_convert(index, buf, 0, V4L2_FRAME_BUF_SIZE);
-		if (result < 0)
-			break;
-
-		buf->bytesused = result;
-		buf->m.offset = V4L2_MMAP_OFFSET_MAGIC | buf->index;
-		buf->length = V4L2_FRAME_BUF_SIZE;
-		if (devices[index].frame_map_count[buf->index])
-			buf->flags |= V4L2_BUF_FLAG_MAPPED;
-		else
-			buf->flags &= ~V4L2_BUF_FLAG_MAPPED;
+		result = v4l2_dequeue_and_convert(index, buf, 0,
+						  V4L2_FRAME_BUF_SIZE);
+		if (result >= 0) {
+			buf->bytesused = result;
+			result = 0;
+		}
 
-		result = 0;
+		v4l2_set_conversion_buf_params(index, buf);
 		break;
 	}
 
-- 
1.7.10.4