CVE-2026-89589
NoneCVSS
—
EPSS
0.2%
Published
Sep 11, 2026
CISA due date
—
Cloudanix analysis
A Linux kernel bug can freeze a server that uses certain high-speed memory hardware if a hardware error is reported at the same moment the system is starting or stopping its error-handling code.
- Exploitation
- Local Privilege
- Attacker needs
- Local User
- Complexity
- High
- Impact
- Denial Of Service
- Component
- OS kernel
- Class
- Race Condition
- Remediation
- Patch
- Effort
- Medium
- Patch risk
- Low
What it actually does
A lock-type and interrupt-safety mismatch in the Linux kernel ACPI APEI GHES CXL CPER path can deadlock a CPU. Registration and unregistration of CXL CPER work acquire cxl_cper_work_lock / cxl_cper_prot_err_work_lock with a normal spinlock while leaving local interrupts enabled, but the corresponding post paths run in hard IRQ context from GHES error notification and take the same locks with irqsave. If a GHES interrupt arrives on the CPU that already holds the lock, the IRQ handler spins forever on that lock while the lock holder is preempted by the IRQ. On PREEMPT_RT, spinlock_t is an rt_mutex, so the IRQ path can also attempt an illegal sleep in hard IRQ context. Related unregister races can schedule work against a pointer about to be freed, and stale kfifo entries can be replayed across module reload. The result is a kernel hang or crash in the hardware-error reporting path, not memory corruption or privilege escalation by itself.
Why it matters to the business
Availability is the primary risk: hosts that use CXL memory or CXL protocol-error reporting through ACPI GHES can freeze or panic when a hardware error notification races with CPER work setup or teardown, causing unplanned downtime, failed failovers, and interrupted workloads on affected servers. This is not listed in CISA KEV, has no associated ransomware use, and has no public exploit maturity. EPSS remains very low and flat (~0.00175, unchanged over 30 days), so mass opportunistic exploitation is unlikely. Urgency is still meaningful for CXL-equipped fleets and PREEMPT_RT / real-time kernels because a single induced or natural GHES event can take a machine down, but it is not an emergency patch-now internet-facing RCE. No named downstream package count or vendor fixed-version list was supplied, so exposure is determined by whether running kernels include the unfixed ACPI/APEI/GHES CXL CPER locking code.
How an attack unfolds
This issue is an in-kernel deadlock and teardown race, not a remote code-execution primitive. An attacker who can run code on the host, load or unload CXL-related modules, or otherwise cause CXL CPER work to be registered or unregistered at the same time a GHES/CXL error notification fires on the same CPU can complete the race: process context holds the non-raw spinlock with interrupts enabled, the hard-IRQ post path (cxl_cper_post_event or cxl_cper_post_prot_err) tries to take the same lock, and that CPU livelocks. On PREEMPT_RT the same sequence can hit a sleeping lock from IRQ context and crash. A parallel teardown window lets an interrupt schedule work on a work_struct that is being cancelled or freed, producing a hang or use-after-free in the error-work path. No threat actors or campaigns are associated with this CVE. Reliable triggering typically needs local influence over CXL/GHES activity plus timing, so real-world abuse is expected to look like denial of service or an induced panic rather than persistence or data theft.
How to fix it
Apply the upstream Linux kernel fix that converts cxl_cper_work_lock and cxl_cper_prot_err_work_lock from spinlock_t to raw_spinlock_t and uses lock guards consistently at every call site so the GHES hard-IRQ post path cannot deadlock or sleep. Take the companion hardening in the same change: WARN_ONCE on double registration, clear the global work pointer under the lock before cancel_work_sync() in both unregister helpers, kfifo_reset() after cancel so stale CPER entries are not replayed on the next module load, and drop the redundant cancel_work_sync() calls from cxl_ras_exit() and cxl_pci_driver_exit(). Deploy a vendor or distro kernel that contains this commit; no per-package fixed versions were provided in the advisory input, so confirm via kernel changelog, git commit presence, or vendor security tracker rather than a version number guess. Until patched, avoid unnecessary CXL driver bind/unbind and module reload on GHES/CXL hosts, and treat PREEMPT_RT CXL systems as higher priority. Reboot into the patched kernel; this is not a live userspace-only mitigation.
How to confirm the fix worked
Confirm the running kernel includes the raw_spinlock_t conversion and unregister restructure (search kernel source or debug symbols for raw_spinlock_t on the CXL CPER work locks, WARN_ONCE in the register helpers, kfifo_reset after cancel_work_sync, and absence of the extra cancel_work_sync in cxl_ras_exit/cxl_pci_driver_exit). After upgrade, reboot and verify uname/package changelog against the distro advisory. On a non-production host only, exercise CXL CPER register/unregister and GHES notification paths and confirm no soft/hard lockups and no scheduling-while-atomic warnings. Inventory remaining unpatched kernels that have CONFIG_ACPI_APEI_GHES and CXL CPER support enabled. Do not attempt to reproduce the deadlock on production systems.
Typical attack path
- Obtain local execution or equivalent control on a Linux host whose kernel still uses spinlock_t for CXL CPER work locks and that has ACPI GHES plus CXL CPER posting enabled.
- Cause CXL CPER work registration or unregistration (for example via CXL/APEI driver bind, unbind, or module teardown) so a CPU holds cxl_cper_work_lock or cxl_cper_prot_err_work_lock with local interrupts still enabled.
- Arrange or wait for a GHES hardware-error notification on that same CPU so cxl_cper_post_event() or cxl_cper_post_prot_err() runs in hard IRQ context and tries to acquire the held lock.
- Alternatively, unregister while a CPER interrupt can still schedule work, hitting the window where the global work pointer is still live but the consumer is being torn down.
- The CPU deadlocks or the kernel panics/sleeps in IRQ context (especially on PREEMPT_RT), taking the host offline.
How to detect it
There is no in-the-wild exploitation, named actor, or ransomware association to hunt for. Look instead for evidence the deadlock or teardown race already fired: kernel ring buffer, serial/console logs, kdump/vmcore, hung_task and NMI/soft-lockup watchdog reports, and panic traces. Stacks of interest mention GHES notification, APEI, cxl_cper_post_event, cxl_cper_post_prot_err, CXL CPER work registration/unregistration, or cancel_work_sync around cxl_ras / cxl_pci teardown. On PREEMPT_RT, also search for scheduling-while-atomic or sleeping-from-IRQ warnings on those locks. Correlate lockups with CXL module load/unload, driver unbind, or hardware-error storms. Absent those artifacts, treat the host as unpatched-exposure rather than confirmed compromise.
- cxl_cper_post_event
- cxl_cper_post_prot_err
- cxl_cper_work_lock
- cxl_cper_prot_err_work_lock
- cxl_ras_exit
- cxl_pci_driver_exit
- watchdog: BUG: soft lockup
- NMI watchdog: Watchdog detected hard LOCKUP
- BUG: scheduling while atomic
- hung_task: blocked for more than
- ghes_proc
- ACPI: APEI
What your security team should do
- Prioritize kernel updates on CXL-capable and PREEMPT_RT systems that enable ACPI APEI GHES CPER posting; this is an availability defect, not a KEV/ransomware emergency.
- Identify hosts with CXL and GHES/APEI enabled and track them until the raw_spinlock_t CPER-lock fix is installed and the box is rebooted.
- Freeze non-essential CXL driver reloads and module unload cycles on unpatched kernels to shrink the register/unregister race window.
- Watch for kernel lockups and hung-task reports in GHES/CXL stacks as a stand-in signal until patch compliance is complete.
- Re-verify after patching that unregister no longer races with IRQ posting and that kfifo state is cleared across module reload.
The record
In the Linux kernel, the following vulnerability has been resolved: acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks The CXL CPER work registration and unregistration helpers acquire cxl_cper_work_lock and cxl_cper_prot_err_work_lock with a spinlock guard(), which leaves local interrupts enabled. The corresponding post paths (cxl_cper_post_event(), cxl_cper_post_prot_err()) 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 spinlock_t to raw_spinlock_t and use guard() at all call sites. On PREEMPT_RT kernels spinlock_t is backed by rt_mutex and sleeping from hard IRQ context is not permitted; raw_spinlock_t is safe in both contexts. Add WARN_ONCE 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 cancel_work_sync(), closing the window where a CPER interrupt could schedule work on a pointer about to be freed. Add kfifo_reset() after cancel_work_sync() so stale entries are not replayed on next module load. Both kfifos are single-consumer: only one work_struct is registered at a time, enforced by the WARN_ONCE guard in the register functions. kfifo_reset() is safe outside the lock because cancel_work_sync() 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 cancel_work_sync() call from cxl_ras_exit() and cxl_pci_driver_exit(). The CPER unregister functions now quiesce the work internally.
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|