From nobody Tue Dec 2 02:05:28 2025 Received: from mail-pf1-f179.google.com (mail-pf1-f179.google.com [209.85.210.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A47DD2D7817 for ; Thu, 20 Nov 2025 04:13:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763612027; cv=none; b=FCoEL04qagyT3VUNI5lxbJ6+cnmTuPfHR2X5ifZS0vD7XOf3R6lkZgGc6wiL+MJY/r+0K0yZ2nhQFpeASuQzxgp2E/Vf/KsBJbFX4skGMWMSBBs1/QBYwpdCjr+jv3ycMguVuIC7YsCY4eVmBp5YgyH9t3OLhuYusAaV4Kb0+L8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763612027; c=relaxed/simple; bh=fFTvaxCHkwe3TWNImhqvxkbkcAX5duXv6fsZu8qXEJ4=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=BA5gVy3r7ePA6qbbxEnJaWctIlRA8KEUfb/AayMVW3GV5o9oCseHmoYtDiI1K4N8A+9rdo6CVWe1TpD8p1N/jk9Schp9enRpM/tkOkKZE4RVQR1drNQDp4+L8BCFyvoyfIG1hWMXOL5i8wlYWTLtIWpiOnHjGpulxzPSk9J4/fE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=KOKaiRLU; arc=none smtp.client-ip=209.85.210.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="KOKaiRLU" Received: by mail-pf1-f179.google.com with SMTP id d2e1a72fcca58-7a9cdf62d31so522082b3a.3 for ; Wed, 19 Nov 2025 20:13:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1763612025; x=1764216825; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=7Pb/ET6Ol1KEYZrGqc/HU9xA8yZrF8vyNBLl5qu1OoU=; b=KOKaiRLUaG8Gw4TInrIlLOszNrX+CRsUKA0s9JBWRW+tflhDkqPI+Mb+NaLvMo+H0B Lr0sO1X7NfzeZLkc7U2Txc/aYWKSuT3GgEFat1MTSiHgBziVknwpqzc3kwtRfw1xlp+q wV8a3Z0K8G5F4rU7zeqhHjcR8sYNupVfmYaZpLE699bpz8B5tpQhWLncVIKHKi3tMZM0 DEevjVC86Rg4d7GXIrCWD7OLb6LLTbVpmYergubS83XgLpGE42V6PnCr3hTDCsCZnfo1 SRYNOEnxVEKYwP6EdZtKIb+A4s1Yyt0Zs+lULIWbMXjNFpbSkuEAitFJhEul1F6oB/Am pHug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763612025; x=1764216825; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=7Pb/ET6Ol1KEYZrGqc/HU9xA8yZrF8vyNBLl5qu1OoU=; b=m77iOqvDmZr3KlCHAG9BMwrkPZYmtZjvR7z0239jTdqepfoiqAbubJtpCUmM7sIwex bPsawoywT0Iuxb0Lu2P5626BG65M28nsbxAtXXsnInd/RjVqlsTGXOFoe0NuHgv4v/Bd xVg10/1hvepQLKHVguqxUT7naONCc2LHs5FMxnC9/NnQYy5CmaEqubU7xRe/TXHwKxWR KCeJ3lhWT1/yOL9m3U5BZhZe69LELncvIDqanARaulJafnasSDjhxUZaPcP4LI//b0js hurZkFi5i36n2p64Z2lESqIAqspVTcERRhRqf2s7tfz1FXpQZRYbTDtvB5LlHmxgTiZL U43A== X-Forwarded-Encrypted: i=1; AJvYcCX9ZZBNym07h7C+PoHsI8trQUJ766/aP5vF0PpU6t+GNg2VUYwHqaVIPRYfI/hpa7f7R9DlfEmdZpwxQEU=@vger.kernel.org X-Gm-Message-State: AOJu0YweQsXE4DDcYQzGysGkS+va+jDAF9W9wYGTlGvZY9zZdS9VGHTj nkRkz+IJldtkI5zcMtPNw+8vE/N7uH3dn8T3OxAW6/VWXWy+fOE23unT X-Gm-Gg: ASbGnctrzNSDR8c3kiecGLjoUYu1Gb9Xad77nmsiQswOf+qSJTnFs2vzC8L4+tpt74e bPC0Vve4ztgHVnGXcbVnWMB0L4SSf3qsIhIA57EzBWYisxZ/mlxPp6RMjRLkYVS+a6I30ENu5QU SbWqVWrQ0nqyIpfg7HnRN03iV2qdu4zy3ol4bk/PpaAWsHpoMM8WUDkHu+stTiGo3WLWZXj0IBF Mipe8WD+b/tI94iQkvrKS0V++FfdpbEvWwh+N/mmDg39qXj7uJwr+3HLCYBjaVVrZ1X2TOftP5q 1i5Ntlg8+tbj5Of3+o7ZefYvzCWt/f2GTt8B6BXL5uUdq8NqM+F2itsZvH8S1rud4+ftpz03uE3 juLoEJlDeptT3ROCDOTPYSrGq/4Y9qQlHleXlMhO9xSPiqK7xJndt+Ofsf87mMrg/LU644LevyU 1GPQ91cJA7qnp2zMbS998u+pJmfGIkmg076z7/ZhQrWL8A7RXFaQs= X-Google-Smtp-Source: AGHT+IEbqJq4oGbb0v90QbD4tSlHOmgRzJICcxZ8RRMzvr4CvJC4X9lCSrnsAdVYzVCR4fl5KksWPg== X-Received: by 2002:a05:6a20:5483:b0:34f:28f7:ed79 with SMTP id adf61e73a8af0-3613ca60118mr1794648637.19.1763612024737; Wed, 19 Nov 2025 20:13:44 -0800 (PST) Received: from localhost.localdomain ([154.3.39.171]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-bd75def6321sm989748a12.6.2025.11.19.20.13.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Nov 2025 20:13:44 -0800 (PST) From: Gui-Dong Han To: juergh@proton.me, linux@roeck-us.net Cc: linux-hwmon@vger.kernel.org, linux-kernel@vger.kernel.org, baijiaju1990@gmail.com, Gui-Dong Han Subject: [PATCH] hwmon: (vt1211) Convert macros to functions to avoid TOCTOU Date: Thu, 20 Nov 2025 12:13:31 +0800 Message-Id: <20251120041331.1917570-1-hanguidong02@gmail.com> X-Mailer: git-send-email 2.34.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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=3DLYJ_ehtp53HXEVkSpYoub+XYSTU8Rg=3D= o1xxMJ8=3D5z8B-g@mail.gmail.com/ Signed-off-by: Gui-Dong Han --- Based on the discussion in the link, I will submit a series of patches to address TOCTOU issues in the hwmon subsystem by converting macros to functions or adjusting locking where appropriate. --- drivers/hwmon/vt1211.c | 53 ++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index 386edea6b69e..1e52cabd6e24 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -142,9 +142,15 @@ struct vt1211_data { * in5 (ix =3D 5) is special. It's the internal 3.3V so it's scaled in the * driver according to the VT1211 BIOS porting guide */ -#define IN_FROM_REG(ix, reg) ((reg) < 3 ? 0 : (ix) =3D=3D 5 ? \ - (((reg) - 3) * 15882 + 479) / 958 : \ - (((reg) - 3) * 10000 + 479) / 958) +static int in_from_reg(int ix, int reg) +{ + if (reg < 3) + return 0; + if (ix =3D=3D 5) + return ((reg - 3) * 15882 + 479) / 958; + return ((reg - 3) * 10000 + 479) / 958; +} + #define IN_TO_REG(ix, val) (clamp_val((ix) =3D=3D 5 ? \ ((val) * 958 + 7941) / 15882 + 3 : \ ((val) * 958 + 5000) / 10000 + 3, 0, 255)) @@ -156,10 +162,15 @@ struct vt1211_data { * temp3-7 are thermistor based so the driver returns the voltage measured= at * the pin (range 0V - 2.2V). */ -#define TEMP_FROM_REG(ix, reg) ((ix) =3D=3D 0 ? (reg) * 1000 : \ - (ix) =3D=3D 1 ? (reg) < 51 ? 0 : \ - ((reg) - 51) * 1000 : \ - ((253 - (reg)) * 2200 + 105) / 210) +static int temp_from_reg(int ix, int reg) +{ + if (ix =3D=3D 0) + return reg * 1000; + if (ix =3D=3D 1) + return reg < 51 ? 0 : (reg - 51) * 1000; + return ((253 - reg) * 2200 + 105) / 210; +} + #define TEMP_TO_REG(ix, val) clamp_val( \ ((ix) =3D=3D 0 ? ((val) + 500) / 1000 : \ (ix) =3D=3D 1 ? ((val) + 500) / 1000 + 51 : \ @@ -167,8 +178,14 @@ struct vt1211_data { =20 #define DIV_FROM_REG(reg) (1 << (reg)) =20 -#define RPM_FROM_REG(reg, div) (((reg) =3D=3D 0) || ((reg) =3D=3D 255) ? 0= : \ - 1310720 / (reg) / DIV_FROM_REG(div)) +static int rpm_from_reg(int reg, int div) +{ + if (reg =3D=3D 0 || reg =3D=3D 255) + return 0; + + return 1310720 / reg / DIV_FROM_REG(div); +} + #define RPM_TO_REG(val, div) ((val) =3D=3D 0 ? 255 : \ clamp_val((1310720 / (val) / \ DIV_FROM_REG(div)), 1, 254)) @@ -343,13 +360,13 @@ static ssize_t show_in(struct device *dev, struct dev= ice_attribute *attr, =20 switch (fn) { case SHOW_IN_INPUT: - res =3D IN_FROM_REG(ix, data->in[ix]); + res =3D in_from_reg(ix, data->in[ix]); break; case SHOW_SET_IN_MIN: - res =3D IN_FROM_REG(ix, data->in_min[ix]); + res =3D in_from_reg(ix, data->in_min[ix]); break; case SHOW_SET_IN_MAX: - res =3D IN_FROM_REG(ix, data->in_max[ix]); + res =3D in_from_reg(ix, data->in_max[ix]); break; case SHOW_IN_ALARM: res =3D (data->alarms >> bitalarmin[ix]) & 1; @@ -417,13 +434,13 @@ static ssize_t show_temp(struct device *dev, struct d= evice_attribute *attr, =20 switch (fn) { case SHOW_TEMP_INPUT: - res =3D TEMP_FROM_REG(ix, data->temp[ix]); + res =3D temp_from_reg(ix, data->temp[ix]); break; case SHOW_SET_TEMP_MAX: - res =3D TEMP_FROM_REG(ix, data->temp_max[ix]); + res =3D temp_from_reg(ix, data->temp_max[ix]); break; case SHOW_SET_TEMP_MAX_HYST: - res =3D TEMP_FROM_REG(ix, data->temp_hyst[ix]); + res =3D temp_from_reg(ix, data->temp_hyst[ix]); break; case SHOW_TEMP_ALARM: res =3D (data->alarms >> bitalarmtemp[ix]) & 1; @@ -493,10 +510,10 @@ static ssize_t show_fan(struct device *dev, struct de= vice_attribute *attr, =20 switch (fn) { case SHOW_FAN_INPUT: - res =3D RPM_FROM_REG(data->fan[ix], data->fan_div[ix]); + res =3D rpm_from_reg(data->fan[ix], data->fan_div[ix]); break; case SHOW_SET_FAN_MIN: - res =3D RPM_FROM_REG(data->fan_min[ix], data->fan_div[ix]); + res =3D rpm_from_reg(data->fan_min[ix], data->fan_div[ix]); break; case SHOW_SET_FAN_DIV: res =3D DIV_FROM_REG(data->fan_div[ix]); @@ -751,7 +768,7 @@ static ssize_t show_pwm_auto_point_temp(struct device *= dev, int ix =3D sensor_attr_2->index; int ap =3D sensor_attr_2->nr; =20 - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->pwm_ctl[ix] & 7, + return sprintf(buf, "%d\n", temp_from_reg(data->pwm_ctl[ix] & 7, data->pwm_auto_temp[ap])); } =20 --=20 2.43.0