* [PATCH v2 0/2] thermal: hwmon: Fix thermal zone removal deadlock
@ 2026-08-04 20:06 Rafael J. Wysocki
2026-08-04 20:09 ` [PATCH v2 1/2] Revert "thermal/drivers/hwmon: Cleanup coding style a bit" Rafael J. Wysocki
2026-08-04 20:11 ` [PATCH v2 2/2] thermal: hwmon: Remove hwmon class device along with its parent Rafael J. Wysocki
0 siblings, 2 replies; 8+ messages in thread
From: Rafael J. Wysocki @ 2026-08-04 20:06 UTC (permalink / raw)
To: Linux PM
Cc: LKML, Linux ACPI, Lukasz Luba, Daniel Lezcano, Armin Wolf,
Guenter Roeck, linux-hwmon
This series is a replacement for
https://lore.kernel.org/linux-pm/23195575.EfDdHjke4D@rafael.j.wysocki/
with an additional patch to fix a UAF issue reintroduced by the
reverts at
https://lore.kernel.org/linux-pm/6319276.lOV4Wx5bFT@rafael.j.wysocki/
The first patch needs to go into 7.2-rc along with these revers,
while the second one is regarded as 7.3 material.
Thanks!
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 1/2] Revert "thermal/drivers/hwmon: Cleanup coding style a bit"
2026-08-04 20:06 [PATCH v2 0/2] thermal: hwmon: Fix thermal zone removal deadlock Rafael J. Wysocki
@ 2026-08-04 20:09 ` Rafael J. Wysocki
2026-08-04 20:24 ` sashiko-bot
2026-08-05 10:32 ` Lukasz Luba
2026-08-04 20:11 ` [PATCH v2 2/2] thermal: hwmon: Remove hwmon class device along with its parent Rafael J. Wysocki
1 sibling, 2 replies; 8+ messages in thread
From: Rafael J. Wysocki @ 2026-08-04 20:09 UTC (permalink / raw)
To: Linux PM
Cc: LKML, Linux ACPI, Lukasz Luba, Daniel Lezcano, Armin Wolf,
Guenter Roeck, linux-hwmon
From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
Revert commit 030a48b0f6ce ("thermal/drivers/hwmon: Cleanup coding style
a bit") that introduced a use-after-free into the error path of
thermal_add_hwmon_sysfs() by removing a valid check from it.
Link: https://lore.kernel.org/linux-hwmon/20260803183915.4ED7D1F000E9@smtp.kernel.org/
Cc: All applicable <stable@vger.kernel.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/thermal/thermal_hwmon.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/thermal/thermal_hwmon.c b/drivers/thermal/thermal_hwmon.c
index 597c33c8a555..ec73d03a1e60 100644
--- a/drivers/thermal/thermal_hwmon.c
+++ b/drivers/thermal/thermal_hwmon.c
@@ -212,7 +212,8 @@ int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
if (new_hwmon_device)
hwmon_device_unregister(hwmon->device);
free_mem:
- kfree(hwmon);
+ if (new_hwmon_device)
+ kfree(hwmon);
return result;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 2/2] thermal: hwmon: Remove hwmon class device along with its parent
2026-08-04 20:06 [PATCH v2 0/2] thermal: hwmon: Fix thermal zone removal deadlock Rafael J. Wysocki
2026-08-04 20:09 ` [PATCH v2 1/2] Revert "thermal/drivers/hwmon: Cleanup coding style a bit" Rafael J. Wysocki
@ 2026-08-04 20:11 ` Rafael J. Wysocki
2026-08-04 20:19 ` sashiko-bot
2026-08-05 10:40 ` Lukasz Luba
1 sibling, 2 replies; 8+ messages in thread
From: Rafael J. Wysocki @ 2026-08-04 20:11 UTC (permalink / raw)
To: Linux PM
Cc: LKML, Linux ACPI, Lukasz Luba, Daniel Lezcano, Armin Wolf,
Guenter Roeck, linux-hwmon
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
The current code creates one hwmon device per thermal zone type and that
device is registered under the first thermal zone of the given type.
That turns out to be problematic when the thermal zone holding the
hwmon device is removed.
For example, say that there are two ACPI thermal zones on a system
/sys/devices/virtual/thermal/thermal_zone0/
/sys/devices/virtual/thermal/thermal_zone1/
The current code registers a hwmon class device for thermal_zone0 only:
/sys/devices/virtual/thermal/thermal_zone0/hwmon0/
because the type is "acpitz" for both of them, but it adds a sysfs
attribute that belongs to thermal_zone1 under it:
/sys/devices/virtual/thermal/thermal_zone0/hwmon0/temp2_input
There is also
/sys/devices/virtual/thermal/thermal_zone0/hwmon0/temp1_input
which belongs to thermal_zone0.
When thermal_zone0 is removed, say because the ACPI thermal driver is
unbound from the underlying platform device, thermal_remove_hwmon_sysfs()
skips the removal of hwmon0 because of the temp2_input attribute
belonging to thermal_zone1 which effectively prevents thermal_zone0
removal from making progress.
Address this by making thermal_remove_hwmon_sysfs() remove the entire
hwmon class device interface for the given thermal zone type when the
thermal zone device holding it is removed.
To prevent races with thermal_add_hwmon_sysfs() that may interfere
with this, carry out the entire addition and removal of hwmon sysfs
interfaces for thermal zones under thermal_hwmon_list_lock.
Also adjust the layout of the labels in thermal_add_hwmon_sysfs() to
the current kernel coding style to align with the new "unlock" label.
Link: https://lore.kernel.org/linux-pm/20260402021828.16556-1-liujia6264@gmail.com/
Fixes: f6b6b52ef7a5 ("thermal_hwmon: Pass the originating device down to hwmon_device_register_with_info")
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
v1 -> v2:
* Rebase on top of the new [1/2]
---
drivers/thermal/thermal_hwmon.c | 89 +++++++++++++++-------------------------
1 file changed, 35 insertions(+), 54 deletions(-)
--- a/drivers/thermal/thermal_hwmon.c
+++ b/drivers/thermal/thermal_hwmon.c
@@ -95,34 +95,12 @@ thermal_hwmon_lookup_by_type(const struc
struct thermal_hwmon_device *hwmon;
char type[THERMAL_NAME_LENGTH];
- mutex_lock(&thermal_hwmon_list_lock);
list_for_each_entry(hwmon, &thermal_hwmon_list, node) {
strscpy(type, tz->type);
strreplace(type, '-', '_');
- if (!strcmp(hwmon->type, type)) {
- mutex_unlock(&thermal_hwmon_list_lock);
+ if (!strcmp(hwmon->type, type))
return hwmon;
- }
}
- mutex_unlock(&thermal_hwmon_list_lock);
-
- return NULL;
-}
-
-/* Find the temperature input matching a given thermal zone */
-static struct thermal_hwmon_temp *
-thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
- const struct thermal_zone_device *tz)
-{
- struct thermal_hwmon_temp *temp;
-
- mutex_lock(&thermal_hwmon_list_lock);
- list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
- if (temp->tz == tz) {
- mutex_unlock(&thermal_hwmon_list_lock);
- return temp;
- }
- mutex_unlock(&thermal_hwmon_list_lock);
return NULL;
}
@@ -138,7 +116,9 @@ int thermal_add_hwmon_sysfs(struct therm
struct thermal_hwmon_device *hwmon;
struct thermal_hwmon_temp *temp;
int new_hwmon_device = 1;
- int result;
+ int result = 0;
+
+ mutex_lock(&thermal_hwmon_list_lock);
hwmon = thermal_hwmon_lookup_by_type(tz);
if (hwmon) {
@@ -147,8 +127,10 @@ int thermal_add_hwmon_sysfs(struct therm
}
hwmon = kzalloc_obj(*hwmon);
- if (!hwmon)
- return -ENOMEM;
+ if (!hwmon) {
+ result = -ENOMEM;
+ goto unlock;
+ }
INIT_LIST_HEAD(&hwmon->tz_list);
strscpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
@@ -196,24 +178,24 @@ int thermal_add_hwmon_sysfs(struct therm
temp->temp_crit_present = true;
}
- mutex_lock(&thermal_hwmon_list_lock);
if (new_hwmon_device)
list_add_tail(&hwmon->node, &thermal_hwmon_list);
list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
- mutex_unlock(&thermal_hwmon_list_lock);
- return 0;
+ goto unlock;
- unregister_input:
+unregister_input:
device_remove_file(hwmon->device, &temp->temp_input.attr);
- free_temp_mem:
+free_temp_mem:
kfree(temp);
- unregister_name:
+unregister_name:
if (new_hwmon_device)
hwmon_device_unregister(hwmon->device);
- free_mem:
+free_mem:
if (new_hwmon_device)
kfree(hwmon);
+unlock:
+ mutex_unlock(&thermal_hwmon_list_lock);
return result;
}
@@ -222,8 +204,11 @@ EXPORT_SYMBOL_GPL(thermal_add_hwmon_sysf
void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
{
+ struct thermal_hwmon_temp *temp, *entry;
struct thermal_hwmon_device *hwmon;
- struct thermal_hwmon_temp *temp;
+ bool unregister;
+
+ guard(mutex)(&thermal_hwmon_list_lock);
hwmon = thermal_hwmon_lookup_by_type(tz);
if (unlikely(!hwmon)) {
@@ -232,29 +217,25 @@ void thermal_remove_hwmon_sysfs(struct t
return;
}
- temp = thermal_hwmon_lookup_temp(hwmon, tz);
- if (unlikely(!temp)) {
- /* Should never happen... */
- dev_dbg(&tz->device, "temperature input lookup failed!\n");
- return;
- }
+ unregister = hwmon->device->parent == &tz->device;
- device_remove_file(hwmon->device, &temp->temp_input.attr);
- if (temp->temp_crit_present)
- device_remove_file(hwmon->device, &temp->temp_crit.attr);
+ list_for_each_entry_safe_reverse(temp, entry, &hwmon->tz_list, hwmon_node) {
+ if (!unregister && temp->tz != tz)
+ continue;
- mutex_lock(&thermal_hwmon_list_lock);
- list_del(&temp->hwmon_node);
- kfree(temp);
- if (!list_empty(&hwmon->tz_list)) {
- mutex_unlock(&thermal_hwmon_list_lock);
- return;
+ device_remove_file(hwmon->device, &temp->temp_input.attr);
+ if (temp->temp_crit_present)
+ device_remove_file(hwmon->device, &temp->temp_crit.attr);
+
+ list_del(&temp->hwmon_node);
+ kfree(temp);
}
- list_del(&hwmon->node);
- mutex_unlock(&thermal_hwmon_list_lock);
- hwmon_device_unregister(hwmon->device);
- kfree(hwmon);
+ if (unregister) {
+ list_del(&hwmon->node);
+ hwmon_device_unregister(hwmon->device);
+ kfree(hwmon);
+ }
}
EXPORT_SYMBOL_GPL(thermal_remove_hwmon_sysfs);
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] thermal: hwmon: Remove hwmon class device along with its parent
2026-08-04 20:11 ` [PATCH v2 2/2] thermal: hwmon: Remove hwmon class device along with its parent Rafael J. Wysocki
@ 2026-08-04 20:19 ` sashiko-bot
2026-08-05 10:40 ` Lukasz Luba
1 sibling, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-08-04 20:19 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: linux-hwmon
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> The current code creates one hwmon device per thermal zone type and that
> device is registered under the first thermal zone of the given type.
>
> That turns out to be problematic when the thermal zone holding the
> hwmon device is removed.
>
> For example, say that there are two ACPI thermal zones on a system
>
> /sys/devices/virtual/thermal/thermal_zone0/
> /sys/devices/virtual/thermal/thermal_zone1/
>
> The current code registers a hwmon class device for thermal_zone0 only:
>
> [ ... ]
> the current kernel coding style to align with the new "unlock" label.
>
> Link: https://lore.kernel.org/linux-pm/20260402021828.16556-1-liujia6264@gmail.com/
> Fixes: f6b6b52ef7a5 ("thermal_hwmon: Pass the originating device down to hwmon_device_register_with_info")
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/12947893.O9o76ZdvQC@rafael.j.wysocki?part=2
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/2] Revert "thermal/drivers/hwmon: Cleanup coding style a bit"
2026-08-04 20:09 ` [PATCH v2 1/2] Revert "thermal/drivers/hwmon: Cleanup coding style a bit" Rafael J. Wysocki
@ 2026-08-04 20:24 ` sashiko-bot
2026-08-05 10:32 ` Lukasz Luba
1 sibling, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-08-04 20:24 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: linux-hwmon
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Lack of synchronization during hwmon device lookup and creation results in Use-After-Free of `hwmon` and Time-of-Check to Time-of-Use (TOCTOU) list duplication.
- [High] The hwmon sysfs attribute callbacks do not use `hwmon_lock()` as required by the subsystem guidelines.
--
--- Patch [1]: [PATCH v2 1/2] Revert "thermal/drivers/hwmon: Cleanup coding style a bit" ---
commit 85ae4605921a40cd95c1000cfc56b0df8bf8c9f1
Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Subject: Revert "thermal/drivers/hwmon: Cleanup coding style a bit"
Reverts a commit that introduced a use-after-free in the error path of
thermal_add_hwmon_sysfs() by removing a valid check.
Link: https://lore.kernel.org/linux-hwmon/20260803183915.4ED7D1F000E9@smtp.kernel.org/
> diff --git a/drivers/thermal/thermal_hwmon.c b/drivers/thermal/thermal_hwmon.c
> index 597c33c8a5550..ec73d03a1e60a 100644
> --- a/drivers/thermal/thermal_hwmon.c
> +++ b/drivers/thermal/thermal_hwmon.c
> @@ -212,7 +212,8 @@ int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> if (new_hwmon_device)
> hwmon_device_unregister(hwmon->device);
> free_mem:
> - kfree(hwmon);
> + if (new_hwmon_device)
> + kfree(hwmon);
>
> return result;
> }
[Severity: High]
This is a pre-existing issue, but is there a use-after-free and TOCTOU race
when looking up and adding a new hwmon device?
If one thread calls thermal_add_hwmon_sysfs() and looks up the hwmon device
via thermal_hwmon_lookup_by_type(), the list lock is dropped and an
unrefcounted pointer is returned:
drivers/thermal/thermal_hwmon.c:thermal_hwmon_lookup_by_type() {
...
if (!strcmp(hwmon->type, type)) {
mutex_unlock(&thermal_hwmon_list_lock);
return hwmon;
}
...
}
Concurrently, another thread could call thermal_remove_hwmon_sysfs() for the
last thermal zone sharing that hwmon device. It removes the last entry,
drops the list lock, unregisters the device, and frees the hwmon pointer
without synchronizing with active readers:
drivers/thermal/thermal_hwmon.c:thermal_remove_hwmon_sysfs() {
...
if (!list_empty(&hwmon->tz_list)) {
mutex_unlock(&thermal_hwmon_list_lock);
return;
}
list_del(&hwmon->node);
mutex_unlock(&thermal_hwmon_list_lock);
hwmon_device_unregister(hwmon->device);
kfree(hwmon);
}
The first thread could then resume in thermal_add_hwmon_sysfs() and
dereference the freed pointer when incrementing the count:
drivers/thermal/thermal_hwmon.c:thermal_add_hwmon_sysfs() {
...
register_sys_interface:
temp = kzalloc_obj(*temp);
if (!temp) {
result = -ENOMEM;
goto unregister_name;
}
temp->tz = tz;
hwmon->count++;
...
}
Could this lead to memory corruption during concurrent device probing or
unbinding?
[Severity: High]
This is a pre-existing issue, but do the hwmon sysfs attribute callbacks
need to use hwmon_lock() and hwmon_unlock() wrappers?
The hwmon subsystem guidelines require drivers to implement locking for
attributes registered by other means than hwmon_device_register_with_info().
The temp_input_show() and temp_crit_show() callbacks read attributes directly
without the required lock:
drivers/thermal/thermal_hwmon.c:temp_input_show() {
...
struct thermal_zone_device *tz = temp->tz;
ret = thermal_zone_get_temp(tz, &temperature);
...
}
drivers/thermal/thermal_hwmon.c:temp_crit_show() {
...
struct thermal_zone_device *tz = temp->tz;
int temperature;
int ret;
guard(thermal_zone)(tz);
ret = tz->ops.get_crit_temp(tz, &temperature);
...
}
Could this result in a race condition with interrupt handlers or driver
unregistration since it bypasses the core kernel locking rules for the hwmon
subsystem?
--
Sashiko AI review · https://sashiko.dev/#/patchset/12947893.O9o76ZdvQC@rafael.j.wysocki?part=1
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/2] Revert "thermal/drivers/hwmon: Cleanup coding style a bit"
2026-08-04 20:09 ` [PATCH v2 1/2] Revert "thermal/drivers/hwmon: Cleanup coding style a bit" Rafael J. Wysocki
2026-08-04 20:24 ` sashiko-bot
@ 2026-08-05 10:32 ` Lukasz Luba
2026-08-05 11:53 ` Rafael J. Wysocki (Intel)
1 sibling, 1 reply; 8+ messages in thread
From: Lukasz Luba @ 2026-08-05 10:32 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: LKML, Linux PM, Linux ACPI, Daniel Lezcano, Armin Wolf,
Guenter Roeck, linux-hwmon
On 8/4/26 21:09, Rafael J. Wysocki wrote:
> From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
>
> Revert commit 030a48b0f6ce ("thermal/drivers/hwmon: Cleanup coding style
> a bit") that introduced a use-after-free into the error path of
> thermal_add_hwmon_sysfs() by removing a valid check from it.
>
> Link: https://lore.kernel.org/linux-hwmon/20260803183915.4ED7D1F000E9@smtp.kernel.org/
> Cc: All applicable <stable@vger.kernel.org>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
> drivers/thermal/thermal_hwmon.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/thermal/thermal_hwmon.c b/drivers/thermal/thermal_hwmon.c
> index 597c33c8a555..ec73d03a1e60 100644
> --- a/drivers/thermal/thermal_hwmon.c
> +++ b/drivers/thermal/thermal_hwmon.c
> @@ -212,7 +212,8 @@ int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> if (new_hwmon_device)
> hwmon_device_unregister(hwmon->device);
> free_mem:
> - kfree(hwmon);
> + if (new_hwmon_device)
> + kfree(hwmon);
>
> return result;
> }
LGTM, a tricky plumbing. I'm sorry for being late with review.
Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] thermal: hwmon: Remove hwmon class device along with its parent
2026-08-04 20:11 ` [PATCH v2 2/2] thermal: hwmon: Remove hwmon class device along with its parent Rafael J. Wysocki
2026-08-04 20:19 ` sashiko-bot
@ 2026-08-05 10:40 ` Lukasz Luba
1 sibling, 0 replies; 8+ messages in thread
From: Lukasz Luba @ 2026-08-05 10:40 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: LKML, Linux PM, Linux ACPI, Daniel Lezcano, Armin Wolf,
Guenter Roeck, linux-hwmon
On 8/4/26 21:11, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> The current code creates one hwmon device per thermal zone type and that
> device is registered under the first thermal zone of the given type.
>
> That turns out to be problematic when the thermal zone holding the
> hwmon device is removed.
>
> For example, say that there are two ACPI thermal zones on a system
>
> /sys/devices/virtual/thermal/thermal_zone0/
> /sys/devices/virtual/thermal/thermal_zone1/
>
> The current code registers a hwmon class device for thermal_zone0 only:
>
> /sys/devices/virtual/thermal/thermal_zone0/hwmon0/
>
> because the type is "acpitz" for both of them, but it adds a sysfs
> attribute that belongs to thermal_zone1 under it:
>
> /sys/devices/virtual/thermal/thermal_zone0/hwmon0/temp2_input
>
> There is also
>
> /sys/devices/virtual/thermal/thermal_zone0/hwmon0/temp1_input
>
> which belongs to thermal_zone0.
>
> When thermal_zone0 is removed, say because the ACPI thermal driver is
> unbound from the underlying platform device, thermal_remove_hwmon_sysfs()
> skips the removal of hwmon0 because of the temp2_input attribute
> belonging to thermal_zone1 which effectively prevents thermal_zone0
> removal from making progress.
>
> Address this by making thermal_remove_hwmon_sysfs() remove the entire
> hwmon class device interface for the given thermal zone type when the
> thermal zone device holding it is removed.
>
> To prevent races with thermal_add_hwmon_sysfs() that may interfere
> with this, carry out the entire addition and removal of hwmon sysfs
> interfaces for thermal zones under thermal_hwmon_list_lock.
>
> Also adjust the layout of the labels in thermal_add_hwmon_sysfs() to
> the current kernel coding style to align with the new "unlock" label.
>
> Link: https://lore.kernel.org/linux-pm/20260402021828.16556-1-liujia6264@gmail.com/
> Fixes: f6b6b52ef7a5 ("thermal_hwmon: Pass the originating device down to hwmon_device_register_with_info")
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
>
> v1 -> v2:
> * Rebase on top of the new [1/2]
>
> ---
> drivers/thermal/thermal_hwmon.c | 89 +++++++++++++++-------------------------
> 1 file changed, 35 insertions(+), 54 deletions(-)
>
> --- a/drivers/thermal/thermal_hwmon.c
> +++ b/drivers/thermal/thermal_hwmon.c
> @@ -95,34 +95,12 @@ thermal_hwmon_lookup_by_type(const struc
> struct thermal_hwmon_device *hwmon;
> char type[THERMAL_NAME_LENGTH];
>
> - mutex_lock(&thermal_hwmon_list_lock);
> list_for_each_entry(hwmon, &thermal_hwmon_list, node) {
> strscpy(type, tz->type);
> strreplace(type, '-', '_');
> - if (!strcmp(hwmon->type, type)) {
> - mutex_unlock(&thermal_hwmon_list_lock);
> + if (!strcmp(hwmon->type, type))
> return hwmon;
> - }
> }
> - mutex_unlock(&thermal_hwmon_list_lock);
> -
> - return NULL;
> -}
> -
> -/* Find the temperature input matching a given thermal zone */
> -static struct thermal_hwmon_temp *
> -thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
> - const struct thermal_zone_device *tz)
> -{
> - struct thermal_hwmon_temp *temp;
> -
> - mutex_lock(&thermal_hwmon_list_lock);
> - list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
> - if (temp->tz == tz) {
> - mutex_unlock(&thermal_hwmon_list_lock);
> - return temp;
> - }
> - mutex_unlock(&thermal_hwmon_list_lock);
>
> return NULL;
> }
> @@ -138,7 +116,9 @@ int thermal_add_hwmon_sysfs(struct therm
> struct thermal_hwmon_device *hwmon;
> struct thermal_hwmon_temp *temp;
> int new_hwmon_device = 1;
> - int result;
> + int result = 0;
> +
> + mutex_lock(&thermal_hwmon_list_lock);
>
> hwmon = thermal_hwmon_lookup_by_type(tz);
> if (hwmon) {
> @@ -147,8 +127,10 @@ int thermal_add_hwmon_sysfs(struct therm
> }
>
> hwmon = kzalloc_obj(*hwmon);
> - if (!hwmon)
> - return -ENOMEM;
> + if (!hwmon) {
> + result = -ENOMEM;
> + goto unlock;
> + }
>
> INIT_LIST_HEAD(&hwmon->tz_list);
> strscpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
> @@ -196,24 +178,24 @@ int thermal_add_hwmon_sysfs(struct therm
> temp->temp_crit_present = true;
> }
>
> - mutex_lock(&thermal_hwmon_list_lock);
> if (new_hwmon_device)
> list_add_tail(&hwmon->node, &thermal_hwmon_list);
> list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
> - mutex_unlock(&thermal_hwmon_list_lock);
>
> - return 0;
> + goto unlock;
>
> - unregister_input:
> +unregister_input:
> device_remove_file(hwmon->device, &temp->temp_input.attr);
> - free_temp_mem:
> +free_temp_mem:
> kfree(temp);
> - unregister_name:
> +unregister_name:
> if (new_hwmon_device)
> hwmon_device_unregister(hwmon->device);
> - free_mem:
> +free_mem:
> if (new_hwmon_device)
> kfree(hwmon);
> +unlock:
> + mutex_unlock(&thermal_hwmon_list_lock);
>
> return result;
> }
> @@ -222,8 +204,11 @@ EXPORT_SYMBOL_GPL(thermal_add_hwmon_sysf
>
> void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> {
> + struct thermal_hwmon_temp *temp, *entry;
> struct thermal_hwmon_device *hwmon;
> - struct thermal_hwmon_temp *temp;
> + bool unregister;
> +
> + guard(mutex)(&thermal_hwmon_list_lock);
>
> hwmon = thermal_hwmon_lookup_by_type(tz);
> if (unlikely(!hwmon)) {
> @@ -232,29 +217,25 @@ void thermal_remove_hwmon_sysfs(struct t
> return;
> }
>
> - temp = thermal_hwmon_lookup_temp(hwmon, tz);
> - if (unlikely(!temp)) {
> - /* Should never happen... */
> - dev_dbg(&tz->device, "temperature input lookup failed!\n");
> - return;
> - }
> + unregister = hwmon->device->parent == &tz->device;
>
> - device_remove_file(hwmon->device, &temp->temp_input.attr);
> - if (temp->temp_crit_present)
> - device_remove_file(hwmon->device, &temp->temp_crit.attr);
> + list_for_each_entry_safe_reverse(temp, entry, &hwmon->tz_list, hwmon_node) {
> + if (!unregister && temp->tz != tz)
> + continue;
>
> - mutex_lock(&thermal_hwmon_list_lock);
> - list_del(&temp->hwmon_node);
> - kfree(temp);
> - if (!list_empty(&hwmon->tz_list)) {
> - mutex_unlock(&thermal_hwmon_list_lock);
> - return;
> + device_remove_file(hwmon->device, &temp->temp_input.attr);
> + if (temp->temp_crit_present)
> + device_remove_file(hwmon->device, &temp->temp_crit.attr);
> +
> + list_del(&temp->hwmon_node);
> + kfree(temp);
> }
> - list_del(&hwmon->node);
> - mutex_unlock(&thermal_hwmon_list_lock);
>
> - hwmon_device_unregister(hwmon->device);
> - kfree(hwmon);
> + if (unregister) {
> + list_del(&hwmon->node);
> + hwmon_device_unregister(hwmon->device);
> + kfree(hwmon);
> + }
> }
> EXPORT_SYMBOL_GPL(thermal_remove_hwmon_sysfs);
>
>
>
>
Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/2] Revert "thermal/drivers/hwmon: Cleanup coding style a bit"
2026-08-05 10:32 ` Lukasz Luba
@ 2026-08-05 11:53 ` Rafael J. Wysocki (Intel)
0 siblings, 0 replies; 8+ messages in thread
From: Rafael J. Wysocki (Intel) @ 2026-08-05 11:53 UTC (permalink / raw)
To: Lukasz Luba
Cc: Rafael J. Wysocki, LKML, Linux PM, Linux ACPI, Daniel Lezcano,
Armin Wolf, Guenter Roeck, linux-hwmon
On Wed, Aug 5, 2026 at 12:32 PM Lukasz Luba <lukasz.luba@arm.com> wrote:
>
>
>
> On 8/4/26 21:09, Rafael J. Wysocki wrote:
> > From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
> >
> > Revert commit 030a48b0f6ce ("thermal/drivers/hwmon: Cleanup coding style
> > a bit") that introduced a use-after-free into the error path of
> > thermal_add_hwmon_sysfs() by removing a valid check from it.
> >
> > Link: https://lore.kernel.org/linux-hwmon/20260803183915.4ED7D1F000E9@smtp.kernel.org/
> > Cc: All applicable <stable@vger.kernel.org>
> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > ---
> > drivers/thermal/thermal_hwmon.c | 3 ++-
> > 1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/thermal/thermal_hwmon.c b/drivers/thermal/thermal_hwmon.c
> > index 597c33c8a555..ec73d03a1e60 100644
> > --- a/drivers/thermal/thermal_hwmon.c
> > +++ b/drivers/thermal/thermal_hwmon.c
> > @@ -212,7 +212,8 @@ int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> > if (new_hwmon_device)
> > hwmon_device_unregister(hwmon->device);
> > free_mem:
> > - kfree(hwmon);
> > + if (new_hwmon_device)
> > + kfree(hwmon);
> >
> > return result;
> > }
>
> LGTM, a tricky plumbing. I'm sorry for being late with review.
No worries.
> Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
And thanks!
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-05 11:53 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-04 20:06 [PATCH v2 0/2] thermal: hwmon: Fix thermal zone removal deadlock Rafael J. Wysocki
2026-08-04 20:09 ` [PATCH v2 1/2] Revert "thermal/drivers/hwmon: Cleanup coding style a bit" Rafael J. Wysocki
2026-08-04 20:24 ` sashiko-bot
2026-08-05 10:32 ` Lukasz Luba
2026-08-05 11:53 ` Rafael J. Wysocki (Intel)
2026-08-04 20:11 ` [PATCH v2 2/2] thermal: hwmon: Remove hwmon class device along with its parent Rafael J. Wysocki
2026-08-04 20:19 ` sashiko-bot
2026-08-05 10:40 ` Lukasz Luba
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox