From 185039b1c0389b70ec52a6d3e3c1494e2d0e23da Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 30 Oct 2026 10:31:20 -0700 Subject: [PATCH] hwmon: (hp-wmi-sensors) Fix unbounded loops in scale_numeric_sensor() In scale_numeric_sensor() in the hp-wmi-sensors hwmon driver, an unbounded loop occurs if the ACPI WMI implementation provides a highly anomalous or malformed UnitModifier value for a numeric sensor. The UnitModifier property is extracted from a WMI ACPI object without bounds checking and cast to a signed 32-bit integer. This value directly controls the iteration count of two scaling loops. If the provided unit_modifier is extremely negative (e.g., INT_MIN), the first loop executes billions of times before reaching target_modifier. Conversely, if unit_modifier is extremely large (e.g., INT_MAX) and the current sensor reading (val) is exactly 0, the second loop's overflow safeguard (val > LONG_MAX / 10) never evaluates to true, resulting in billions of unnecessary iterations. This prolonged execution causes severe CPU stalls and thread soft lockups during driver initialization or whenever a user-space process reads the sensor attribute via sysfs, resulting in a denial of service on the affected CPU core. Fix the problem in the first loop by exiting it as soon as val is zero. Fix the problem with the second loop by only entering it if val is not zero. Also add a check for val < LONG_MIN / 10 and exit the loop if that is the case. Fixes: 23902f98f8d4 ("hwmon: add HP WMI Sensors driver") Cc: stable@vger.kernel.org Cc: James Seo Acked-by: James Seo Signed-off-by: Guenter Roeck --- drivers/hwmon/hp-wmi-sensors.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/hwmon/hp-wmi-sensors.c b/drivers/hwmon/hp-wmi-sensors.c index a859752c8387..1953d672edaf 100644 --- a/drivers/hwmon/hp-wmi-sensors.c +++ b/drivers/hwmon/hp-wmi-sensors.c @@ -739,15 +739,21 @@ static long scale_numeric_sensor(const struct hp_wmi_numeric_sensor *nsensor) val = current_reading; - for (; unit_modifier < target_modifier; unit_modifier++) + for (; val && unit_modifier < target_modifier; unit_modifier++) val = DIV_ROUND_CLOSEST(val, 10); - for (; unit_modifier > target_modifier; unit_modifier--) { - if (val > LONG_MAX / 10) { - val = LONG_MAX; - break; + if (val) { + for (; unit_modifier > target_modifier; unit_modifier--) { + if (val > LONG_MAX / 10) { + val = LONG_MAX; + break; + } + if (val < LONG_MIN / 10) { + val = LONG_MIN; + break; + } + val *= 10; } - val *= 10; } if (sensor_type == HP_WMI_TYPE_TEMPERATURE) {