* [PATCH 6.6.y 0/2] jbd2: backport CVE-2026-89566, CVE-2026-89567
@ 2026-10-08 19:20 Artem Dinaburg
2026-10-08 19:20 ` [PATCH 6.6.y 1/2] jbd2: check need_resched() when skipping busy checkpoint buffers Artem Dinaburg
2026-10-08 19:20 ` [PATCH 6.6.y 2/2] jbd2: bound shrinker scans by examined " Artem Dinaburg
0 siblings, 2 replies; 3+ messages in thread
From: Artem Dinaburg @ 2026-10-08 19:20 UTC (permalink / raw)
To: stable
Cc: Artem Dinaburg, Greg Kroah-Hartman, Sasha Levin, Max Kellermann,
Zhang Yi, Jan Kara, Theodore Ts'o, Jan Kara, linux-ext4,
linux-kernel
Hi Greg, Sasha, and maintainers,
I'm working through the smaller CVE backports still missing from 6.6.y.
These 2 upstream changes belong together for CVE-2026-89566,
CVE-2026-89567. They must be applied in this order because the later change
depends on or completes the earlier one.
The complete series is already present in 6.12.y, 6.18.y, and 7.2.y.
These fixes also affect 6.1.y, which will need a separate backport; this
series is only for 6.6.y.
Could you please consider this series for 6.6.y?
Thanks,
Artem Dinaburg
Series:
1. jbd2: check need_resched() when skipping busy checkpoint buffers
2. jbd2: bound shrinker scans by examined checkpoint buffers
base: v6.6.157 (79643295eba17affbd16ca97f3ef04c90266b28c) plus stable-queue
revision 958ddf240a33ef26b1771be944f0ea6c3b597472
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 6.6.y 1/2] jbd2: check need_resched() when skipping busy checkpoint buffers
2026-10-08 19:20 [PATCH 6.6.y 0/2] jbd2: backport CVE-2026-89566, CVE-2026-89567 Artem Dinaburg
@ 2026-10-08 19:20 ` Artem Dinaburg
2026-10-08 19:20 ` [PATCH 6.6.y 2/2] jbd2: bound shrinker scans by examined " Artem Dinaburg
1 sibling, 0 replies; 3+ messages in thread
From: Artem Dinaburg @ 2026-10-08 19:20 UTC (permalink / raw)
To: stable
Cc: Artem Dinaburg, Greg Kroah-Hartman, Sasha Levin, Max Kellermann,
Zhang Yi, Jan Kara, Theodore Ts'o, Jan Kara, linux-ext4,
linux-kernel
From: Max Kellermann <max.kellermann@ionos.com>
[ Upstream commit f213e12ff5c9590b1034ae8da0e6d09665c772d0 ]
journal_shrink_one_cp_list() skips busy checkpoint buffers when called
with JBD2_SHRINK_BUSY_SKIP. The continue statement on this path also
skips the need_resched() check at the end of the loop body.
Consequently, when a checkpoint list contains mostly busy buffers, the
shrinker can walk the entire list while holding journal->j_list_lock,
even when a reschedule has been requested. Large checkpoint lists under
memory pressure can therefore cause long lock hold times and leave other
CPUs spinning on j_list_lock, resulting in soft lockups or RCU stalls.
Route the busy-buffer path through the need_resched() check so that the
shrinker can release j_list_lock and reschedule promptly, restoring
parity with the clean-buffer path, which already checks need_resched().
This does not change which checkpoint buffers are eligible for removal.
[ Backport to 6.6.y: Use this tree's older shrink_type enumerator names
while routing busy buffers through the existing reschedule check. ]
Fixes: b98dba273a0e ("jbd2: remove journal_clean_one_cp_list()")
Cc: stable@vger.kernel.org
Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260713102229.1598812-2-max.kellermann@ionos.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Assisted-by: LLM
Signed-off-by: Artem Dinaburg <artem@trailofbits.com>
---
This is patch 1 of 2 in the ordered 6.6.y backport series.
This change addresses CVE-2026-89566. Both targets skip the common
scheduling check on the busy-buffer continue path, allowing an unbounded
non-preemptible scan.
The fix is already present in 6.12.y, 6.18.y, and 7.2.y, but not in 6.6.y.
This fix also affects 6.1.y, which will need a separate backport; this
submission contains only the 6.6.y patch.
fs/jbd2/checkpoint.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
index 32ed28cfb3a0..e8a7186eb8c3 100644
--- a/fs/jbd2/checkpoint.c
+++ b/fs/jbd2/checkpoint.c
@@ -391,7 +391,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
ret = jbd2_journal_try_remove_checkpoint(jh);
if (ret < 0) {
if (type == SHRINK_BUSY_SKIP)
- continue;
+ goto next;
break;
}
}
@@ -402,6 +402,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
break;
}
+next:
if (need_resched())
break;
} while (jh != last_jh);
--
2.39.5
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 6.6.y 2/2] jbd2: bound shrinker scans by examined checkpoint buffers
2026-10-08 19:20 [PATCH 6.6.y 0/2] jbd2: backport CVE-2026-89566, CVE-2026-89567 Artem Dinaburg
2026-10-08 19:20 ` [PATCH 6.6.y 1/2] jbd2: check need_resched() when skipping busy checkpoint buffers Artem Dinaburg
@ 2026-10-08 19:20 ` Artem Dinaburg
1 sibling, 0 replies; 3+ messages in thread
From: Artem Dinaburg @ 2026-10-08 19:20 UTC (permalink / raw)
To: stable
Cc: Artem Dinaburg, Greg Kroah-Hartman, Sasha Levin, Max Kellermann,
Zhang Yi, Jan Kara, Theodore Ts'o, Jan Kara, linux-ext4,
linux-kernel
From: Max Kellermann <max.kellermann@ionos.com>
[ Upstream commit 15cb16496446b94e67f7abcb049b8e2c75cd3d02 ]
The jbd2 shrinker currently accounts only checkpoint buffers that it
successfully releases against nr_to_scan. Busy buffers therefore do not
consume the scan budget.
If a checkpoint transaction contains mostly busy buffers, the shrinker
can scan its entire checkpoint list while holding journal->j_list_lock.
Large checkpoint lists can result in excessive lock hold times and leave
other CPUs spinning on j_list_lock, causing soft lockups or RCU stalls.
Pass nr_to_scan into journal_shrink_one_cp_list() and decrement it for
every buffer examined, including busy buffers. Pass NULL from checkpoint
cleanup paths so their existing full-list behavior is preserved.
This restores the scan-budget semantics that existed before
journal_shrink_one_cp_list() was changed to always scan a complete
checkpoint list.
[ Backport to 6.6.y: use this tree's older shrink_type enumerator names;
the scan-budget accounting and caller changes are otherwise unchanged. ]
Fixes: b98dba273a0e ("jbd2: remove journal_clean_one_cp_list()")
Cc: stable@vger.kernel.org
Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260713102229.1598812-3-max.kellermann@ionos.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Assisted-by: LLM
Signed-off-by: Artem Dinaburg <artem@trailofbits.com>
---
This is patch 2 of 2 in the ordered 6.6.y backport series.
This change addresses CVE-2026-89567. Both jbd2 shrinkers decrement the
scan budget only for buffers actually freed, so busy checkpoint lists can
hold j_list_lock unboundedly; counting examined buffers restores shrinker
semantics.
This needed a target-specific adjustment; I called it out in the bracketed
backport note above.
The fix is already present in 6.12.y, 6.18.y, and 7.2.y, but not in 6.6.y.
This fix also affects 6.1.y, which will need a separate backport; this
submission contains only the 6.6.y patch.
fs/jbd2/checkpoint.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
index e8a7186eb8c3..0462101f683c 100644
--- a/fs/jbd2/checkpoint.c
+++ b/fs/jbd2/checkpoint.c
@@ -360,15 +360,16 @@ enum shrink_type {SHRINK_DESTROY, SHRINK_BUSY_STOP, SHRINK_BUSY_SKIP};
/*
* journal_shrink_one_cp_list
*
- * Find all the written-back checkpoint buffers in the given list
- * and try to release them. If the whole transaction is released, set
- * the 'released' parameter. Return the number of released checkpointed
- * buffers.
+ * Find written-back checkpoint buffers in the given list and try to release
+ * them. If 'nr_to_scan' is set, scan at most that many buffers. If the whole
+ * transaction is released, set the 'released' parameter. Return the number of
+ * released checkpointed buffers.
*
* Called with j_list_lock held.
*/
static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
enum shrink_type type,
+ unsigned long *nr_to_scan,
bool *released)
{
struct journal_head *last_jh;
@@ -377,13 +378,15 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
int ret;
*released = false;
- if (!jh)
+ if (!jh || (nr_to_scan && !*nr_to_scan))
return 0;
last_jh = jh->b_cpprev;
do {
jh = next_jh;
next_jh = jh->b_cpnext;
+ if (nr_to_scan)
+ (*nr_to_scan)--;
if (type == SHRINK_DESTROY) {
ret = __jbd2_journal_remove_checkpoint(jh);
@@ -405,7 +408,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
next:
if (need_resched())
break;
- } while (jh != last_jh);
+ } while (jh != last_jh && (!nr_to_scan || *nr_to_scan));
return nr_freed;
}
@@ -427,7 +430,6 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
tid_t first_tid = 0, last_tid = 0, next_tid = 0;
tid_t tid = 0;
unsigned long nr_freed = 0;
- unsigned long freed;
bool first_set = false;
again:
@@ -460,10 +462,9 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
next_transaction = transaction->t_cpnext;
tid = transaction->t_tid;
- freed = journal_shrink_one_cp_list(transaction->t_checkpoint_list,
- SHRINK_BUSY_SKIP, &released);
- nr_freed += freed;
- (*nr_to_scan) -= min(*nr_to_scan, freed);
+ nr_freed += journal_shrink_one_cp_list(transaction->t_checkpoint_list,
+ SHRINK_BUSY_SKIP,
+ nr_to_scan, &released);
if (*nr_to_scan == 0)
break;
if (need_resched() || spin_needbreak(&journal->j_list_lock))
@@ -515,7 +516,7 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
transaction = next_transaction;
next_transaction = transaction->t_cpnext;
journal_shrink_one_cp_list(transaction->t_checkpoint_list,
- type, &released);
+ type, NULL, &released);
/*
* This function only frees up some memory if possible so we
* dont have an obligation to finish processing. Bail out if
--
2.39.5
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-08 19:21 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-08 19:20 [PATCH 6.6.y 0/2] jbd2: backport CVE-2026-89566, CVE-2026-89567 Artem Dinaburg
2026-10-08 19:20 ` [PATCH 6.6.y 1/2] jbd2: check need_resched() when skipping busy checkpoint buffers Artem Dinaburg
2026-10-08 19:20 ` [PATCH 6.6.y 2/2] jbd2: bound shrinker scans by examined " Artem Dinaburg
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®