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