VYPR
Unrated severityNVD Advisory· Published May 27, 2026· Updated May 27, 2026

CVE-2026-46021

CVE-2026-46021

Description

In the Linux kernel, the following vulnerability has been resolved:

thermal: core: Fix thermal zone governor cleanup issues

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.

Affected products

1

Patches

10
37a430a2d4e6

thermal: core: Fix thermal zone governor cleanup issues

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git"Rafael J. Wysocki"Apr 30, 2026Fixed in 6.6.140via kernel-cna
1 file changed · +4 4
  • drivers/thermal/thermal_core.c+4 4 modified
    diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
    index 660a8d6f35673b..3efdd2ae6dcb89 100644
    --- a/drivers/thermal/thermal_core.c
    +++ b/drivers/thermal/thermal_core.c
    @@ -804,6 +804,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",
    @@ -1325,8 +1326,10 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t
     	/* 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);
    @@ -1478,8 +1481,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_free(&thermal_tz_ida, tz->id);
     	ida_destroy(&tz->ida);
    -- 
    cgit 1.3-korg
    
    
    
f412e541d25a

thermal: core: Fix thermal zone governor cleanup issues

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git"Rafael J. Wysocki"Apr 30, 2026Fixed in 6.12.86via kernel-cna
1 file changed · +4 4
  • drivers/thermal/thermal_core.c+4 4 modified
    diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
    index 8ce1134e15e567..1eaddce11aedd9 100644
    --- a/drivers/thermal/thermal_core.c
    +++ b/drivers/thermal/thermal_core.c
    @@ -917,6 +917,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",
    @@ -1483,8 +1484,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;
    +	}
     
     	/* A new thermal zone needs to be updated anyway. */
     	atomic_set(&tz->need_update, 1);
    @@ -1630,8 +1633,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_free(&thermal_tz_ida, tz->id);
     	ida_destroy(&tz->ida);
    -- 
    cgit 1.3-korg
    
    
    
41ff66baf81c

thermal: core: Fix thermal zone governor cleanup issues

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git"Rafael J. Wysocki"Fixed in 7.1-rc1via kernel-cna
1 file changed · +4 4
  • drivers/thermal/thermal_core.c+4 4 modified
    diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
    index b6b651cb233173..6e10b2fe29724a 100644
    --- a/drivers/thermal/thermal_core.c
    +++ b/drivers/thermal/thermal_core.c
    @@ -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);
    -- 
    cgit 1.3-korg
    
    
    
75f8f3c3e091

thermal: core: Fix thermal zone governor cleanup issues

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git"Rafael J. Wysocki"Fixed in 6.18.27via kernel-cna
1 file changed · +4 4
  • drivers/thermal/thermal_core.c+4 4 modified
    diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
    index f28c15dd0b9260..61e6dc81dc923e 100644
    --- a/drivers/thermal/thermal_core.c
    +++ b/drivers/thermal/thermal_core.c
    @@ -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",
    @@ -1607,8 +1608,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)
    @@ -1721,8 +1724,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);
    -- 
    cgit 1.3-korg
    
    
    
64d4ebf91d08

thermal: core: Fix thermal zone governor cleanup issues

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git"Rafael J. Wysocki"Fixed in 7.0.4via kernel-cna
1 file changed · +4 4
  • drivers/thermal/thermal_core.c+4 4 modified
    diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
    index d1beee9e15f8ef..cf75f7035602fd 100644
    --- a/drivers/thermal/thermal_core.c
    +++ b/drivers/thermal/thermal_core.c
    @@ -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",
    @@ -1611,8 +1612,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)
    @@ -1725,8 +1728,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);
    -- 
    cgit 1.3-korg
    
    
    
37a430a2d4e6

thermal: core: Fix thermal zone governor cleanup issues

