Skip to content

Commit dff2055

Browse files
2045geminigroeck
authored andcommitted
hwmon: (lm63) Add locking to avoid TOCTOU
The functions show_fan(), show_pwm1(), show_temp11(), temp2_crit_hyst_show(), and show_lut_temp_hyst() access shared cached data without holding the update lock. This can cause TOCTOU races if the cached values change between the checks and the later calculations. Those cached values are updated in lm63_update_device(). In the general case, the affected functions combine multiple cached values without locking and can therefore observe a mixed old/new snapshot. In addition, show_fan() reads data->fan[nr] locklessly while lm63_update_device() updates data->fan[0] in two steps, which can expose an intermediate torn value and potentially trigger a divide-by-zero error. This means that converting the macro to a function is not sufficient to fix show_fan(). Hold the update lock across the whole read and calculation sequence so that the values remain stable. Check the other functions in the driver as well. Keep them unchanged because they either do not access shared cached values multiple times or already do so under lock. Link: https://lore.kernel.org/linux-hwmon/CALbr=LYJ_ehtp53HXEVkSpYoub+XYSTU8Rg=o1xxMJ8=5z8B-g@mail.gmail.com/ Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Fixes: e872c91 ("hwmon: (lm63) Add support for unsigned upper temperature limits") Fixes: d216f68 ("hwmon: (lm63) Expose automatic fan speed control lookup table") Signed-off-by: Gui-Dong Han <hanguidong02@gmail.com> Link: https://lore.kernel.org/r/20260416135703.53262-1-hanguidong02@gmail.com [groeck: Use lm63_update_device() to get driver data in temp2_crit_hyst_store] Signed-off-by: Guenter Roeck <linux@roeck-us.net>
1 parent 1746064 commit dff2055

1 file changed

Lines changed: 30 additions & 9 deletions

File tree

drivers/hwmon/lm63.c

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,13 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
333333
{
334334
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
335335
struct lm63_data *data = lm63_update_device(dev);
336-
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index]));
336+
int fan;
337+
338+
mutex_lock(&data->update_lock);
339+
fan = FAN_FROM_REG(data->fan[attr->index]);
340+
mutex_unlock(&data->update_lock);
341+
342+
return sprintf(buf, "%d\n", fan);
337343
}
338344

339345
static ssize_t set_fan(struct device *dev, struct device_attribute *dummy,
@@ -366,12 +372,14 @@ static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr,
366372
int nr = attr->index;
367373
int pwm;
368374

375+
mutex_lock(&data->update_lock);
369376
if (data->pwm_highres)
370377
pwm = data->pwm1[nr];
371378
else
372379
pwm = data->pwm1[nr] >= 2 * data->pwm1_freq ?
373380
255 : (data->pwm1[nr] * 255 + data->pwm1_freq) /
374381
(2 * data->pwm1_freq);
382+
mutex_unlock(&data->update_lock);
375383

376384
return sprintf(buf, "%d\n", pwm);
377385
}
@@ -529,6 +537,7 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
529537
int nr = attr->index;
530538
int temp;
531539

540+
mutex_lock(&data->update_lock);
532541
if (!nr) {
533542
/*
534543
* Use unsigned temperature unless its value is zero.
@@ -544,7 +553,10 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
544553
else
545554
temp = TEMP11_FROM_REG(data->temp11[nr]);
546555
}
547-
return sprintf(buf, "%d\n", temp + data->temp2_offset);
556+
temp += data->temp2_offset;
557+
mutex_unlock(&data->update_lock);
558+
559+
return sprintf(buf, "%d\n", temp);
548560
}
549561

550562
static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
@@ -592,20 +604,29 @@ static ssize_t temp2_crit_hyst_show(struct device *dev,
592604
struct device_attribute *dummy, char *buf)
593605
{
594606
struct lm63_data *data = lm63_update_device(dev);
595-
return sprintf(buf, "%d\n", temp8_from_reg(data, 2)
596-
+ data->temp2_offset
597-
- TEMP8_FROM_REG(data->temp2_crit_hyst));
607+
int temp;
608+
609+
mutex_lock(&data->update_lock);
610+
temp = temp8_from_reg(data, 2) + data->temp2_offset
611+
- TEMP8_FROM_REG(data->temp2_crit_hyst);
612+
mutex_unlock(&data->update_lock);
613+
614+
return sprintf(buf, "%d\n", temp);
598615
}
599616

600617
static ssize_t show_lut_temp_hyst(struct device *dev,
601618
struct device_attribute *devattr, char *buf)
602619
{
603620
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
604621
struct lm63_data *data = lm63_update_device(dev);
622+
int temp;
605623

606-
return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index)
607-
+ data->temp2_offset
608-
- TEMP8_FROM_REG(data->lut_temp_hyst));
624+
mutex_lock(&data->update_lock);
625+
temp = lut_temp_from_reg(data, attr->index) + data->temp2_offset
626+
- TEMP8_FROM_REG(data->lut_temp_hyst);
627+
mutex_unlock(&data->update_lock);
628+
629+
return sprintf(buf, "%d\n", temp);
609630
}
610631

611632
/*
@@ -616,7 +637,7 @@ static ssize_t temp2_crit_hyst_store(struct device *dev,
616637
struct device_attribute *dummy,
617638
const char *buf, size_t count)
618639
{
619-
struct lm63_data *data = dev_get_drvdata(dev);
640+
struct lm63_data *data = lm63_update_device(dev);
620641
struct i2c_client *client = data->client;
621642
long val;
622643
int err;

0 commit comments

Comments
 (0)