CVE-2026-31731

Severity CVSS v4.0:
Pending analysis
Type:
CWE-416 Use After Free
Publication date:
01/05/2026
Last modified:
08/05/2026

Description

In the Linux kernel, the following vulnerability has been resolved:<br /> <br /> thermal: core: Address thermal zone removal races with resume<br /> <br /> Since thermal_zone_pm_complete() and thermal_zone_device_resume()<br /> re-initialize the poll_queue delayed work for the given thermal zone,<br /> the cancel_delayed_work_sync() in thermal_zone_device_unregister()<br /> may miss some already running work items and the thermal zone may<br /> be freed prematurely [1].<br /> <br /> There are two failing scenarios that both start with<br /> running thermal_pm_notify_complete() right before invoking<br /> thermal_zone_device_unregister() for one of the thermal zones.<br /> <br /> In the first scenario, there is a work item already running for<br /> the given thermal zone when thermal_pm_notify_complete() calls<br /> thermal_zone_pm_complete() for that thermal zone and it continues to<br /> run when thermal_zone_device_unregister() starts. Since the poll_queue<br /> delayed work has been re-initialized by thermal_pm_notify_complete(), the<br /> running work item will be missed by the cancel_delayed_work_sync() in<br /> thermal_zone_device_unregister() and if it continues to run past the<br /> freeing of the thermal zone object, a use-after-free will occur.<br /> <br /> In the second scenario, thermal_zone_device_resume() queued up by<br /> thermal_pm_notify_complete() runs right after the thermal_zone_exit()<br /> called by thermal_zone_device_unregister() has returned. The poll_queue<br /> delayed work is re-initialized by it before cancel_delayed_work_sync() is<br /> called by thermal_zone_device_unregister(), so it may continue to run<br /> after the freeing of the thermal zone object, which also leads to a<br /> use-after-free.<br /> <br /> Address the first failing scenario by ensuring that no thermal work<br /> items will be running when thermal_pm_notify_complete() is called.<br /> For this purpose, first move the cancel_delayed_work() call from<br /> thermal_zone_pm_complete() to thermal_zone_pm_prepare() to prevent<br /> new work from entering the workqueue going forward. Next, switch<br /> over to using a dedicated workqueue for thermal events and update<br /> the code in thermal_pm_notify() to flush that workqueue after<br /> thermal_pm_notify_prepare() has returned which will take care of<br /> all leftover thermal work already on the workqueue (that leftover<br /> work would do nothing useful anyway because all of the thermal zones<br /> have been flagged as suspended).<br /> <br /> The second failing scenario is addressed by adding a tz-&gt;state check<br /> to thermal_zone_device_resume() to prevent it from re-initializing<br /> the poll_queue delayed work if the thermal zone is going away.<br /> <br /> Note that the above changes will also facilitate relocating the suspend<br /> and resume of thermal zones closer to the suspend and resume of devices,<br /> respectively.

Vulnerable products and versions

CPE From Up to
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.8 (including) 6.12.83 (excluding)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.13 (including) 6.18.22 (excluding)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.19 (including) 6.19.12 (excluding)
cpe:2.3:o:linux:linux_kernel:7.0:rc1:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:7.0:rc2:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:7.0:rc3:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:7.0:rc4:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:7.0:rc5:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:7.0:rc6:*:*:*:*:*:*