[media] media: videobuf2: fix the length check for mmap
authorMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 19 Apr 2013 10:18:01 +0000 (07:18 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 25 Apr 2013 12:54:00 +0000 (09:54 -0300)
Memory maps typically require that the buffer size to be page
aligned. Currently, two memops drivers do such alignment
internally, but videobuf-vmalloc doesn't.
Also, the buffer overflow check doesn't take it into account.
So, instead of doing it at each memops driver, enforce it at
VB2 core.

Reported-by: Prabhakar lad <prabhakar.csengg@gmail.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/v4l2-core/videobuf2-core.c
drivers/media/v4l2-core/videobuf2-dma-contig.c
drivers/media/v4l2-core/videobuf2-dma-sg.c

index 58c17444d22faf4c1117383c1a86698aed2450e7..7d833eefaf4e9bf2124f035db614179127268e4a 100644 (file)
@@ -54,10 +54,15 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
        void *mem_priv;
        int plane;
 
-       /* Allocate memory for all planes in this buffer */
+       /*
+        * Allocate memory for all planes in this buffer
+        * NOTE: mmapped areas should be page aligned
+        */
        for (plane = 0; plane < vb->num_planes; ++plane) {
+               unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]);
+
                mem_priv = call_memop(q, alloc, q->alloc_ctx[plane],
-                                     q->plane_sizes[plane], q->gfp_flags);
+                                     size, q->gfp_flags);
                if (IS_ERR_OR_NULL(mem_priv))
                        goto free;
 
@@ -1852,6 +1857,7 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
        struct vb2_buffer *vb;
        unsigned int buffer, plane;
        int ret;
+       unsigned long length;
 
        if (q->memory != V4L2_MEMORY_MMAP) {
                dprintk(1, "Queue is not currently set up for mmap\n");
@@ -1886,8 +1892,15 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
 
        vb = q->bufs[buffer];
 
-       if (vb->v4l2_planes[plane].length < (vma->vm_end - vma->vm_start)) {
-               dprintk(1, "Invalid length\n");
+       /*
+        * MMAP requires page_aligned buffers.
+        * The buffer length was page_aligned at __vb2_buf_mem_alloc(),
+        * so, we need to do the same here.
+        */
+       length = PAGE_ALIGN(vb->v4l2_planes[plane].length);
+       if (length < (vma->vm_end - vma->vm_start)) {
+               dprintk(1,
+                       "MMAP invalid, as it would overflow buffer length\n");
                return -EINVAL;
        }
 
index ae35d255a43016cc325db28899a2351b83f4d02f..fd56f25632018fde92f1acefc4d284e6a47d6dba 100644 (file)
@@ -162,9 +162,6 @@ static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags)
        if (!buf)
                return ERR_PTR(-ENOMEM);
 
-       /* align image size to PAGE_SIZE */
-       size = PAGE_ALIGN(size);
-
        buf->vaddr = dma_alloc_coherent(dev, size, &buf->dma_addr,
                                                GFP_KERNEL | gfp_flags);
        if (!buf->vaddr) {
index 59522b2ebae1027e88282dc40904f1df11ac898e..16ae3dcc7e294cdb4722d0991b31b9e6ac7cacf0 100644 (file)
@@ -55,7 +55,8 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_fla
        buf->write = 0;
        buf->offset = 0;
        buf->sg_desc.size = size;
-       buf->sg_desc.num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       /* size is already page aligned */
+       buf->sg_desc.num_pages = size >> PAGE_SHIFT;
 
        buf->sg_desc.sglist = vzalloc(buf->sg_desc.num_pages *
                                      sizeof(*buf->sg_desc.sglist));