| From 3bacc10cd4a85bc70bc0b6c001d3bf995c7fe04c Mon Sep 17 00:00:00 2001 |
| From: Maciej Matraszek <m.matraszek@samsung.com> |
| Date: Mon, 15 Sep 2014 05:14:48 -0300 |
| Subject: media: v4l2-common: fix overflow in v4l_bound_align_image() |
| |
| From: Maciej Matraszek <m.matraszek@samsung.com> |
| |
| commit 3bacc10cd4a85bc70bc0b6c001d3bf995c7fe04c upstream. |
| |
| Fix clamp_align() used in v4l_bound_align_image() to prevent overflow |
| when passed large value like UINT32_MAX. |
| |
| In the current implementation: |
| clamp_align(UINT32_MAX, 8, 8192, 3) |
| |
| returns 8, because in line: |
| |
| x = (x + (1 << (align - 1))) & mask; |
| |
| x overflows to (-1 + 4) & 0x7 = 3, while expected value is 8192. |
| |
| v4l_bound_align_image() is heavily used in VIDIOC_S_FMT and |
| VIDIOC_SUBDEV_S_FMT ioctls handlers, and documentation of the latter |
| explicitly states that: |
| |
| "The modified format should be as close as possible to the original |
| request." |
| -- http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-subdev-g-fmt.html |
| |
| Thus one would expect, that passing UINT32_MAX as format width and |
| height will result in setting maximum possible resolution for the |
| device. Particularly, when the driver doesn't support |
| VIDIOC_ENUM_FRAMESIZES ioctl, which is common in the codebase. |
| |
| Fixes changeset: b0d3159be9a3 |
| |
| Signed-off-by: Maciej Matraszek <m.matraszek@samsung.com> |
| Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com> |
| Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/media/v4l2-core/v4l2-common.c | 9 +++------ |
| 1 file changed, 3 insertions(+), 6 deletions(-) |
| |
| --- a/drivers/media/v4l2-core/v4l2-common.c |
| +++ b/drivers/media/v4l2-core/v4l2-common.c |
| @@ -435,16 +435,13 @@ static unsigned int clamp_align(unsigned |
| /* Bits that must be zero to be aligned */ |
| unsigned int mask = ~((1 << align) - 1); |
| |
| + /* Clamp to aligned min and max */ |
| + x = clamp(x, (min + ~mask) & mask, max & mask); |
| + |
| /* Round to nearest aligned value */ |
| if (align) |
| x = (x + (1 << (align - 1))) & mask; |
| |
| - /* Clamp to aligned value of min and max */ |
| - if (x < min) |
| - x = (min + ~mask) & mask; |
| - else if (x > max) |
| - x = max & mask; |
| - |
| return x; |
| } |
| |