[PATCH 6.12 082/337] hwmon: (adt7470) Fix divide-by-zero TOCTOU crash in fan speed read
Greg Kroah-Hartman <[email protected]>
| Newsgroups | dev.linux.lists.patches,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
6.12-stable review patch. If anyone has any objections, please let me know. ------------------ From: Luiz Angelo Daros de Luca <[email protected]> [ Upstream commit 1b46fe9dc8f8de59310f37e6c5e5c0e05ded46c3 ] 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: [email protected] Closes: https://lore.kernel.org/r/[email protected]/ Fixes: fc958a61ff6d ("hwmon: (adt7470) Convert to devm_hwmon_device_register_with_info API") Signed-off-by: Luiz Angelo Daros de Luca <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Guenter Roeck <[email protected]> Signed-off-by: Sasha Levin <[email protected]> --- drivers/hwmon/adt7470.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index 43c0130342622..3a2d408a45be8 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -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; } -- 2.53.0