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

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,
Peter
quoted
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