Re: [PATCH v6 08/13] iio: afe: rescale: reduce risk of integer overflow
From: Liam Beguin <hidden>
Date: 2021-07-29 16:02:39
Also in:
linux-iio, lkml
On Wed Jul 28, 2021 at 3:47 AM EDT, Peter Rosin wrote:
On 2021-07-28 02:07, Liam Beguin wrote:quoted
On Fri Jul 23, 2021 at 5:17 PM EDT, Peter Rosin wrote:quoted
On 2021-07-21 05:06, Liam Beguin wrote:quoted
From: Liam Beguin <redacted> Reduce the risk of integer overflow by doing the scale calculation with 64bit integers and looking for a Greatest Common Divider for both parts of the fractional value when required. Signed-off-by: Liam Beguin <redacted> --- drivers/iio/afe/iio-rescale.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index 6f6a711ae3ae..35fa3b4e53e0 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c@@ -21,12 +21,21 @@ int rescale_process_scale(struct rescale *rescale, int scale_type, int *val, int *val2) { - unsigned long long tmp; + s64 tmp, tmp2; + u32 factor; switch (scale_type) { case IIO_VAL_FRACTIONAL: - *val *= rescale->numerator; - *val2 *= rescale->denominator; + if (check_mul_overflow(*val, rescale->numerator, (s32 *)&tmp) || + check_mul_overflow(*val2, rescale->denominator, (s32 *)&tmp2)) { + tmp = (s64)*val * rescale->numerator; + tmp2 = (s64)*val2 * rescale->denominator; + factor = gcd(tmp, tmp2);Hi Peter,quoted
Hi! Reiterating that gcd() only works for unsigned operands, so this is broken for negative values.Apologies, I didn't mean to make it seem like I ignored your comments. I should've added a note. After you pointed out that gcd() only works for unsigned elements, I added test cases for negative values, and all tests passed. I'll look into it more.Maybe I've misread the code and gcd is in fact working for negative numbers? However, I imagine it might be arch specific, so testing on a single arch feels insufficient and deeper analysis is required. However, looking at lib/math/gcd.c it certainly still looks like negative values will work very poorly, and there is no macro magic in include/linux/gcd.h to handle it by wrapping the core C routine.
I agree that looking at lib/math/gcd.c odd things might happen with negative values. I'll use the the absolute values to calculate the GCD as it shouldn't affect the value of factor.
quoted
rescale_voltage_divider_props() seems to also use gcd() with signed integers.The type of the operands may be s32, but if you look at how those values are populated, and with what they are populated, I think you will find that only positive scale factors are sensible for a voltage divider. Using resistors with so high resistance that s32 is not enough is simply not supported.
That makes sense! Thanks, Liam
Cheers, Peterquoted
Thanks, Liamquoted
Cheers, Peterquoted
+ tmp = div_s64(tmp, factor); + tmp2 = div_s64(tmp2, factor); + } + *val = tmp; + *val2 = tmp2; return scale_type; case IIO_VAL_INT: *val *= rescale->numerator;