public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 1/3] hwmon: (pt5161l) Fix bugs in pt5161l_read_block_data()
       [not found] <20260407173624.247803-1-sanman.pradhan@hpe.com>
@ 2026-04-07 17:37 ` Pradhan, Sanman
  2026-04-07 17:38 ` [PATCH v2 2/3] hwmon: (isl28022) Fix integer overflow in power calculation on 32-bit Pradhan, Sanman
  2026-04-07 17:38 ` [PATCH v2 3/3] hwmon: (powerz) Fix use-after-free and signal handling on USB disconnect Pradhan, Sanman
  2 siblings, 0 replies; 7+ messages in thread
From: Pradhan, Sanman @ 2026-04-07 17:37 UTC (permalink / raw)
  To: linux-hwmon@vger.kernel.org
  Cc: linux@roeck-us.net, linux@weissschuh.net, cosmo.chou@quantatw.com,
	mail@carsten-spiess.de, linux-kernel@vger.kernel.org,
	Sanman Pradhan, stable@vger.kernel.org

From: Sanman Pradhan <psanman@juniper.net>

Fix two bugs in pt5161l_read_block_data():

1. Buffer overrun: The local buffer rbuf is declared as u8 rbuf[24],
   but i2c_smbus_read_block_data() can return up to
   I2C_SMBUS_BLOCK_MAX (32) bytes. The i2c-core copies the data into
   the caller's buffer before the return value can be checked, so
   the post-read length validation does not prevent a stack overrun
   if a device returns more than 24 bytes. Resize the buffer to
   I2C_SMBUS_BLOCK_MAX.

2. Unexpected positive return on length mismatch: When all three
   retries are exhausted because the device returns data with an
   unexpected length, i2c_smbus_read_block_data() returns a positive
   byte count. The function returns this directly, and callers treat
   any non-negative return as success, processing stale or incomplete
   buffer contents. Return -EIO when retries are exhausted with a
   positive return value, preserving the negative error code on I2C
   failure.

Fixes: 1b2ca93cd0592 ("hwmon: Add driver for Astera Labs PT5161L retimer")
Cc: stable@vger.kernel.org
Signed-off-by: Sanman Pradhan <psanman@juniper.net>
---
v2:
 - Also fix unexpected positive return when retries are exhausted
   due to length mismatch

 drivers/hwmon/pt5161l.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/hwmon/pt5161l.c b/drivers/hwmon/pt5161l.c
index 20e3cfa625f1..89d4da8aa4c0 100644
--- a/drivers/hwmon/pt5161l.c
+++ b/drivers/hwmon/pt5161l.c
@@ -121,7 +121,7 @@ static int pt5161l_read_block_data(struct pt5161l_data *data, u32 address,
 	int ret, tries;
 	u8 remain_len = len;
 	u8 curr_len;
-	u8 wbuf[16], rbuf[24];
+	u8 wbuf[16], rbuf[I2C_SMBUS_BLOCK_MAX];
 	u8 cmd = 0x08; /* [7]:pec_en, [4:2]:func, [1]:start, [0]:end */
 	u8 config = 0x00; /* [6]:cfg_type, [4:1]:burst_len, [0]:address bit16 */
 
@@ -151,7 +151,7 @@ static int pt5161l_read_block_data(struct pt5161l_data *data, u32 address,
 				break;
 		}
 		if (tries >= 3)
-			return ret;
+			return ret < 0 ? ret : -EIO;
 
 		memcpy(val, rbuf, curr_len);
 		val += curr_len;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 2/3] hwmon: (isl28022) Fix integer overflow in power calculation on 32-bit
       [not found] <20260407173624.247803-1-sanman.pradhan@hpe.com>
  2026-04-07 17:37 ` [PATCH v2 1/3] hwmon: (pt5161l) Fix bugs in pt5161l_read_block_data() Pradhan, Sanman
