FAILED: patch "[PATCH] xfs: fix cursor and pointer handling when recovering iunlink" failed to apply to 6.6-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x 65f39d09d73718611cee40399179323b5d4ead00
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026092920-booth-deluge-dbf3@gregkh' --subject-prefix 'PATCH 6.6.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 65f39d09d73718611cee40399179323b5d4ead00 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <[email protected]>
Date: Mon, 14 Sep 2026 22:38:38 -0700
Subject: [PATCH] xfs: fix cursor and pointer handling when recovering iunlink
buckets
LOLLM pointed out a bug in xlog_recover_iunlink_bucket:
1. We don't null out prev_ip after releasing it, which can lead to UAF problems if the inodegc flush call in the loop fails.
at which point I noticed even more bugs:
2. If the inodegc flush inside the loop fails, we also leak @ip.
3. We set prev_agino to agino having already advanced agino, which results in inodes with i_prev_unlinked set to itself.
4. If we exit the bottom of the loop with prev_ip set, then prev_ip aliases ip and we also set its i_prev_unlinked to itself.
Bugs 3 and 4 introduce loops into the unlinked list, though these loops don't surface because we immediately flush each unlinked inode after loading it.
Fix all of these issues.
fs/xfs/xfs_log_recover.c +8 -5
@@ -2736,12 +2736,13 @@ xlog_recover_iunlink_bucket( {struct xfs_mount *mp =pag_mount (pag);struct xfs_inode *prev_ip =NULL ; -struct xfs_inode *ip;xfs_agino_t prev_agino, agino;int error =0 ; agino =be32_to_cpu (agi->agi_unlinked[bucket]);while (agino !=NULLAGINO ) { +struct xfs_inode *ip; + error =xfs_iget (mp,NULL ,xfs_agino_to_ino (pag, agino),0 ,0 , &ip);if (error)
@@ -2750,11 +2751,11 @@ xlog_recover_iunlink_bucket(ASSERT (VFS_I (ip)->i_nlink ==0 );ASSERT (VFS_I (ip)->i_mode !=0 );xfs_iflags_clear (ip,XFS_IRECOVERY ); - agino = ip->i_next_unlinked;if (prev_ip) { ip->i_prev_unlinked = prev_agino;xfs_irele (prev_ip); + prev_ip =NULL ;/* * Ensure the inode is removed from the unlinked list
@@ -2766,18 +2767,20 @@ xlog_recover_iunlink_bucket(* complete. */ error =xfs_inodegc_flush (mp); -if (error) -break ; +if (error) { +xfs_irele (ip); +return error; + } } prev_agino = agino; + agino = ip->i_next_unlinked; prev_ip = ip; }if (prev_ip) {int error2; - ip->i_prev_unlinked = prev_agino;xfs_irele (prev_ip); error2 =xfs_inodegc_flush (mp);
Sasha Levin
maintainerPATCH 1/2 xfs: pass a pag to xfs_difree_inode_chunk
From: Christoph Hellwig <[email protected]>
[ Upstream commit 67ce5ba575354da1542e0579fb8c7a871cbf57b3 ]
We'll want to use more than just the agno field in a bit.
Stable-dep-of: 65f39d09d737 ("xfs: fix cursor and pointer handling when recovering iunlink buckets")
--- fs/xfs/libxfs/xfs_ialloc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/xfs/libxfs/xfs_ialloc.c +3 -2
@@ -1837,10 +1837,11 @@ xfs_dialloc(static int xfs_difree_inode_chunk (struct xfs_trans *tp, -xfs_agnumber_t agno, +struct xfs_perag *pag,struct xfs_inobt_rec_incore *rec) {struct xfs_mount *mp = tp->t_mountp; +xfs_agnumber_t agno = pag->pag_agno;xfs_agblock_t sagbno =XFS_AGINO_TO_AGBNO (mp, rec->ir_startino);int startidx, endidx;
@@ -2009,7 +2010,7 @@ xfs_difree_inobt( goto error0; } - error =xfs_difree_inode_chunk (tp, pag->pag_agno, &rec); + error =xfs_difree_inode_chunk (tp, pag, &rec);if (error) goto error0; }else {
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 xfs: fix cursor and pointer handling when recovering iunlink buckets
From: "Darrick J. Wong" <[email protected]>
[ Upstream commit 65f39d09d73718611cee40399179323b5d4ead00 ]
LOLLM pointed out a bug in xlog_recover_iunlink_bucket:
1. We don't null out prev_ip after releasing it, which can lead to UAF problems if the inodegc flush call in the loop fails.
at which point I noticed even more bugs:
2. If the inodegc flush inside the loop fails, we also leak @ip.
3. We set prev_agino to agino having already advanced agino, which results in inodes with i_prev_unlinked set to itself.
4. If we exit the bottom of the loop with prev_ip set, then prev_ip aliases ip and we also set its i_prev_unlinked to itself.
Bugs 3 and 4 introduce loops into the unlinked list, though these loops don't surface because we immediately flush each unlinked inode after loading it.
Fix all of these issues.
--- fs/xfs/xfs_log_recover.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
fs/xfs/xfs_log_recover.c +8 -5
@@ -2701,12 +2701,13 @@ xlog_recover_iunlink_bucket( {struct xfs_mount *mp = pag->pag_mount;struct xfs_inode *prev_ip =NULL ; -struct xfs_inode *ip;xfs_agino_t prev_agino, agino;int error =0 ; agino =be32_to_cpu (agi->agi_unlinked[bucket]);while (agino !=NULLAGINO ) { +struct xfs_inode *ip; + error =xfs_iget (mp,NULL ,XFS_AGINO_TO_INO (mp, pag->pag_agno, agino),0 ,0 , &ip);
@@ -2716,11 +2717,11 @@ xlog_recover_iunlink_bucket(ASSERT (VFS_I (ip)->i_nlink ==0 );ASSERT (VFS_I (ip)->i_mode !=0 );xfs_iflags_clear (ip,XFS_IRECOVERY ); - agino = ip->i_next_unlinked;if (prev_ip) { ip->i_prev_unlinked = prev_agino;xfs_irele (prev_ip); + prev_ip =NULL ;/* * Ensure the inode is removed from the unlinked list
@@ -2732,18 +2733,20 @@ xlog_recover_iunlink_bucket(* complete. */ error =xfs_inodegc_flush (mp); -if (error) -break ; +if (error) { +xfs_irele (ip); +return error; + } } prev_agino = agino; + agino = ip->i_next_unlinked; prev_ip = ip; }if (prev_ip) {int error2; - ip->i_prev_unlinked = prev_agino;xfs_irele (prev_ip); error2 =xfs_inodegc_flush (mp);
Signature · 1 line
2.53.0