Thread (33 messages) 33 messages, 5 authors, 2021-07-31

Re: [PATCH v6 08/13] iio: afe: rescale: reduce risk of integer overflow

From: Peter Rosin <hidden>
Date: 2021-07-28 07:47:41
Also in: linux-iio, lkml

On 2021-07-28 02:07, Liam Beguin wrote:
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.
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.

Cheers,
Peter
Thanks,
Liam
quoted
Cheers,
Peter
quoted
+			tmp = div_s64(tmp, factor);
+			tmp2 = div_s64(tmp2, factor);
+		}
+		*val = tmp;
+		*val2 = tmp2;
 		return scale_type;
 	case IIO_VAL_INT:
 		*val *= rescale->numerator;
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help