CVE-2026-89655
Critical · 9.8CVSS
9.8
EPSS
0.7%
Published
Sep 11, 2026
CISA due date
—
Cloudanix analysis
A race condition in Linux storage code can let attackers crash systems or run malicious code by sending storage messages at exactly the wrong moment.
- Exploitation
- Local Privilege
- Attacker needs
- Local User
- Complexity
- Moderate
- Impact
- Full Compromise
- Component
- OS kernel
- Class
- Use After Free
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
Use-after-free during list iteration in ceph cap flushing logic: __kick_flushing_caps drops i_ceph_lock, allowing handle_cap_flush_ack to detach and free cf entries; the loop then dereferences the freed cf->i_list.next pointer.
Why it matters to the business
Linux systems using Ceph may experience kernel crashes or arbitrary code execution from network-triggered races, leading to service outages and potential full host compromise in storage clusters.
How an attack unfolds
An attacker interacts with a Ceph MDS to trigger rapid FLUSH/FLUSH_ACK exchanges while a kernel thread is iterating the cap flush list, freeing an entry under the attacker-controlled timing window and causing the original thread to access freed memory on list advance.
How to fix it
Apply the upstream fix that replaces list_for_each_entry with a manual while loop saving the next pointer under lock before any unlock; rebuild and deploy the patched kernel on all Ceph clients.
How to confirm the fix worked
Confirm the patch is present by inspecting __kick_flushing_caps for the manual while-loop pattern with saved next pointer; run targeted stress tests exercising concurrent cap flushes and acks; verify no UAF reports in kernel logs under load.
Typical attack path
- Establish Ceph client connection to MDS
- Trigger cap flush operations that populate i_cap_flush_list
- Send or induce quick FLUSH_ACK responses while lock is dropped
- Force the victim thread to advance the now-stale list entry
- Dereference freed memory to achieve UAF primitive
How to detect it
Search kernel logs and dmesg for ceph-related oops, use-after-free warnings, or list corruption panics occurring shortly after MDS cap flush activity; correlate with Ceph client connection and ack traffic in network captures.
- BUG: KASAN: use-after-free in __kick_flushing_caps
- list_next_entry.*ceph.*cap
- ceph_free_cap_flush.*called under lock contention
What your security team should do
- Immediately upgrade all Ceph client kernels to a version containing the fix
- Prioritize Ceph storage clusters and any systems mounting CephFS
- Enable kernel hardening features such as KASAN in test environments to catch similar issues
- Monitor for kernel oops or panic events related to ceph cap lists
The record
In the Linux kernel, the following vulnerability has been resolved: ceph: fix UAF in __kick_flushing_caps() on cf entry freed during unlock list_for_each_entry() iterates ci->i_cap_flush_list but drops i_ceph_lock to send cap messages. During the unlock window, handle_cap_flush_ack() can acquire i_ceph_lock, detach cf entries with tid <= flush_tid from the list, release i_ceph_lock, and free them via ceph_free_cap_flush() outside any lock. When the original thread reacquires i_ceph_lock and the for-loop macro advances via cf = list_next_entry(cf, i_list), it dereferences cf->i_list.next on freed memory. The race timeline: __kick_flushing_caps() handle_cap_flush_ack() ----------------------- ----------------------- holds i_ceph_lock <--- iterates to cf (tid=10) prepares FLUSH message drops i_ceph_lock <--- __send_cap() ── FLUSH(tid=10) MDS sends FLUSH_ACK(tid=10) ---> acquires i_ceph_lock cf->tid(10) <= flush_tid(10), detaches cf from i_cap_flush_list drops i_ceph_lock ceph_free_cap_flush(cf) <- frees it! acquires i_ceph_lock <--- for-loop advances: cf = list_next_entry(cf, i_list) -- UAF on freed cf->i_list.next The cf was just sent by __kick_flushing_caps itself via __send_cap(). The MDS may respond with FLUSH_ACK quickly enough that handle_cap_flush_ack() frees cf before __kick_flushing_caps can finish the iteration. Fix by converting to a manual while loop: save the next pointer under i_ceph_lock before dropping it, then use the saved pointer after reacquiring, so the potentially-freed cf is never accessed again.
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|