1 file changed · +4 4
  • drivers/thermal/thermal_core.c+4 4 modified
    diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
    index 660a8d6f35673b..3efdd2ae6dcb89 100644
    --- a/drivers/thermal/thermal_core.c
    +++ b/drivers/thermal/thermal_core.c
    @@ -804,6 +804,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",
    @@ -1325,8 +1326,10 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t
     	/* 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);
    @@ -1478,8 +1481,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_free(&thermal_tz_ida, tz->id);
     	ida_destroy(&tz->ida);
    -- 
    cgit 1.3-korg
    
    
    
f412e541d25a

thermal: core: Fix thermal zone governor cleanup issues

1 file changed · +4 4
  • drivers/thermal/thermal_core.c+4 4 modified
    diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
    index 8ce1134e15e567..1eaddce11aedd9 100644
    --- a/drivers/thermal/thermal_core.c
    +++ b/drivers/thermal/thermal_core.c
    @@ -917,6 +917,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",
    @@ -1483,8 +1484,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;
    +	}
     
     	/* A new thermal zone needs to be updated anyway. */
     	atomic_set(&tz->need_update, 1);
    @@ -1630,8 +1633,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_free(&thermal_tz_ida, tz->id);
     	ida_destroy(&tz->ida);
    -- 
    cgit 1.3-korg
    
    
    
41ff66baf81c

thermal: core: Fix thermal zone governor cleanup issues

1 file changed · +4 4
  • drivers/thermal/thermal_core.c+4 4 modified
    diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
    index b6b651cb233173..6e10b2fe29724a 100644
    --- a/drivers/thermal/thermal_core.c
    +++ b/drivers/thermal/thermal_core.c
    @@ -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);
    -- 
    cgit 1.3-korg
    
    
    
64d4ebf91d08

thermal: core: Fix thermal zone governor cleanup issues

1 file changed · +4 4
  • drivers/thermal/thermal_core.c+4 4 modified
    diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
    index d1beee9e15f8ef..cf75f7035602fd 100644
    --- a/drivers/thermal/thermal_core.c
    +++ b/drivers/thermal/thermal_core.c
    @@ -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",
    @@ -1611,8 +1612,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)
    @@ -1725,8 +1728,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);
    -- 
    cgit 1.3-korg
    
    
    
75f8f3c3e091

thermal: core: Fix thermal zone governor cleanup issues

1 file changed · +4 4
  • drivers/thermal/thermal_core.c+4 4 modified
    diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
    index f28c15dd0b9260..61e6dc81dc923e 100644
    --- a/drivers/thermal/thermal_core.c
    +++ b/drivers/thermal/thermal_core.c
    @@ -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",
    @@ -1607,8 +1608,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)
    @@ -1721,8 +1724,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);
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"Missing governor cleanup in thermal zone release and registration error paths, and missing lock acquisition when calling thermal_set_governor() during unregistration."

Attack vector

An attacker with local access can trigger the race condition by writing to the thermal zone's governor sysfs attribute concurrently with a thermal zone device being unregistered. Because `thermal_zone_device_unregister()` called `thermal_set_governor()` without acquiring the thermal zone lock [patch_id=2660373], a concurrent sysfs governor update could race with the unregister path, leading to a use-after-free. Additionally, if `thermal_zone_device_register_with_trips()` fails after a governor has been added (e.g., if `thermal_zone_create_device_groups()` fails), the governor is not removed, causing a memory leak.

Affected code

The vulnerability is in `drivers/thermal/thermal_core.c`, specifically in the functions `thermal_release()`, `thermal_zone_device_register_with_trips()`, and `thermal_zone_device_unregister()` [patch_id=2660373]. The registration error path and the release path both failed to call `thermal_set_governor(tz, NULL)` to properly clean up the governor association, and `thermal_zone_device_unregister()` called `thermal_set_governor()` without holding the thermal zone lock.

What the fix does

The patch adds `thermal_set_governor(tz, NULL)` in two places. First, in `thermal_release()`, so that when a thermal zone device is released, the governor is properly detached, preventing a memory leak of governor-private data. Second, in the error path of `thermal_zone_device_register_with_trips()` after `thermal_zone_create_device_groups()` fails, ensuring that if registration fails after a governor was already added, the governor is cleaned up. The patch also removes the unprotected `thermal_set_governor(tz, NULL)` call from `thermal_zone_device_unregister()`, since the release path now handles it under the lock [patch_id=2660373].

Preconditions

  • authLocal access to the system to trigger thermal zone registration/unregistration or to write to sysfs governor attributes
  • inputAbility to trigger a failure in thermal_zone_device_register_with_trips() after governor attachment (for memory leak)
  • inputConcurrent sysfs governor write and thermal zone unregistration (for use-after-free race)

Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.