]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
hwmon: (tmp401) fix overflow caused by default conversion rate value
authorAlexey Simakov <bigalex934@gmail.com>
Thu, 11 Dec 2025 16:43:43 +0000 (19:43 +0300)
committerGuenter Roeck <linux@roeck-us.net>
Sun, 14 Dec 2025 17:52:28 +0000 (09:52 -0800)
The driver computes conversion intervals using the formula:

    interval = (1 << (7 - rate)) * 125ms

where 'rate' is the sensor's conversion rate register value. According to
the datasheet, the power-on reset value of this register is 0x8, which
could be assigned to the register, after handling i2c general call.
Using this default value causes a result greater than the bit width of
left operand and an undefined behaviour in the calculation above, since
shifting by values larger than the bit width is undefined behaviour as
per C language standard.

Limit the maximum usable 'rate' value to 7 to prevent undefined
behaviour in calculations.

Found by Linux Verification Center (linuxtesting.org) with Svace.

Note (groeck):
    This does not matter in practice unless someone overwrites the chip
    configuration from outside the driver while the driver is loaded.
    The conversion time register is initialized with a value of 5 (500ms)
    when the driver is loaded, and the driver never writes a bad value.

Fixes: ca53e7640de7 ("hwmon: (tmp401) Convert to _info API")
Signed-off-by: Alexey Simakov <bigalex934@gmail.com>
Link: https://lore.kernel.org/r/20251211164342.6291-1-bigalex934@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
drivers/hwmon/tmp401.c

index fbaa34973694f24a32b4deb7a4fa1e7ea57b1c3b..07f596581c6eb70d424ed777d5a526478e4a3211 100644 (file)
@@ -397,7 +397,7 @@ static int tmp401_chip_read(struct device *dev, u32 attr, int channel, long *val
                ret = regmap_read(data->regmap, TMP401_CONVERSION_RATE, &regval);
                if (ret < 0)
                        return ret;
-               *val = (1 << (7 - regval)) * 125;
+               *val = (1 << (7 - min(regval, 7))) * 125;
                break;
        case hwmon_chip_temp_reset_history:
                *val = 0;