@ 2026-04-07 17:38 ` Pradhan, Sanman
  2026-04-07 19:21   ` David Laight
  2026-04-07 17:38 ` [PATCH v2 3/3] hwmon: (powerz) Fix use-after-free and signal handling on USB disconnect Pradhan, Sanman
  2 siblings, 1 reply; 7+ messages in thread
From: Pradhan, Sanman @ 2026-04-07 17:38 UTC (permalink / raw)
  To: linux-hwmon@vger.kernel.org
  Cc: linux@roeck-us.net, linux@weissschuh.net, cosmo.chou@quantatw.com,
	mail@carsten-spiess.de, linux-kernel@vger.kernel.org,
	Sanman Pradhan, stable@vger.kernel.org

From: Sanman Pradhan <psanman@juniper.net>

isl28022_read_power() computes:

  *val = ((51200000L * ((long)data->gain)) /
          (long)data->shunt) * (long)regval;

On 32-bit platforms, 'long' is 32 bits. With gain=8 and shunt=10000
(the default configuration):

  (51200000 * 8) / 10000 = 40960
  40960 * 65535 = 2,684,313,600

This exceeds LONG_MAX (2,147,483,647), resulting in signed integer
overflow.

Additionally, dividing before multiplying by regval loses precision
unnecessarily.

Use u64 intermediates with div_u64() and multiply before dividing
to retain precision. Power is inherently non-negative, so unsigned
types are the natural fit. Clamp the result to LONG_MAX before
returning it through the hwmon callback, following the pattern used
by ina238.

Fixes: 39671a14df4f2 ("hwmon: (isl28022) new driver for ISL28022 power monitor")
Cc: stable@vger.kernel.org
Signed-off-by: Sanman Pradhan <psanman@juniper.net>
---
v2:
 - Switch from s64/div_s64() to u64/div_u64() since power is
   inherently non-negative, avoiding implicit u32-to-s32 narrowing
   of the shunt divisor

 drivers/hwmon/isl28022.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/hwmon/isl28022.c b/drivers/hwmon/isl28022.c
index c2e559dde63f..d233a7b3f327 100644
--- a/drivers/hwmon/isl28022.c
+++ b/drivers/hwmon/isl28022.c
@@ -9,6 +9,7 @@
 #include <linux/err.h>
 #include <linux/hwmon.h>
 #include <linux/i2c.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
 
@@ -178,6 +179,7 @@ static int isl28022_read_power(struct device *dev, u32 attr, long *val)
 	struct isl28022_data *data = dev_get_drvdata(dev);
 	unsigned int regval;
 	int err;
+	u64 tmp;
 
 	switch (attr) {
 	case hwmon_power_input:
@@ -185,8 +187,9 @@ static int isl28022_read_power(struct device *dev, u32 attr, long *val)
 				  ISL28022_REG_POWER, &regval);
 		if (err < 0)
 			return err;
-		*val = ((51200000L * ((long)data->gain)) /
-			(long)data->shunt) * (long)regval;
+		tmp = (u64)51200000 * data->gain * regval;
+		tmp = div_u64(tmp, data->shunt);
+		*val = clamp_val(tmp, 0, LONG_MAX);
 		break;
 	default:
 		return -EOPNOTSUPP;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 3/3] hwmon: (powerz) Fix use-after-free and signal handling on USB disconnect
       [not found] <20260407173624.247803-1-sanman.pradhan@hpe.com>
  2026-04-07 17:37 ` [PATCH v2 1/3] hwmon: (pt5161l) Fix bugs in pt5161l_read_block_data() Pradhan, Sanman
  2026-04-07 17:38 ` [PATCH v2 2/3] hwmon: (isl28022) Fix integer overflow in power calculation on 32-bit Pradhan, Sanman
@ 2026-04-07 17:38 ` Pradhan, Sanman
  2026-04-07 21:22   ` Pradhan, Sanman
  2 siblings, 1 reply; 7+ messages in thread
From: Pradhan, Sanman @ 2026-04-07 17:38 UTC (permalink / raw)
  To: linux-hwmon@vger.kernel.org
  Cc: linux@roeck-us.net, linux@weissschuh.net, cosmo.chou@quantatw.com,
	mail@carsten-spiess.de, linux-kernel@vger.kernel.org,
	Sanman Pradhan, stable@vger.kernel.org

From: Sanman Pradhan <psanman@juniper.net>

Fix several issues in the powerz driver related to USB disconnect
races and signal handling:

1. Use-after-free: When hwmon sysfs attributes are read concurrently
   with USB disconnect, powerz_read() obtains a pointer to the
   private data via usb_get_intfdata(), then powerz_disconnect() runs
   and frees the URB while powerz_read_data() may still reference it.
   Fix by:
   - Moving usb_set_intfdata() before hwmon registration so the
     disconnect handler can always find the priv pointer.
   - Clearing intfdata and NULLing the URB pointer in disconnect
     under the mutex.
   - Guarding powerz_read_data() with a !priv->urb check.

2. Signal handling: wait_for_completion_interruptible_timeout()
   returns -ERESTARTSYS on signal, 0 on timeout, or positive on
   completion. The original code tests !ret, which only catches
   timeout. On signal delivery (-ERESTARTSYS), !ret is false so the
   function skips usb_kill_urb() and falls through, accessing
   potentially stale URB data. Capture the return value and handle
   both the signal (negative) and timeout (zero) cases explicitly.

Fixes: 4381a36abdf1c ("hwmon: add POWER-Z driver")
Cc: stable@vger.kernel.org
Signed-off-by: Sanman Pradhan <psanman@juniper.net>
---
v2:
 - Also fix signal handling in wait_for_completion_interruptible_timeout();
   original code only handled timeout (ret==0) but not signals
   (ret==-ERESTARTSYS)
 - Return -ENODEV instead of -EIO for disconnected device

 drivers/hwmon/powerz.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/drivers/hwmon/powerz.c b/drivers/hwmon/powerz.c
index 4e663d5b4e33..0b38fdf42ddb 100644
--- a/drivers/hwmon/powerz.c
+++ b/drivers/hwmon/powerz.c
@@ -108,6 +108,9 @@ static int powerz_read_data(struct usb_device *udev, struct powerz_priv *priv)
 {
 	int ret;
 
+	if (!priv->urb)
+		return -ENODEV;
+
 	priv->status = -ETIMEDOUT;
 	reinit_completion(&priv->completion);
 
@@ -124,10 +127,11 @@ static int powerz_read_data(struct usb_device *udev, struct powerz_priv *priv)
 	if (ret)
 		return ret;
 
-	if (!wait_for_completion_interruptible_timeout
-	    (&priv->completion, msecs_to_jiffies(5))) {
+	ret = wait_for_completion_interruptible_timeout(&priv->completion,
+							msecs_to_jiffies(5));
+	if (ret <= 0) {
 		usb_kill_urb(priv->urb);
-		return -EIO;
+		return ret ? ret : -EIO;
 	}
 
 	if (priv->urb->actual_length < sizeof(struct powerz_sensor_data))
@@ -224,16 +228,17 @@ static int powerz_probe(struct usb_interface *intf,
 	mutex_init(&priv->mutex);
 	init_completion(&priv->completion);
 
+	usb_set_intfdata(intf, priv);
+
 	hwmon_dev =
 	    devm_hwmon_device_register_with_info(parent, DRIVER_NAME, priv,
 						 &powerz_chip_info, NULL);
 	if (IS_ERR(hwmon_dev)) {
+		usb_set_intfdata(intf, NULL);
 		usb_free_urb(priv->urb);
 		return PTR_ERR(hwmon_dev);
 	}
 
-	usb_set_intfdata(intf, priv);
-
 	return 0;
 }
 
@@ -241,9 +246,12 @@ static void powerz_disconnect(struct usb_interface *intf)
 {
 	struct powerz_priv *priv = usb_get_intfdata(intf);
 
+	usb_set_intfdata(intf, NULL);
+
 	mutex_lock(&priv->mutex);
 	usb_kill_urb(priv->urb);
 	usb_free_urb(priv->urb);
+	priv->urb = NULL;
 	mutex_unlock(&priv->mutex);
 }
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 2/3] hwmon: (isl28022) Fix integer overflow in power calculation on 32-bit
  2026-04-07 17:38 ` [PATCH v2 2/3] hwmon: (isl28022) Fix integer overflow in power calculation on 32-bit Pradhan, Sanman
