From: Guenter Roeck <linux@roeck-us.net>
To: Hardware Monitoring <linux-hwmon@vger.kernel.org>
Cc: Guenter Roeck <linux@roeck-us.net>,
Loic Poulain <loic.poulain@oss.qualcomm.com>
Subject: [PATCH] hwmon: (ina2xx) Fix overflow issues
Date: Wed, 10 Jun 2026 08:57:31 -0700 [thread overview]
Message-ID: <20260610155732.12686-1-linux@roeck-us.net> (raw)
Sashiko reports the following overflow problems:
In ina2xx_get_value(), the INA2XX_POWER calculation is:
val = regval * data->power_lsb_uW;
The result is returned as a signed 32-bit int. For the INA232 with a common
2mOhm shunt, power_lsb_uW becomes 40,000. When the 16-bit regval exceeds
53,687, the product exceeds INT_MAX. This overflows the 32-bit signed math,
wrapping to a negative integer and reporting erroneous negative power
readings to userspace.
For INA2XX_POWER, the upper bound is clamped:
val = clamp_val(val, 0, UINT_MAX - data->power_lsb_uW);
clamp_val() implicitly casts the upper bound to a 32-bit signed long on
32-bit platforms. This results in a negative number, meaning any valid
power limit is clamped to a negative value and ultimately programmed as 0.
Similarly, for INA2XX_SHUNT_VOLTAGE, the initial clamp uses SHRT_MAX *
shunt_div instead of division. The subsequent multiplication:
val *= data->config->shunt_div;
overflows LONG_MAX on 32-bit platforms for high inputs, wrapping to a
negative value and also programming the hardware limit to 0.
For INA2XX_BUS_VOLTAGE on parts with bus_voltage_shift > 0, the calculation
(val * 1000) << shift can exceed LONG_MAX for limits over ~134V, wrapping
to negative and setting the limit to 0.
Have ina2xx_get_value() return a long variable to improve the supported
value range on 64-bit systems and to match the type os values returned
to the hwmon core.
Clamp the result of 'regval * data->power_lsb_uW' to LONG_MAX to fix the
INA2XX_POWER calculation overflow.
Change the initial clamp for INA2XX_SHUNT_VOLTAGE to SHRT_MAX / shunt_div
to fix the shunt limit overflow.
For INA2XX_BUS_VOLTAGE, limit the initial clamp to 130V instead of 200V
to avoid the overflow.
Cc: Loic Poulain <loic.poulain@oss.qualcomm.com>
Fixes: ab7fbee452be ("hwmon: (ina2xx) Fix various overflow issues")
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
drivers/hwmon/ina2xx.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index c4742e84b999..0615666e430e 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -16,6 +16,7 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/limits.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regmap.h>
@@ -266,10 +267,10 @@ static u16 ina226_interval_to_reg(long interval)
return FIELD_PREP(INA226_AVG_RD_MASK, avg_bits);
}
-static int ina2xx_get_value(struct ina2xx_data *data, u8 reg,
- unsigned int regval)
+static long ina2xx_get_value(struct ina2xx_data *data, u8 reg,
+ unsigned int regval)
{
- int val;
+ long val;
switch (reg) {
case INA2XX_SHUNT_VOLTAGE:
@@ -283,7 +284,7 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 reg,
val = DIV_ROUND_CLOSEST(val, 1000);
break;
case INA2XX_POWER:
- val = regval * data->power_lsb_uW;
+ val = clamp_val((u64)regval * data->power_lsb_uW, 0, LONG_MAX);
break;
case INA2XX_CURRENT:
/* signed register, result in mA */
@@ -380,17 +381,17 @@ static u16 ina226_alert_to_reg(struct ina2xx_data *data, int reg, long val)
{
switch (reg) {
case INA2XX_SHUNT_VOLTAGE:
- val = clamp_val(val, 0, SHRT_MAX * data->config->shunt_div);
+ val = clamp_val(val, 0, DIV_ROUND_CLOSEST(SHRT_MAX, data->config->shunt_div));
val *= data->config->shunt_div;
val <<= data->config->shunt_voltage_shift;
return clamp_val(val, 0, SHRT_MAX);
case INA2XX_BUS_VOLTAGE:
- val = clamp_val(val, 0, 200000);
+ val = clamp_val(val, 0, 130000);
val = (val * 1000) << data->config->bus_voltage_shift;
val = DIV_ROUND_CLOSEST(val, data->config->bus_voltage_lsb);
return clamp_val(val, 0, USHRT_MAX);
case INA2XX_POWER:
- val = clamp_val(val, 0, UINT_MAX - data->power_lsb_uW);
+ val = clamp_val(val, 0, LONG_MAX - data->power_lsb_uW);
val = DIV_ROUND_CLOSEST(val, data->power_lsb_uW);
return clamp_val(val, 0, USHRT_MAX);
case INA2XX_CURRENT:
--
2.45.2
next reply other threads:[~2026-06-10 15:57 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-10 15:57 Guenter Roeck [this message]
2026-06-10 16:12 ` [PATCH] hwmon: (ina2xx) Fix overflow issues sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260610155732.12686-1-linux@roeck-us.net \
--to=linux@roeck-us.net \
--cc=linux-hwmon@vger.kernel.org \
--cc=loic.poulain@oss.qualcomm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox