GHSA-MRGJ-88F9-5G2F
Vulnerability from github – Published: 2026-06-24 18:32 – Updated: 2026-06-24 18:32In the Linux kernel, the following vulnerability has been resolved:
fsnotify: fix inode reference leak in fsnotify_recalc_mask()
fsnotify_recalc_mask() fails to handle the return value of __fsnotify_recalc_mask(), which may return an inode pointer that needs to be released via fsnotify_drop_object() when the connector's HAS_IREF flag transitions from set to cleared.
This manifests as a hung task with the following call trace:
INFO: task umount:1234 blocked for more than 120 seconds. Call Trace: __schedule schedule fsnotify_sb_delete generic_shutdown_super kill_anon_super cleanup_mnt task_work_run do_exit do_group_exit
The race window that triggers the iref leak:
Thread A (adding mark) Thread B (removing mark) ────────────────────── ──────────────────────── fsnotify_add_mark_locked(): fsnotify_add_mark_list(): spin_lock(conn->lock) add mark_B(evictable) to list spin_unlock(conn->lock) return
/* ---- gap: no lock held ---- */
fsnotify_detach_mark(mark_A):
spin_lock(mark_A->lock)
clear ATTACHED flag on mark_A
spin_unlock(mark_A->lock)
fsnotify_put_mark(mark_A)
fsnotify_recalc_mask():
spin_lock(conn->lock)
__fsnotify_recalc_mask():
/* mark_A skipped: ATTACHED cleared */
/* only mark_B(evictable) remains */
want_iref = false
has_iref = true /* not yet cleared */
-> HAS_IREF transitions true -> false
-> returns inode pointer
spin_unlock(conn->lock)
/* BUG: return value discarded!
* iput() and fsnotify_put_sb_watched_objects()
* are never called */
Fix this by deferring the transition true -> false of HAS_IREF flag from fsnotify_recalc_mask() (Thread A) to fsnotify_put_mark() (thread B).
{
"affected": [],
"aliases": [
"CVE-2026-52990"
],
"database_specific": {
"cwe_ids": [],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-06-24T17:17:09Z",
"severity": null
},
"details": "In the Linux kernel, the following vulnerability has been resolved:\n\nfsnotify: fix inode reference leak in fsnotify_recalc_mask()\n\nfsnotify_recalc_mask() fails to handle the return value of\n__fsnotify_recalc_mask(), which may return an inode pointer that needs\nto be released via fsnotify_drop_object() when the connector\u0027s HAS_IREF\nflag transitions from set to cleared.\n\nThis manifests as a hung task with the following call trace:\n\n INFO: task umount:1234 blocked for more than 120 seconds.\n Call Trace:\n __schedule\n schedule\n fsnotify_sb_delete\n generic_shutdown_super\n kill_anon_super\n cleanup_mnt\n task_work_run\n do_exit\n do_group_exit\n\nThe race window that triggers the iref leak:\n\n Thread A (adding mark) Thread B (removing mark)\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n fsnotify_add_mark_locked():\n fsnotify_add_mark_list():\n spin_lock(conn-\u003elock)\n add mark_B(evictable) to list\n spin_unlock(conn-\u003elock)\n return\n\n /* ---- gap: no lock held ---- */\n\n fsnotify_detach_mark(mark_A):\n spin_lock(mark_A-\u003elock)\n clear ATTACHED flag on mark_A\n spin_unlock(mark_A-\u003elock)\n fsnotify_put_mark(mark_A)\n\n fsnotify_recalc_mask():\n spin_lock(conn-\u003elock)\n __fsnotify_recalc_mask():\n /* mark_A skipped: ATTACHED cleared */\n /* only mark_B(evictable) remains */\n want_iref = false\n has_iref = true /* not yet cleared */\n -\u003e HAS_IREF transitions true -\u003e false\n -\u003e returns inode pointer\n spin_unlock(conn-\u003elock)\n /* BUG: return value discarded!\n * iput() and fsnotify_put_sb_watched_objects()\n * are never called */\n\nFix this by deferring the transition true -\u003e false of HAS_IREF flag from\nfsnotify_recalc_mask() (Thread A) to fsnotify_put_mark() (thread B).",
"id": "GHSA-mrgj-88f9-5g2f",
"modified": "2026-06-24T18:32:42Z",
"published": "2026-06-24T18:32:42Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-52990"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/4aca914ac152f5d055ddcb36704d1e539ac08977"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/5c80289503da3658e3df80280598c68d181eadbd"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/8c8afa6444e6bdc145d2bf2f3aeeca6da3e36b42"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/b740cc86816bbc87902ae9db74cd21abde3c8d63"
}
],
"schema_version": "1.4.0",
"severity": []
}
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.