diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-04-19 06:18:01 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-04-25 08:54:00 -0400 |
commit | 7f8414594e4755234fd0ca415630cfe2dfab42ce (patch) | |
tree | 4fc8507e954362d9f5898703e0c10dbd1651b2b8 | |
parent | b3404a8ef567de43b74018bbdbd989b53426d422 (diff) |
[media] media: videobuf2: fix the length check for mmap
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>
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-core.c | 21 | ||||
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-dma-contig.c | 3 | ||||
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-dma-sg.c | 3 |
3 files changed, 19 insertions, 8 deletions
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 58c17444d22f..7d833eefaf4e 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c | |||
@@ -54,10 +54,15 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) | |||
54 | void *mem_priv; | 54 | void *mem_priv; |
55 | int plane; | 55 | int plane; |
56 | 56 | ||
57 | /* Allocate memory for all planes in this buffer */ | 57 | /* |
58 | * Allocate memory for all planes in this buffer | ||
59 | * NOTE: mmapped areas should be page aligned | ||
60 | */ | ||
58 | for (plane = 0; plane < vb->num_planes; ++plane) { | 61 | for (plane = 0; plane < vb->num_planes; ++plane) { |
62 | unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]); | ||
63 | |||
59 | mem_priv = call_memop(q, alloc, q->alloc_ctx[plane], | 64 | mem_priv = call_memop(q, alloc, q->alloc_ctx[plane], |
60 | q->plane_sizes[plane], q->gfp_flags); | 65 | size, q->gfp_flags); |
61 | if (IS_ERR_OR_NULL(mem_priv)) | 66 | if (IS_ERR_OR_NULL(mem_priv)) |
62 | goto free; | 67 | goto free; |
63 | 68 | ||
@@ -1852,6 +1857,7 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) | |||
1852 | struct vb2_buffer *vb; | 1857 | struct vb2_buffer *vb; |
1853 | unsigned int buffer, plane; | 1858 | unsigned int buffer, plane; |
1854 | int ret; | 1859 | int ret; |
1860 | unsigned long length; | ||
1855 | 1861 | ||
1856 | if (q->memory != V4L2_MEMORY_MMAP) { | 1862 | if (q->memory != V4L2_MEMORY_MMAP) { |
1857 | dprintk(1, "Queue is not currently set up for mmap\n"); | 1863 | 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) | |||
1886 | 1892 | ||
1887 | vb = q->bufs[buffer]; | 1893 | vb = q->bufs[buffer]; |
1888 | 1894 | ||
1889 | if (vb->v4l2_planes[plane].length < (vma->vm_end - vma->vm_start)) { | 1895 | /* |
1890 | dprintk(1, "Invalid length\n"); | 1896 | * MMAP requires page_aligned buffers. |
1897 | * The buffer length was page_aligned at __vb2_buf_mem_alloc(), | ||
1898 | * so, we need to do the same here. | ||
1899 | */ | ||
1900 | length = PAGE_ALIGN(vb->v4l2_planes[plane].length); | ||
1901 | if (length < (vma->vm_end - vma->vm_start)) { | ||
1902 | dprintk(1, | ||
1903 | "MMAP invalid, as it would overflow buffer length\n"); | ||
1891 | return -EINVAL; | 1904 | return -EINVAL; |
1892 | } | 1905 | } |
1893 | 1906 | ||
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index ae35d255a430..fd56f2563201 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c | |||
@@ -162,9 +162,6 @@ static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags) | |||
162 | if (!buf) | 162 | if (!buf) |
163 | return ERR_PTR(-ENOMEM); | 163 | return ERR_PTR(-ENOMEM); |
164 | 164 | ||
165 | /* align image size to PAGE_SIZE */ | ||
166 | size = PAGE_ALIGN(size); | ||
167 | |||
168 | buf->vaddr = dma_alloc_coherent(dev, size, &buf->dma_addr, | 165 | buf->vaddr = dma_alloc_coherent(dev, size, &buf->dma_addr, |
169 | GFP_KERNEL | gfp_flags); | 166 | GFP_KERNEL | gfp_flags); |
170 | if (!buf->vaddr) { | 167 | if (!buf->vaddr) { |
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index 59522b2ebae1..16ae3dcc7e29 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c | |||
@@ -55,7 +55,8 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_fla | |||
55 | buf->write = 0; | 55 | buf->write = 0; |
56 | buf->offset = 0; | 56 | buf->offset = 0; |
57 | buf->sg_desc.size = size; | 57 | buf->sg_desc.size = size; |
58 | buf->sg_desc.num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; | 58 | /* size is already page aligned */ |
59 | buf->sg_desc.num_pages = size >> PAGE_SHIFT; | ||
59 | 60 | ||
60 | buf->sg_desc.sglist = vzalloc(buf->sg_desc.num_pages * | 61 | buf->sg_desc.sglist = vzalloc(buf->sg_desc.num_pages * |
61 | sizeof(*buf->sg_desc.sglist)); | 62 | sizeof(*buf->sg_desc.sglist)); |