CVE-2026-45861
Description
In the Linux kernel, the following vulnerability has been resolved:
gfs2: Fix slab-use-after-free in qd_put
Commit a475c5dd16e5 ("gfs2: Free quota data objects synchronously") started freeing quota data objects during filesystem shutdown instead of putting them back onto the LRU list, but it failed to remove these objects from the LRU list, causing LRU list corruption. This caused use-after-free when the shrinker (gfs2_qd_shrink_scan) tried to access already-freed objects on the LRU list.
Fix this by removing qd objects from the LRU list before freeing them in qd_put().
Initial fix from Deepanshu Kartikey <kartikey406@gmail.com>.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A use-after-free in Linux kernel's GFS2 occurs when quota data objects are freed without LRU removal, allowing the shrinker to access freed memory.
Vulnerability
In the Linux kernel's GFS2 filesystem, a slab-use-after-free vulnerability exists in the qd_put function. Commit a475c5dd16e5 ("gfs2: Free quota data objects synchronously") introduced a change that frees quota data objects during filesystem shutdown instead of returning them to the LRU list. However, it failed to remove these objects from the LRU list before freeing, leading to LRU list corruption. This allows the shrinker (gfs2_qd_shrink_scan) to access already-freed objects, causing a use-after-free. The vulnerability affects versions that include the problematic commit. The fix is in commit 80fff26d7a0c [1].
Exploitation
An attacker would need to trigger filesystem shutdown (e.g., unmount) while the shrinker is active. The race condition occurs when the shrinker scans the LRU list and encounters a freed qd object. No special privileges are required beyond the ability to mount and unmount a GFS2 filesystem. The exploitation sequence involves causing the filesystem to shut down while the shrinker is running, leading to access of freed memory.
Impact
Successful exploitation results in a use-after-free condition, which can lead to memory corruption, system crash (denial of service), or potentially arbitrary code execution in kernel context. The attacker gains the ability to corrupt kernel memory, potentially escalating privileges or causing instability.
Mitigation
The fix is included in commit 80fff26d7a0c ("gfs2: Fix slab-use-after-free in qd_put") applied to the Linux kernel stable tree [1]. Users should update to a kernel version containing this commit. No workaround is available; the vulnerability must be patched. The CVE is not listed on CISA's Known Exploited Vulnerabilities (KEV) catalog as of publication.
AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
1Patches
81d47922b9804gfs2: Fix slab-use-after-free in qd_put
2 files changed · +2 −2
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index f2df01f801b811..898fc3937b4497 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -334,6 +334,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index f2df01f801b811..898fc3937b4497 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -334,6 +334,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
80fff26d7a0cgfs2: Fix slab-use-after-free in qd_put
2 files changed · +2 −2
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index b1692f12a602a6..2b499b554e876a 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -334,6 +334,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index b1692f12a602a6..2b499b554e876a 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -334,6 +334,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
22150a7d401dgfs2: Fix slab-use-after-free in qd_put
2 files changed · +2 −2
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 21dfe1e48da6e1..1c3455093ae8c2 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -334,6 +334,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 21dfe1e48da6e1..1c3455093ae8c2 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -334,6 +334,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
ca7c67bdd293gfs2: Fix slab-use-after-free in qd_put
2 files changed · +2 −2
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 642584265a6f45..95b20e6a3fbc60 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -336,6 +336,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 642584265a6f45..95b20e6a3fbc60 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -336,6 +336,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
22150a7d401dgfs2: Fix slab-use-after-free in qd_put
2 files changed · +2 −2
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 21dfe1e48da6e1..1c3455093ae8c2 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -334,6 +334,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 21dfe1e48da6e1..1c3455093ae8c2 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -334,6 +334,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
80fff26d7a0cgfs2: Fix slab-use-after-free in qd_put
2 files changed · +2 −2
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index b1692f12a602a6..2b499b554e876a 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -334,6 +334,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index b1692f12a602a6..2b499b554e876a 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -334,6 +334,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
ca7c67bdd293gfs2: Fix slab-use-after-free in qd_put
2 files changed · +2 −2
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 642584265a6f45..95b20e6a3fbc60 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -336,6 +336,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 642584265a6f45..95b20e6a3fbc60 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -336,6 +336,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
1d47922b9804gfs2: Fix slab-use-after-free in qd_put
2 files changed · +2 −2
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index f2df01f801b811..898fc3937b4497 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -334,6 +334,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
fs/gfs2/quota.c+1 −1 modifieddiff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index f2df01f801b811..898fc3937b4497 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -334,6 +334,7 @@ static void qd_put(struct gfs2_quota_data *qd) lockref_mark_dead(&qd->qd_lockref); spin_unlock(&qd->qd_lockref.lock); + list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); gfs2_qd_dispose(qd); return; } -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"Missing LRU list removal before freeing quota data objects in qd_put() leads to slab-use-after-free."
Attack vector
An attacker can trigger this use-after-free by causing the GFS2 filesystem to shut down while quota data objects are still present on the LRU list. During shutdown, `qd_put()` frees quota data objects synchronously without removing them from the LRU list. Subsequently, the shrinker (`gfs2_qd_shrink_scan`) traverses the now-stale LRU list and accesses already-freed objects, leading to slab-use-after-free. No special network path or authentication is required beyond the ability to trigger a GFS2 filesystem shutdown.
Affected code
The vulnerability is in the `qd_put()` function in `fs/gfs2/quota.c`. The function frees quota data (`qd`) objects during filesystem shutdown via `gfs2_qd_dispose()` but fails to first remove them from the global LRU list (`gfs2_qd_lru`).
What the fix does
The patch adds a single line — `list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru);` — before the call to `gfs2_qd_dispose(qd)` in `qd_put()` [patch_id=2661990]. This ensures the quota data object is removed from the LRU list before it is freed, preventing the shrinker from later iterating over a dangling pointer. The fix is minimal and directly addresses the root cause: the missing LRU list removal introduced by commit a475c5dd16e5.
Preconditions
- inputThe GFS2 filesystem must be shut down (triggering the synchronous free path in qd_put)
- configQuota data objects must exist on the LRU list at the time of shutdown
Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4News mentions
0No linked articles in our index yet.