@ 2026-04-07 19:21   ` David Laight
  2026-04-07 21:21     ` Pradhan, Sanman
  0 siblings, 1 reply; 7+ messages in thread
From: David Laight @ 2026-04-07 19:21 UTC (permalink / raw)
  To: Pradhan, Sanman
  Cc: linux-hwmon@vger.kernel.org, linux@roeck-us.net,
	linux@weissschuh.net, cosmo.chou@quantatw.com,
	mail@carsten-spiess.de, linux-kernel@vger.kernel.org,
	Sanman Pradhan, stable@vger.kernel.org

On Tue, 7 Apr 2026 17:38:01 +0000
"Pradhan, Sanman" <sanman.pradhan@hpe.com> wrote:

> From: Sanman Pradhan <psanman@juniper.net>
> 
> isl28022_read_power() computes:
> 
>   *val = ((51200000L * ((long)data->gain)) /
>           (long)data->shunt) * (long)regval;
> 
> On 32-bit platforms, 'long' is 32 bits. With gain=8 and shunt=10000
> (the default configuration):
> 
>   (51200000 * 8) / 10000 = 40960
>   40960 * 65535 = 2,684,313,600
> 
> This exceeds LONG_MAX (2,147,483,647), resulting in signed integer
> overflow.
> 
> Additionally, dividing before multiplying by regval loses precision
> unnecessarily.
> 
> Use u64 intermediates with div_u64() and multiply before dividing
> to retain precision. Power is inherently non-negative, so unsigned
> types are the natural fit. Clamp the result to LONG_MAX before
> returning it through the hwmon callback, following the pattern used
> by ina238.
> 
> Fixes: 39671a14df4f2 ("hwmon: (isl28022) new driver for ISL28022 power monitor")
> Cc: stable@vger.kernel.org
> Signed-off-by: Sanman Pradhan <psanman@juniper.net>
> ---
> v2:
>  - Switch from s64/div_s64() to u64/div_u64() since power is
>    inherently non-negative, avoiding implicit u32-to-s32 narrowing
>    of the shunt divisor

