GHSA-67R3-HJ2C-67VV
Vulnerability from github – Published: 2026-09-11 21:31 – Updated: 2026-09-14 15:32In 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": [],
"aliases": [
"CVE-2026-89655"
],
"database_specific": {
"cwe_ids": [],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-09-11T20:19:51Z",
"severity": "CRITICAL"
},
"details": "In the Linux kernel, the following vulnerability has been resolved:\n\nceph: fix UAF in __kick_flushing_caps() on cf entry freed during unlock\n\nlist_for_each_entry() iterates ci-\u003ei_cap_flush_list but drops\ni_ceph_lock to send cap messages. During the unlock window,\nhandle_cap_flush_ack() can acquire i_ceph_lock, detach cf entries\nwith tid \u003c= flush_tid from the list, release i_ceph_lock, and free\nthem via ceph_free_cap_flush() outside any lock. When the original\nthread reacquires i_ceph_lock and the for-loop macro advances via\ncf = list_next_entry(cf, i_list), it dereferences cf-\u003ei_list.next\non freed memory.\n\nThe race timeline:\n\n __kick_flushing_caps() handle_cap_flush_ack()\n ----------------------- -----------------------\n holds i_ceph_lock \u003c---\n iterates to cf (tid=10)\n prepares FLUSH message\n drops i_ceph_lock \u003c---\n __send_cap() \u2500\u2500 FLUSH(tid=10)\n\t MDS sends FLUSH_ACK(tid=10)\n ---\u003e acquires i_ceph_lock\n cf-\u003etid(10) \u003c= flush_tid(10),\n detaches cf from i_cap_flush_list\n drops i_ceph_lock\n ceph_free_cap_flush(cf) \u003c- frees it!\n acquires i_ceph_lock \u003c---\n for-loop advances:\n cf = list_next_entry(cf, i_list)\n -- UAF on freed cf-\u003ei_list.next\n\nThe cf was just sent by __kick_flushing_caps itself via __send_cap().\nThe MDS may respond with FLUSH_ACK quickly enough that\nhandle_cap_flush_ack() frees cf before __kick_flushing_caps can\nfinish the iteration.\n\nFix by converting to a manual while loop: save the next pointer\nunder i_ceph_lock before dropping it, then use the saved pointer\nafter reacquiring, so the potentially-freed cf is never accessed again.",
"id": "GHSA-67r3-hj2c-67vv",
"modified": "2026-09-14T15:32:33Z",
"published": "2026-09-11T21:31:35Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-89655"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/01542430081014d80fc9e70e92d6647432ddb7fc"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/091137821e1fc88f37e15201abf055c9494ddc61"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/19f16f04c2b014a7dd214dc1e42557d8530b16f3"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/23eb34a53a53cb1a6dab1eeee830633207ac158d"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/2701431aa3cc8b23efe6890182e7b04f5e76fab5"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/2dba24dcd5050be4b7b119e6f0b01f62203b5d26"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/7af4c4f01305b0935adf6d4301b1ec407025485d"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/fe46746087b5b9c5bb2d022df6c7819218494ced"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
How durations are calculated
Following the VTEM framework (Black Hat USA 2015), time to patch starts when the vendor or a coordinator was informed, total time to patch at discovery, and disclosure to patch at public disclosure; vendor response time runs from the report to its acknowledgement. Time to exploit and time unpatched start at the earliest discovery or report, falling back to public disclosure. Unpatched time ends at the first recorded patch, or the calculation time when no patch is recorded. Exploitation to patch shows the interval between those two events; a published proof of concept is a public exploit, not exploitation.
Each result shows its source dates. A negative interval means the end event came first; when date-only inputs leave the order open, the result says so. Date-only inputs are approximate. The earliest evidence wins: KEV report dates and sightings are labelled as such. Records describing another vulnerability are listed but never calculated from, and a PoC alone does not establish exploitation. Missing patch evidence does not prove that no patch exists. Filters below change the event list only.
Loading timeline…
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.