Commit 2eb30577 authored by Liam Beguin's avatar Liam Beguin Committed by Jonathan Cameron
Browse files

iio: afe: rescale: reduce risk of integer overflow



Reduce the risk of integer overflow by doing the scale calculation on
a 64-bit integer. Since the rescaling is only performed on *val, reuse
the IIO_VAL_FRACTIONAL_LOG2 case.

Signed-off-by: default avatarLiam Beguin <liambeguin@gmail.com>
Reviewed-by: default avatarPeter Rosin <peda@axentia.se>
Reviewed-by: default avatarAndy Shevchenko <andy.shevchenko@gmail.com>
Link: https://lore.kernel.org/r/20220213025739.2561834-6-liambeguin@gmail.com


Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent f5fc003d
Loading
Loading
Loading
Loading
+18 −5
Original line number Diff line number Diff line
@@ -24,21 +24,31 @@ int rescale_process_scale(struct rescale *rescale, int scale_type,
			  int *val, int *val2)
{
	s64 tmp;
	int _val, _val2;
	s32 rem, rem2;
	u32 mult;
	u32 neg;

	switch (scale_type) {
	case IIO_VAL_FRACTIONAL:
		*val *= rescale->numerator;
		*val2 *= rescale->denominator;
		return scale_type;
	case IIO_VAL_INT:
		*val *= rescale->numerator;
		if (rescale->denominator == 1)
			return scale_type;
		*val2 = rescale->denominator;
		return IIO_VAL_FRACTIONAL;
	case IIO_VAL_FRACTIONAL:
		/*
		 * When the product of both scales doesn't overflow, avoid
		 * potential accuracy loss (for in kernel consumers) by
		 * keeping a fractional representation.
		 */
		if (!check_mul_overflow(*val, rescale->numerator, &_val) &&
		    !check_mul_overflow(*val2, rescale->denominator, &_val2)) {
			*val = _val;
			*val2 = _val2;
			return IIO_VAL_FRACTIONAL;
		}
		fallthrough;
	case IIO_VAL_FRACTIONAL_LOG2:
		tmp = (s64)*val * 1000000000LL;
		tmp = div_s64(tmp, rescale->denominator);
@@ -50,7 +60,10 @@ int rescale_process_scale(struct rescale *rescale, int scale_type,
		if (!rem)
			return scale_type;

		tmp = 1 << *val2;
		if (scale_type == IIO_VAL_FRACTIONAL)
			tmp = *val2;
		else
			tmp = ULL(1) << *val2;

		rem2 = *val % (int)tmp;
		*val = *val / (int)tmp;