There is no such thing as u32-to-s32 narrowing.
Basically nothing happens to the bit pattern.
But the values are almost certainly never negative.

> 
>  drivers/hwmon/isl28022.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/hwmon/isl28022.c b/drivers/hwmon/isl28022.c
> index c2e559dde63f..d233a7b3f327 100644
> --- a/drivers/hwmon/isl28022.c
> +++ b/drivers/hwmon/isl28022.c
> @@ -9,6 +9,7 @@
>  #include <linux/err.h>
>  #include <linux/hwmon.h>
>  #include <linux/i2c.h>
> +#include <linux/math64.h>
>  #include <linux/module.h>
>  #include <linux/regmap.h>
>  
> @@ -178,6 +179,7 @@ static int isl28022_read_power(struct device *dev, u32 attr, long *val)
>  	struct isl28022_data *data = dev_get_drvdata(dev);
>  	unsigned int regval;
>  	int err;
> +	u64 tmp;
>  
>  	switch (attr) {
>  	case hwmon_power_input:
> @@ -185,8 +187,9 @@ static int isl28022_read_power(struct device *dev, u32 attr, long *val)
>  				  ISL28022_REG_POWER, &regval);
>  		if (err < 0)
>  			return err;
> -		*val = ((51200000L * ((long)data->gain)) /
> -			(long)data->shunt) * (long)regval;
> +		tmp = (u64)51200000 * data->gain * regval;
> +		tmp = div_u64(tmp, data->shunt);
> +		*val = clamp_val(tmp, 0, LONG_MAX);

Don't use clamp_val(), you don't need to and it is completely
broken by design.
Just use min().
You could just write:
	*val = min(div_u64(51200000ULL * data->gain * regval, data->shunt), LONG_MAX);

Have you checked that the multiply can't overflow 64bits?
That might be why the last multiply was done after the divide.

	David   


>  		break;
>  	default:
>  		return -EOPNOTSUPP;


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 2/3] hwmon: (isl28022) Fix integer overflow in power calculation on 32-bit
  2026-04-07 19:21   ` David Laight
@ 2026-04-07 21:21     ` Pradhan, Sanman
  0 siblings, 0 replies; 7+ messages in thread
From: Pradhan, Sanman @ 2026-04-07 21:21 UTC (permalink / raw)
  To: david.laight.linux@gmail.com
  Cc: linux-hwmon@vger.kernel.org, linux@roeck-us.net,
	linux@weissschuh.net, cosmo.chou@quantatw.com,
	mail@carsten-spiess.de, linux-kernel@vger.kernel.org,
	stable@vger.kernel.org, Sanman Pradhan

