]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
thermal: core: Fix thermal zone governor cleanup issues
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 7 Apr 2026 13:55:19 +0000 (15:55 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 8 Apr 2026 10:30:30 +0000 (12:30 +0200)
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
drivers/thermal/thermal_core.c

index b6b651cb233173ba520a8462382c096183b5bbd6..6e10b2fe29724a9872260edf760d563ab20e3b89 100644 (file)
@@ -964,6 +964,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);
                mutex_destroy(&tz->lock);
                complete(&tz->removal);
        } else if (!strncmp(dev_name(dev), "cooling_device",
@@ -1610,8 +1611,10 @@ thermal_zone_device_register_with_trips(const char *type,
        /* sys I/F */
        /* Add nodes that are always present via .groups */
        result = thermal_zone_create_device_groups(tz);
-       if (result)
+       if (result) {
+               thermal_set_governor(tz, NULL);
                goto remove_id;
+       }
 
        result = device_register(&tz->device);
        if (result)
@@ -1724,8 +1727,6 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
 
        cancel_delayed_work_sync(&tz->poll_queue);
 
-       thermal_set_governor(tz, NULL);
-
        thermal_thresholds_exit(tz);
        thermal_remove_hwmon_sysfs(tz);
        ida_free(&thermal_tz_ida, tz->id);