CVE-2026-89589: acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks

Published Sep 11, 2026
·
Updated

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

1 affected component
Linux Linux kernel

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Configuration

    Change both locks cxl_cper_work_lock and cxl_cper_prot_err_work_lock from spinlock_t to raw_spinlock_t.

    Linux kernel (cxl/CPER work registration helpers; acpi/apei/ghes) Use raw_spinlock_t for cxl_cper_work_lock and cxl_cper_prot_err_work_lock (instead of spinlock_t) = raw_spinlock_t
  2. Configuration

    In all call sites from both the GHES error notification path (IRQ/CPER context) and normal contexts, acquire the CXL CPER work locks using guard() with irqsave.

    Linux kernel (cxl/CPER work registration helpers; acpi/apei/ghes) Lock acquisition at IRQ context = irqsave guard()
  3. Configuration

    Add WARN_ONCE to both CPER work register functions to surface double-registration (enforced by WARN_ONCE guard in the register functions).

    Linux kernel (CXL CPER work unregister/register helpers) register helper double-registration detection = Add WARN_ONCE to both register functions
  4. Configuration

    In both unregister paths, call kfifo_reset() after cancel_work_sync() so stale entries are cleared.

    Linux kernel (CXL CPER work unregister helpers) kfifo_reset after cancel_work_sync = Call kfifo_reset() after cancel_work_sync()
  5. Configuration

    Remove the redundant cancel_work_sync() call from cxl_ras_exit().

    Linux kernel (cxl/CPER work unregistration) Remove redundant cancel_work_sync() call = Remove extra cancel_work_sync() in cxl_ras_exit()
  6. Configuration

    Restructure both unregister functions to clear the global work pointer; the CPER unregister functions should quiesce and clear global work pointers so consumers can’t schedule work on pointers about to be freed.

    Linux kernel (CXL CPER unregister helpers) Restructure unregister functions to clear global work pointer = Clear global work pointer during CPER unregister
  7. Compensating control

    Ensure unregister quiesces the consumer so no new consumer can register until module exit completes and a fresh module init can run (prevents replay/scheduling bugs at runtime).

Event History

Sep 11, 2026
CVE Published
via MITRE·07:44 PM
Data Sourced
via MITRE·07:44 PM
Description

Frequently Asked Questions

1

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.

2

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.

3

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.

4

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.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203