From: Sanman Pradhan <psanman@juniper.net>

Thanks for the review.

Yes, I checked this.

In this driver, gain is limited to {1, 2, 4, 8} by
isl28022_read_properties(), and regval is a 16-bit register value
(max 65535). The worst-case numerator is:

  51200000 * 8 * 65535 = 26843136000000

which is well below U64_MAX, so the multiply cannot overflow.

I'll switch to min_t(u64, ...) here to make the type handling explicit
for the u64 result of div_u64(), if that's ok, and send a v3.

Thank you.

Regards,
Sanman Pradhan

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 3/3] hwmon: (powerz) Fix use-after-free and signal handling on USB disconnect
  2026-04-07 17:38 ` [PATCH v2 3/3] hwmon: (powerz) Fix use-after-free and signal handling on USB disconnect Pradhan, Sanman
@ 2026-04-07 21:22   ` Pradhan, Sanman
  2026-04-07 23:38     ` Guenter Roeck
  0 siblings, 1 reply; 7+ messages in thread
From: Pradhan, Sanman @ 2026-04-07 21:22 UTC (permalink / raw)
  To: linux-hwmon@vger.kernel.org
  Cc: linux@roeck-us.net, linux@weissschuh.net, cosmo.chou@quantatw.com,
	mail@carsten-spiess.de, linux-kernel@vger.kernel.org,
	stable@vger.kernel.org, Sanman Pradhan

From: Sanman Pradhan <psanman@juniper.net>

Good observation in the AI feedback, this would be a pre-existing issue
in the driver, as this patch does not change the struct layout or DMA
buffer usage.

I would prefer to keep this patch focused on the disconnect lifetime and
signal-handling fixes. Addressing potential cacheline sharing for the DMA
buffer likely requires a more deliberate change to the struct layout or
allocation strategy, so it would be better handled in a separate follow-up.

Happy to take a look at that separately if needed.

Thank you.

Regards,
Sanman Pradhan

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 3/3] hwmon: (powerz) Fix use-after-free and signal handling on USB disconnect
  2026-04-07 21:22   ` Pradhan, Sanman
@ 2026-04-07 23:38     ` Guenter Roeck
  0 siblings, 0 replies; 7+ messages in thread
From: Guenter Roeck @ 2026-04-07 23:38 UTC (permalink / raw)
  To: Pradhan, Sanman, linux-hwmon@vger.kernel.org
  Cc: linux@weissschuh.net, cosmo.chou@quantatw.com,
	mail@carsten-spiess.de, linux-kernel@vger.kernel.org,
	stable@vger.kernel.org, Sanman Pradhan

On 4/7/26 14:22, Pradhan, Sanman wrote:
> From: Sanman Pradhan <psanman@juniper.net>
> 
> Good observation in the AI feedback, this would be a pre-existing issue
> in the driver, as this patch does not change the struct layout or DMA
> buffer usage.
> 
> I would prefer to keep this patch focused on the disconnect lifetime and
> signal-handling fixes. Addressing potential cacheline sharing for the DMA
> buffer likely requires a more deliberate change to the struct layout or
> allocation strategy, so it would be better handled in a separate follow-up.
> 
> Happy to take a look at that separately if needed.
> 

Makes sense.

Thanks,
Guenter


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-04-07 23:38 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20260407173624.247803-1-sanman.pradhan@hpe.com>
2026-04-07 17:37 ` [PATCH v2 1/3] hwmon: (pt5161l) Fix bugs in pt5161l_read_block_data() Pradhan, Sanman
2026-04-07 17:38 ` [PATCH v2 2/3] hwmon: (isl28022) Fix integer overflow in power calculation on 32-bit Pradhan, Sanman
2026-04-07 19:21   ` David Laight
2026-04-07 21:21     ` Pradhan, Sanman
2026-04-07 17:38 ` [PATCH v2 3/3] hwmon: (powerz) Fix use-after-free and signal handling on USB disconnect Pradhan, Sanman
2026-04-07 21:22   ` Pradhan, Sanman
2026-04-07 23:38     ` Guenter Roeck

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox