CVE-2026-89589: acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks
In the Linux kernel, the following vulnerability has been resolved:
acpi/apei/ghes: Use rawspinlockt for CXL CPER work locks
The CXL CPER work registration and unregistration helpers acquire cxlcperworklock and cxlcperproterrworklock with a spinlock guard(), which leaves local interrupts enabled. The corresponding post paths (cxlcperpostevent(), cxlcperpostproterr()) execute in hard IRQ context (they are called from the GHES error notification path) and acquire the same locks with an irqsave guard().
If a CPU is holding one of these locks via a spinlock guard() when a GHES interrupt arrives on the same CPU, the IRQ handler spins on the held lock waiting for it to release, while the lock holder is preempted by the IRQ. The result is a deadlock.
Convert both locks from spinlockt to rawspinlockt and use guard() at all call sites. On PREEMPTRT kernels spinlockt is backed by rtmutex and sleeping from hard IRQ context is not permitted; rawspinlockt is safe in both contexts.
Add WARNONCE to both register functions to surface double-registration bugs at runtime.
Restructure both unregister functions to clear the global work pointer under the lock before calling cancelworksync(), closing the window where a CPER interrupt could schedule work on a pointer about to be freed. Add kfiforeset() after cancelworksync() so stale entries are not replayed on next module load.
Both kfifos are single-consumer: only one workstruct is registered at a time, enforced by the WARNONCE guard in the register functions. kfiforeset() is safe outside the lock because cancelworksync() has already quiesced the consumer, and no new consumer can register until the current module exit completes and a fresh module init runs.
Remove the redundant cancelworksync() call from cxlrasexit() and cxlpcidriverexit(). The CPER unregister functions now quiesce the work internally.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
debian/linuxto a version that resolves this vulnerability.Fixed in 6.1.176-1Fixed in 6.1.190-1Fixed in 6.12.115-2Fixed in 7.2.12-1Fixed in 7.2.15-1 - Upgrade
Upgrade
debian/linux-6.12to a version that resolves this vulnerability.Fixed in 6.12.113-1~deb12u1 - Upgrade
Upgrade
ubuntu/linux-hwe-7.0to a version that resolves this vulnerability.Fixed in 7.0.0-42.42~24.04.1 - Upgrade
Upgrade
ubuntu/linux-riscv-7.0to a version that resolves this vulnerability.Fixed in 7.0.0-42.42.1~24.04.1 - Upgrade
Upgrade
ubuntu/linuxto a version that resolves this vulnerability.Fixed in 7.0.0-42.42 - Upgrade
Upgrade
ubuntu/linux-awsto a version that resolves this vulnerability.Fixed in 7.0.0-1016.17 - Upgrade
Upgrade
ubuntu/linux-gcpto a version that resolves this vulnerability.Fixed in 7.0.0-1016.18 - Upgrade
Upgrade
ubuntu/linux-ibmto a version that resolves this vulnerability.Fixed in 7.0.0-1017.17 - Upgrade
Upgrade
ubuntu/linux-oem-7.0to a version that resolves this vulnerability.Fixed in 7.0.0-1017.17 - Upgrade
Upgrade
ubuntu/linux-oracleto a version that resolves this vulnerability.Fixed in 7.0.0-1015.16 - Upgrade
Upgrade
ubuntu/linux-riscvto a version that resolves this vulnerability.Fixed in 7.0.0-42.42.1 - Compensating control
Convert cxl_cper_work_lock and cxl_cper_prot_err_work_lock from spinlock_t to raw_spinlock_t, and use irqsave guard() at the hard-IRQ call sites cxl_cper_post_event() and cxl_cper_post_prot_err().
- Compensating control
Add WARN_ONCE guards to both CPER work registration functions to detect double registration at runtime.
- Compensating control
In both unregister functions, clear the global work pointer while holding the lock before calling cancel_work_sync(), preventing CPER interrupts from scheduling work through a pointer about to be freed.
- Compensating control
Call kfifo_reset() after cancel_work_sync() so stale FIFO entries are not replayed on the next module load.
- Compensating control
Remove the redundant cancel_work_sync() calls from cxl_ras_exit() and cxl_pci_driver_exit().
Event History
Frequently Asked Questions
Which systems are exposed to this deadlock condition?
Systems using the Linux kernel's CXL CPER work registration paths and receiving GHES error notifications are relevant. The deadlock requires a GHES interrupt to arrive on a CPU while that CPU holds one of the affected CXL CPER work locks.
What is required to trigger the failure?
A CPU must hold cxl_cper_work_lock or cxl_cper_prot_err_work_lock with local interrupts enabled, then receive a GHES interrupt on that same CPU. The hard-IRQ handler attempts to acquire the same lock and can spin indefinitely while preempting the lock holder.
Why are PREEMPT_RT kernels specifically relevant?
On PREEMPT_RT kernels, spinlock_t is backed by an rt_mutex, which cannot safely be used from hard IRQ context because it may sleep. The resolution changes the affected locks to raw_spinlock_t so they are safe in both normal and hard-IRQ contexts.
Is there an indication of duplicate CXL CPER work registration after the fix?
The resolved code adds WARN_ONCE checks to both registration functions. These warnings are intended to expose double-registration bugs at runtime.