[PATCH v2 4/4] hwmon: ltc2945: Fix possible overflows

From: Cormier, Jonathan
Date: Mon Dec 19 2022 - 19:06:13 EST


From: John Pruitt <jpruitt@xxxxxxxxxxxxxxxx>

Use 64-bit values for intermediate calculations. Check for
overflows and return INT_MAX if overflows happened.

Signed-off-by: John Pruitt <jpruitt@xxxxxxxxxxxxxxxx>
Signed-off-by: "Cormier, Jonathan" <jcormier@xxxxxxxxxxxxxxxx>
---
drivers/hwmon/ltc2945.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c
index fc7d399b2c85..7239422fc6db 100644
--- a/drivers/hwmon/ltc2945.c
+++ b/drivers/hwmon/ltc2945.c
@@ -126,6 +126,10 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
}
val *= 1000;
val = DIV_ROUND_CLOSEST_ULL(val, shunt_resistor);
+ /* check for overflow, use MAX value if it happened */
+ if (val > INT_MAX)
+ val = INT_MAX;
+
break;
case LTC2945_VIN_H:
case LTC2945_MAX_VIN_H:
@@ -159,12 +163,14 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
}

static int ltc2945_val_to_reg(struct device *dev, u8 reg,
- unsigned long val)
+ unsigned long val_32)
{
struct ltc2945_data *data = dev_get_drvdata(dev);
struct regmap *regmap = data->regmap;
u32 shunt_resistor = data->shunt_resistor;
unsigned int control;
+ /* use 64-bit val for intermediate calculations */
+ unsigned long long val = val_32;
int ret;

switch (reg) {
@@ -184,7 +190,7 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
if (control & CONTROL_MULT_SELECT) {
/* 25 mV * 25 uV = 0.625 uV resolution. */
val *= shunt_resistor;
- val = DIV_ROUND_CLOSEST(val, 625 * 1000);
+ val = DIV_ROUND_CLOSEST_ULL(val, 625LL * 1000LL);
} else {
/*
* 0.5 mV * 25 uV = 0.0125 uV resolution.
@@ -192,7 +198,7 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
* accept loss of accuracy.
*/
val *= shunt_resistor;
- val = DIV_ROUND_CLOSEST(val, 25 * 1000) * 2;
+ val = DIV_ROUND_CLOSEST_ULL(val, 25LL * 1000LL) * 2;
}
break;
case LTC2945_VIN_H:
@@ -201,7 +207,7 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
case LTC2945_MAX_VIN_THRES_H:
case LTC2945_MIN_VIN_THRES_H:
/* 25 mV resolution. */
- val /= 25;
+ val = DIV_ROUND_CLOSEST_ULL(val, 25LL);
break;
case LTC2945_ADIN_H:
case LTC2945_MAX_ADIN_H:
@@ -218,11 +224,15 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
case LTC2945_MIN_SENSE_THRES_H:
/* 25 uV resolution. Convert to mA. */
val *= shunt_resistor;
- val = DIV_ROUND_CLOSEST(val, 25 * 1000);
+ val = DIV_ROUND_CLOSEST_ULL(val, 25LL * 1000LL);
break;
default:
return -EINVAL;
}
+ /* If val is too large, just return the max value */
+ if (val > INT_MAX)
+ return INT_MAX;
+
return val;
}

--
2.25.1