hwmon: (adt7470) Fix divide-by-zero TOCTOU crash in fan speed read

If the fan data becomes 0 between the FAN_DATA_VALID() check and the
FAN_PERIOD_TO_RPM() conversion, it will result in a divide-by-zero crash
due to a race with a concurrent update of the cached fan value.

Fix a TOCTOU issue by reading fan data once.

Reported-by: sashiko-bot@kernel.org
Closes: https://lore.kernel.org/r/20260727034929.E29B71F000E9@smtp.kernel.org/
Fixes: fc958a61ff ("hwmon: (adt7470) Convert to devm_hwmon_device_register_with_info API")
Signed-off-by: Luiz Angelo Daros de Luca <luizluca@gmail.com>
Link: https://lore.kernel.org/r/20260727-adt7470_fixes-v2-7-598e38a46ba6@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
Luiz Angelo Daros de Luca 2026-07-27 21:22:23 -03:00 committed by Guenter Roeck
parent 60677cd4c2
commit 1b46fe9dc8

View File

@ -660,36 +660,33 @@ static ssize_t alarm_mask_store(struct device *dev,
static int adt7470_fan_read(struct device *dev, u32 attr, int channel, long *val)
{
struct adt7470_data *data = adt7470_update_device(dev);
u16 fan_data;
if (IS_ERR(data))
return PTR_ERR(data);
switch (attr) {
case hwmon_fan_input:
if (FAN_DATA_VALID(data->fan[channel]))
*val = FAN_PERIOD_TO_RPM(data->fan[channel]);
else
*val = 0;
fan_data = READ_ONCE(data->fan[channel]);
break;
case hwmon_fan_min:
if (FAN_DATA_VALID(data->fan_min[channel]))
*val = FAN_PERIOD_TO_RPM(data->fan_min[channel]);
else
*val = 0;
fan_data = READ_ONCE(data->fan_min[channel]);
break;
case hwmon_fan_max:
if (FAN_DATA_VALID(data->fan_max[channel]))
*val = FAN_PERIOD_TO_RPM(data->fan_max[channel]);
else
*val = 0;
fan_data = READ_ONCE(data->fan_max[channel]);
break;
case hwmon_fan_alarm:
*val = !!(data->alarm & FAN_ALARM_BIT(channel));
break;
return 0;
default:
return -EOPNOTSUPP;
}
if (FAN_DATA_VALID(fan_data))
*val = FAN_PERIOD_TO_RPM(fan_data);
else
*val = 0;
return 0;
}