Skip to content

Commit b9b4590

Browse files
2045castorUlrich Hecht
authored andcommitted
hwmon: (w83791d) Convert macros to functions to avoid TOCTOU
commit 670d7ef945d3a84683594429aea6ab2cdfa5ceb4 upstream. The macro FAN_FROM_REG evaluates its arguments multiple times. When used in lockless contexts involving shared driver data, this leads to Time-of-Check to Time-of-Use (TOCTOU) race conditions, potentially causing divide-by-zero errors. Convert the macro to a static function. This guarantees that arguments are evaluated only once (pass-by-value), preventing the race conditions. Additionally, in store_fan_div, move the calculation of the minimum limit inside the update lock. This ensures that the read-modify-write sequence operates on consistent data. Adhere to the principle of minimal changes by only converting macros that evaluate arguments multiple times and are used in lockless contexts. Link: https://lore.kernel.org/all/CALbr=LYJ_ehtp53HXEVkSpYoub+XYSTU8Rg=o1xxMJ8=5z8B-g@mail.gmail.com/ Fixes: 9873964 ("[PATCH] HWMON: w83791d: New hardware monitoring driver for the Winbond W83791D") Cc: stable@vger.kernel.org Signed-off-by: Gui-Dong Han <hanguidong02@gmail.com> Link: https://lore.kernel.org/r/20251202180105.12842-1-hanguidong02@gmail.com Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Ulrich Hecht <uli@kernel.org>
1 parent 834a778 commit b9b4590

1 file changed

Lines changed: 11 additions & 6 deletions

File tree

drivers/hwmon/w83791d.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,14 @@ static u8 fan_to_reg(long rpm, int div)
231231
return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
232232
}
233233

234-
#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \
235-
((val) == 255 ? 0 : \
236-
1350000 / ((val) * (div))))
234+
static int fan_from_reg(int val, int div)
235+
{
236+
if (val == 0)
237+
return -1;
238+
if (val == 255)
239+
return 0;
240+
return 1350000 / (val * div);
241+
}
237242

238243
/* for temp1 which is 8-bit resolution, LSB = 1 degree Celsius */
239244
#define TEMP1_FROM_REG(val) ((val) * 1000)
@@ -538,7 +543,7 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
538543
struct w83791d_data *data = w83791d_update_device(dev); \
539544
int nr = sensor_attr->index; \
540545
return sprintf(buf, "%d\n", \
541-
FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \
546+
fan_from_reg(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \
542547
}
543548

544549
show_fan_reg(fan);
@@ -602,10 +607,10 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr,
602607
if (err)
603608
return err;
604609

610+
mutex_lock(&data->update_lock);
605611
/* Save fan_min */
606-
min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
612+
min = fan_from_reg(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
607613

608-
mutex_lock(&data->update_lock);
609614
data->fan_div[nr] = div_to_reg(nr, val);
610615

611616
switch (nr) {

0 commit comments

Comments
 (0)