From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com> mainline inclusion from mainline-v7.1-rc1 commit 41ff66baf81c6541f4f985dd7eac4494d03d9440 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/15286 CVE: CVE-2026-46021 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- If thermal_zone_device_register_with_trips() fails after adding a thermal governor to the thermal zone being registered, the governor is not removed from it as appropriate which may lead to a memory leak. In turn, thermal_zone_device_unregister() calls thermal_set_governor() without acquiring the thermal zone lock beforehand which may race with a governor update via sysfs and may lead to a use-after-free in that case. Address these issues by adding two thermal_set_governor() calls, one to thermal_release() to remove the governor from the given thermal zone, and one to the thermal zone registration error path to cover failures preceding the thermal zone device registration. Fixes: e33df1d2f3a0 ("thermal: let governors have private data for each thermal zone") Cc: All applicable <stable@vger.kernel.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Link: https://patch.msgid.link/5092923.31r3eYUQgx@rafael.j.wysocki Conflicts: drivers/thermal/thermal_core.c [context conflict.] Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com> --- drivers/thermal/thermal_core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 98d9bba6f4ac..37cb45b133ed 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -840,6 +840,7 @@ static void thermal_release(struct device *dev) sizeof("thermal_zone") - 1)) { tz = to_thermal_zone(dev); thermal_zone_destroy_device_groups(tz); + thermal_set_governor(tz, NULL); kfree(tz); } else if (!strncmp(dev_name(dev), "cooling_device", sizeof("cooling_device") - 1)) { @@ -1230,8 +1231,10 @@ thermal_zone_device_register(const char *type, int trips, int mask, /* sys I/F */ /* Add nodes that are always present via .groups */ result = thermal_zone_create_device_groups(tz, mask); - if (result) + if (result) { + thermal_set_governor(tz, NULL); goto remove_id; + } /* A new thermal zone needs to be updated anyway. */ atomic_set(&tz->need_update, 1); @@ -1353,8 +1356,6 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) cancel_delayed_work_sync(&tz->poll_queue); - thermal_set_governor(tz, NULL); - thermal_remove_hwmon_sysfs(tz); ida_simple_remove(&thermal_tz_ida, tz->id); ida_destroy(&tz->ida); -- 2.34.1