Linux Hardware Monitor development
 help / color / mirror / Atom feed
From: Guenter Roeck <linux@roeck-us.net>
To: Hardware Monitoring <linux-hwmon@vger.kernel.org>
Cc: Tzung-Bi Shih <tzungbi@kernel.org>, Guenter Roeck <linux@roeck-us.net>
Subject: [PATCH v2 07/14] hwmon: (ina2xx) Fix various overflow issues
Date: Thu, 29 Aug 2024 18:05:47 -0700	[thread overview]
Message-ID: <20240830010554.1462861-8-linux@roeck-us.net> (raw)
In-Reply-To: <20240830010554.1462861-1-linux@roeck-us.net>

Module tests show various overflow problems when writing limits
and other attributes.

in0_crit: Suspected overflow: [max=82, read 0, written 2147483648]
in0_lcrit: Suspected overflow: [max=82, read 0, written 2147483648]
in1_crit: Suspected overflow: [max=40959, read 0, written 2147483647]
in1_lcrit: Suspected overflow: [max=40959, read 0, written 2147483647]
power1_crit: Suspected overflow: [max=134218750, read 0, written 2147483648]
update_interval: Suspected overflow: [max=2253, read 2, written 2147483647]

Implement missing clamping on attribute write operations to avoid those
problems.

While at it, check in the probe function if the shunt resistor value
passed from devicetree is valid, and bail out if it isn't. Also limit
mutex use to the code calling ina2xx_set_shunt() since it isn't needed
when called from the probe function.

Reviewed-by: Tzung-Bi Shih <tzungbi@kernel.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
v2: Dropped unrelated cosmetic change
    Added Reviewed-by: tag

 drivers/hwmon/ina2xx.c | 32 ++++++++++++++++++++------------
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index db6432523e59..2aea461b8c6d 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -193,10 +193,16 @@ static int ina226_reg_to_interval(u16 config)
  * Return the new, shifted AVG field value of CONFIG register,
  * to use with regmap_update_bits
  */
-static u16 ina226_interval_to_reg(int interval)
+static u16 ina226_interval_to_reg(unsigned long interval)
 {
 	int avg, avg_bits;
 
+	/*
+	 * The maximum supported interval is 1,024 * (2 * 8.244ms) ~= 16.8s.
+	 * Clamp to 32 seconds before calculations to avoid overflows.
+	 */
+	interval = clamp_val(interval, 0, 32000);
+
 	avg = DIV_ROUND_CLOSEST(interval * 1000,
 				INA226_TOTAL_CONV_TIME_DEFAULT);
 	avg_bits = find_closest(avg, ina226_avg_tab,
@@ -371,19 +377,22 @@ static int ina226_reg_to_alert(struct ina2xx_data *data, u32 mask, u16 regval)
  * Turns alert limit values into register values.
  * Opposite of the formula in ina2xx_get_value().
  */
-static u16 ina226_alert_to_reg(struct ina2xx_data *data, u32 mask, int val)
+static u16 ina226_alert_to_reg(struct ina2xx_data *data, u32 mask, unsigned long val)
 {
 	switch (mask) {
 	case INA226_SHUNT_OVER_VOLTAGE_MASK:
 	case INA226_SHUNT_UNDER_VOLTAGE_MASK:
+		val = clamp_val(val, 0, SHRT_MAX * data->config->shunt_div);
 		val *= data->config->shunt_div;
-		return clamp_val(val, SHRT_MIN, SHRT_MAX);
+		return clamp_val(val, 0, SHRT_MAX);
 	case INA226_BUS_OVER_VOLTAGE_MASK:
 	case INA226_BUS_UNDER_VOLTAGE_MASK:
+		val = clamp_val(val, 0, 200000);
 		val = (val * 1000) << data->config->bus_voltage_shift;
 		val = DIV_ROUND_CLOSEST(val, data->config->bus_voltage_lsb);
-		return clamp_val(val, 0, SHRT_MAX);
+		return clamp_val(val, 0, USHRT_MAX);
 	case INA226_POWER_OVER_LIMIT_MASK:
+		val = clamp_val(val, 0, UINT_MAX - data->power_lsb_uW);
 		val = DIV_ROUND_CLOSEST(val, data->power_lsb_uW);
 		return clamp_val(val, 0, USHRT_MAX);
 	default:
@@ -490,19 +499,17 @@ static ssize_t ina226_alarm_show(struct device *dev,
  * to shunt_voltage_lsb = 1 / shunt_div multiplied by 10^9 in order
  * to keep the scale.
  */
-static int ina2xx_set_shunt(struct ina2xx_data *data, long val)
+static int ina2xx_set_shunt(struct ina2xx_data *data, unsigned long val)
 {
 	unsigned int dividend = DIV_ROUND_CLOSEST(1000000000,
 						  data->config->shunt_div);
-	if (val <= 0 || val > dividend)
+	if (!val || val > dividend)
 		return -EINVAL;
 
-	mutex_lock(&data->config_lock);
 	data->rshunt = val;
 	data->current_lsb_uA = DIV_ROUND_CLOSEST(dividend, val);
 	data->power_lsb_uW = data->config->power_lsb_factor *
 			     data->current_lsb_uA;
-	mutex_unlock(&data->config_lock);
 
 	return 0;
 }
@@ -527,7 +534,9 @@ static ssize_t ina2xx_shunt_store(struct device *dev,
 	if (status < 0)
 		return status;
 
+	mutex_lock(&data->config_lock);
 	status = ina2xx_set_shunt(data, val);
+	mutex_unlock(&data->config_lock);
 	if (status < 0)
 		return status;
 	return count;
@@ -545,9 +554,6 @@ static ssize_t ina226_interval_store(struct device *dev,
 	if (status < 0)
 		return status;
 
-	if (val > INT_MAX || val == 0)
-		return -EINVAL;
-
 	status = regmap_update_bits(data->regmap, INA2XX_CONFIG,
 				    INA226_AVG_RD_MASK,
 				    ina226_interval_to_reg(val));
@@ -667,7 +673,9 @@ static int ina2xx_probe(struct i2c_client *client)
 	if (device_property_read_u32(dev, "shunt-resistor", &val) < 0)
 		val = INA2XX_RSHUNT_DEFAULT;
 
-	ina2xx_set_shunt(data, val);
+	ret = ina2xx_set_shunt(data, val);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Invalid shunt resistor value\n");
 
 	data->regmap = devm_regmap_init_i2c(client, &ina2xx_regmap_config);
 	if (IS_ERR(data->regmap)) {
-- 
2.45.2


  parent reply	other threads:[~2024-08-30  1:06 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-30  1:05 [PATCH v2 00/14] hwmon: (ina2xx) Cleanup and convert to use with_info API Guenter Roeck
2024-08-30  1:05 ` [PATCH v2 01/14] hwmon: (ina2xx) Reorder include files to alphabetic order Guenter Roeck
2024-08-30  1:05 ` [PATCH v2 02/14] hwmon: (ina2xx) Replace platform data with device properties Guenter Roeck
2024-08-30  1:05 ` [PATCH v2 03/14] hwmon: (ina2xx) Use bit operations Guenter Roeck
2024-08-30  1:05 ` [PATCH v2 04/14] hwmon: (ina2xx) Mark regmap_config as const Guenter Roeck
2024-08-30 12:28   ` Tzung-Bi Shih
2024-08-30  1:05 ` [PATCH v2 05/14] hwmon: (ina2xx) Use local regmap pointer if used more than once Guenter Roeck
2024-08-30  1:05 ` [PATCH v2 06/14] hwmon: (ina2xx) Re-initialize chip using regmap functions Guenter Roeck
2024-08-30 12:29   ` Tzung-Bi Shih
2024-08-30  1:05 ` Guenter Roeck [this message]
2024-08-30  1:05 ` [PATCH v2 08/14] hwmon: (ina2xx) Consolidate chip initialization code Guenter Roeck
2024-08-30 12:29   ` Tzung-Bi Shih
2024-08-30  1:05 ` [PATCH v2 09/14] hwmon: (ina2xx) Set alert latch Guenter Roeck
2024-08-30 12:29   ` Tzung-Bi Shih
2024-08-30  1:05 ` [PATCH v2 10/14] hwmon: (ina2xx) Move ina2xx_get_value() Guenter Roeck
2024-08-30  1:05 ` [PATCH v2 11/14] hwmon: (ina2xx) Convert to use with_info hwmon API Guenter Roeck
2024-08-30 12:30   ` Tzung-Bi Shih
2024-08-30 15:32     ` Guenter Roeck
2024-08-30  1:05 ` [PATCH v2 12/14] hwmon: (ina2xx) Pass register to alert limit write functions Guenter Roeck
2024-08-30 12:30   ` Tzung-Bi Shih
2024-08-30  1:05 ` [PATCH v2 13/14] hwmon: (ina2xx) Add support for current limits Guenter Roeck
2024-08-30 12:30   ` Tzung-Bi Shih
2024-08-30  1:05 ` [PATCH v2 14/14] hwmon: (ina2xx) Use shunt voltage to calculate current Guenter Roeck
2024-08-30 12:30   ` Tzung-Bi Shih

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=20240830010554.1462861-8-linux@roeck-us.net \
    --to=linux@roeck-us.net \
    --cc=linux-hwmon@vger.kernel.org \
    --cc=tzungbi@kernel.org \
    /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