CVE-2026-31731: thermal: core: Address thermal zone removal races with resume
In the Linux kernel, the following vulnerability has been resolved:
thermal: core: Address thermal zone removal races with resume
Since thermalzonepmcomplete() and thermalzonedeviceresume() re-initialize the pollqueue delayed work for the given thermal zone, the canceldelayedworksync() in thermalzonedeviceunregister() may miss some already running work items and the thermal zone may be freed prematurely [1].
There are two failing scenarios that both start with running thermalpmnotifycomplete() right before invoking thermalzonedeviceunregister() for one of the thermal zones.
In the first scenario, there is a work item already running for the given thermal zone when thermalpmnotifycomplete() calls thermalzonepmcomplete() for that thermal zone and it continues to run when thermalzonedeviceunregister() starts. Since the pollqueue delayed work has been re-initialized by thermalpmnotifycomplete(), the running work item will be missed by the canceldelayedworksync() in thermalzonedeviceunregister() and if it continues to run past the freeing of the thermal zone object, a use-after-free will occur.
In the second scenario, thermalzonedeviceresume() queued up by thermalpmnotifycomplete() runs right after the thermalzoneexit() called by thermalzonedeviceunregister() has returned. The pollqueue delayed work is re-initialized by it before canceldelayedworksync() is called by thermalzonedeviceunregister(), so it may continue to run after the freeing of the thermal zone object, which also leads to a use-after-free.
Address the first failing scenario by ensuring that no thermal work items will be running when thermalpmnotifycomplete() is called. For this purpose, first move the canceldelayedwork() call from thermalzonepmcomplete() to thermalzonepmprepare() to prevent new work from entering the workqueue going forward. Next, switch over to using a dedicated workqueue for thermal events and update the code in thermalpmnotify() to flush that workqueue after thermalpmnotifyprepare() has returned which will take care of all leftover thermal work already on the workqueue (that leftover work would do nothing useful anyway because all of the thermal zones have been flagged as suspended).
The second failing scenario is addressed by adding a tz->state check to thermalzonedeviceresume() to prevent it from re-initializing the pollqueue delayed work if the thermal zone is going away.
Note that the above changes will also facilitate relocating the suspend and resume of thermal zones closer to the suspend and resume of devices, respectively.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Configuration
Implement the kernel thermal-core race fix: (1) move the cancel_delayed_work() call so it happens before the thermal zone object is freed, avoiding use-after-free when delayed work is re-initialized by thermal_pm_notify_complete(); (2) switch to a dedicated workqueue for thermal events and re-initialize the poll_queue delayed work for the given thermal zone; (3) flush that workqueue after poll_queue delayed work is triggered during thermal_pm_notify_complete() when the thermal zone is going away; and (4) in the second failing scenario, add a tz->state check (as described) to prevent resuming/running work during removal.
Linux kernel thermal core poll_queue delayed work re-initialization and cancel_delayed_work()/cancel_delayed_work_sync sequencing = Move cancel_delayed_work() from the location mentioned in the text to ensure no thermal work can run after freeing the thermal zone object; use dedicated workqueue for thermal events and flush it when thermal_pm_notify_complete() calls the poll_queue delayed work if the thermal zone is going away; add tz->state check in the second failing scenario.
Event History
Frequently Asked Questions
What level of access is required to exploit this issue?
The CVSS vector indicates local access with low privileges is required. No user interaction is required.
When is the vulnerable race most likely to occur?
The race involves a thermal zone being unregistered while power-management completion or resume processing reinitializes or runs its poll_queue delayed work. If that work continues after the thermal zone object is freed, it can result in a use-after-free.