Commit 958c7c7e authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[media] v4l2-ctrls: fix corner case in round-to-range code

If you have a maximum that is at the limit of what the type supports,
and the step is > 1, then you can get wrap-around errors since the
code assumes that the maximum that the type supports is
ctrl->maximum + ctrl->step / 2.

In practice this is always fine, but in artificially crafted ranges
you will hit this bug. Since this is core code it should just work.

This bug has always been there but since it doesn't cause problems in
practice it was never noticed.
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent 12c78e66
...@@ -1295,11 +1295,19 @@ static void std_log(const struct v4l2_ctrl *ctrl) ...@@ -1295,11 +1295,19 @@ static void std_log(const struct v4l2_ctrl *ctrl)
} }
} }
/* Round towards the closest legal value */ /*
* Round towards the closest legal value. Be careful when we are
* close to the maximum range of the control type to prevent
* wrap-arounds.
*/
#define ROUND_TO_RANGE(val, offset_type, ctrl) \ #define ROUND_TO_RANGE(val, offset_type, ctrl) \
({ \ ({ \
offset_type offset; \ offset_type offset; \
val += (ctrl)->step / 2; \ if ((ctrl)->maximum >= 0 && \
val >= (ctrl)->maximum - ((ctrl)->step / 2)) \
val = (ctrl)->maximum; \
else \
val += (ctrl)->step / 2; \
val = clamp_t(typeof(val), val, \ val = clamp_t(typeof(val), val, \
(ctrl)->minimum, (ctrl)->maximum); \ (ctrl)->minimum, (ctrl)->maximum); \
offset = (val) - (ctrl)->minimum; \ offset = (val) - (ctrl)->minimum; \
...@@ -1325,7 +1333,10 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, ...@@ -1325,7 +1333,10 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
* the u64 divide that needs special care. * the u64 divide that needs special care.
*/ */
val = ptr.p_s64[idx]; val = ptr.p_s64[idx];
val += ctrl->step / 2; if (ctrl->maximum >= 0 && val >= ctrl->maximum - ctrl->step / 2)
val = ctrl->maximum;
else
val += ctrl->step / 2;
val = clamp_t(s64, val, ctrl->minimum, ctrl->maximum); val = clamp_t(s64, val, ctrl->minimum, ctrl->maximum);
offset = val - ctrl->minimum; offset = val - ctrl->minimum;
do_div(offset, ctrl->step); do_div(offset, ctrl->step);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment