Skip to content

Commit 9671081

Browse files
2045castorgroeck
authored andcommitted
hwmon: (vt1211) Convert macros to functions to avoid TOCTOU
The macros IN_FROM_REG, TEMP_FROM_REG, and RPM_FROM_REG evaluate their arguments multiple times. These macros are used in lockless show functions involving shared driver data, leading to Time-of-Check to Time-of-Use race conditions. For example, RPM_FROM_REG checks if a value is 0 or 255, and then uses it in a division. If the value is modified by another thread to 0 after the check but before the division, it causes a divide-by-zero error. Convert these macros to static functions. This guarantees that arguments are evaluated only once (pass-by-value), fixing the race conditions. Adhere to the principle of minimal changes by only converting the specific macros involved in these lockless contexts. Link: https://lore.kernel.org/all/CALbr=LYJ_ehtp53HXEVkSpYoub+XYSTU8Rg=o1xxMJ8=5z8B-g@mail.gmail.com/ Signed-off-by: Gui-Dong Han <hanguidong02@gmail.com> Link: https://lore.kernel.org/r/20251120041331.1917570-1-hanguidong02@gmail.com Signed-off-by: Guenter Roeck <linux@roeck-us.net>
1 parent d56933e commit 9671081

1 file changed

Lines changed: 35 additions & 18 deletions

File tree

drivers/hwmon/vt1211.c

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,15 @@ struct vt1211_data {
142142
* in5 (ix = 5) is special. It's the internal 3.3V so it's scaled in the
143143
* driver according to the VT1211 BIOS porting guide
144144
*/
145-
#define IN_FROM_REG(ix, reg) ((reg) < 3 ? 0 : (ix) == 5 ? \
146-
(((reg) - 3) * 15882 + 479) / 958 : \
147-
(((reg) - 3) * 10000 + 479) / 958)
145+
static int in_from_reg(int ix, int reg)
146+
{
147+
if (reg < 3)
148+
return 0;
149+
if (ix == 5)
150+
return ((reg - 3) * 15882 + 479) / 958;
151+
return ((reg - 3) * 10000 + 479) / 958;
152+
}
153+
148154
#define IN_TO_REG(ix, val) (clamp_val((ix) == 5 ? \
149155
((val) * 958 + 7941) / 15882 + 3 : \
150156
((val) * 958 + 5000) / 10000 + 3, 0, 255))
@@ -156,19 +162,30 @@ struct vt1211_data {
156162
* temp3-7 are thermistor based so the driver returns the voltage measured at
157163
* the pin (range 0V - 2.2V).
158164
*/
159-
#define TEMP_FROM_REG(ix, reg) ((ix) == 0 ? (reg) * 1000 : \
160-
(ix) == 1 ? (reg) < 51 ? 0 : \
161-
((reg) - 51) * 1000 : \
162-
((253 - (reg)) * 2200 + 105) / 210)
165+
static int temp_from_reg(int ix, int reg)
166+
{
167+
if (ix == 0)
168+
return reg * 1000;
169+
if (ix == 1)
170+
return reg < 51 ? 0 : (reg - 51) * 1000;
171+
return ((253 - reg) * 2200 + 105) / 210;
172+
}
173+
163174
#define TEMP_TO_REG(ix, val) clamp_val( \
164175
((ix) == 0 ? ((val) + 500) / 1000 : \
165176
(ix) == 1 ? ((val) + 500) / 1000 + 51 : \
166177
253 - ((val) * 210 + 1100) / 2200), 0, 255)
167178

168179
#define DIV_FROM_REG(reg) (1 << (reg))
169180

170-
#define RPM_FROM_REG(reg, div) (((reg) == 0) || ((reg) == 255) ? 0 : \
171-
1310720 / (reg) / DIV_FROM_REG(div))
181+
static int rpm_from_reg(int reg, int div)
182+
{
183+
if (reg == 0 || reg == 255)
184+
return 0;
185+
186+
return 1310720 / reg / DIV_FROM_REG(div);
187+
}
188+
172189
#define RPM_TO_REG(val, div) ((val) == 0 ? 255 : \
173190
clamp_val((1310720 / (val) / \
174191
DIV_FROM_REG(div)), 1, 254))
@@ -343,13 +360,13 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
343360

344361
switch (fn) {
345362
case SHOW_IN_INPUT:
346-
res = IN_FROM_REG(ix, data->in[ix]);
363+
res = in_from_reg(ix, data->in[ix]);
347364
break;
348365
case SHOW_SET_IN_MIN:
349-
res = IN_FROM_REG(ix, data->in_min[ix]);
366+
res = in_from_reg(ix, data->in_min[ix]);
350367
break;
351368
case SHOW_SET_IN_MAX:
352-
res = IN_FROM_REG(ix, data->in_max[ix]);
369+
res = in_from_reg(ix, data->in_max[ix]);
353370
break;
354371
case SHOW_IN_ALARM:
355372
res = (data->alarms >> bitalarmin[ix]) & 1;
@@ -417,13 +434,13 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
417434

418435
switch (fn) {
419436
case SHOW_TEMP_INPUT:
420-
res = TEMP_FROM_REG(ix, data->temp[ix]);
437+
res = temp_from_reg(ix, data->temp[ix]);
421438
break;
422439
case SHOW_SET_TEMP_MAX:
423-
res = TEMP_FROM_REG(ix, data->temp_max[ix]);
440+
res = temp_from_reg(ix, data->temp_max[ix]);
424441
break;
425442
case SHOW_SET_TEMP_MAX_HYST:
426-
res = TEMP_FROM_REG(ix, data->temp_hyst[ix]);
443+
res = temp_from_reg(ix, data->temp_hyst[ix]);
427444
break;
428445
case SHOW_TEMP_ALARM:
429446
res = (data->alarms >> bitalarmtemp[ix]) & 1;
@@ -493,10 +510,10 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
493510

494511
switch (fn) {
495512
case SHOW_FAN_INPUT:
496-
res = RPM_FROM_REG(data->fan[ix], data->fan_div[ix]);
513+
res = rpm_from_reg(data->fan[ix], data->fan_div[ix]);
497514
break;
498515
case SHOW_SET_FAN_MIN:
499-
res = RPM_FROM_REG(data->fan_min[ix], data->fan_div[ix]);
516+
res = rpm_from_reg(data->fan_min[ix], data->fan_div[ix]);
500517
break;
501518
case SHOW_SET_FAN_DIV:
502519
res = DIV_FROM_REG(data->fan_div[ix]);
@@ -751,7 +768,7 @@ static ssize_t show_pwm_auto_point_temp(struct device *dev,
751768
int ix = sensor_attr_2->index;
752769
int ap = sensor_attr_2->nr;
753770

754-
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->pwm_ctl[ix] & 7,
771+
return sprintf(buf, "%d\n", temp_from_reg(data->pwm_ctl[ix] & 7,
755772
data->pwm_auto_temp[ap]));
756773
}
757774

0 commit comments

Comments
 (0)