From: Greg Kroah-Hartman Date: Fri, 17 Jul 2026 09:33:35 +0000 (+0200) Subject: 5.15-stable patches X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e9e9359142ae16ec23566e061ffc369ad67994e0;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: xfs-fail-recovery-on-a-committed-log-item-with-no-regions.patch xfs-resample-the-data-fork-mapping-after-cycling-ilock.patch --- diff --git a/queue-5.15/series b/queue-5.15/series index 45289bdc57..b627d905a3 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -194,3 +194,5 @@ rdma-rtrs-srv-bound-rdma-write-length-to-chunk-size-in-rdma_write_sg.patch rdma-siw-bound-read-response-placement-to-the-rread-length.patch fuse-fix-device-node-leak-in-cuse_process_init_reply.patch fuse-re-lock-request-before-returning-from-fuse_ref_folio.patch +xfs-fail-recovery-on-a-committed-log-item-with-no-regions.patch +xfs-resample-the-data-fork-mapping-after-cycling-ilock.patch diff --git a/queue-5.15/xfs-fail-recovery-on-a-committed-log-item-with-no-regions.patch b/queue-5.15/xfs-fail-recovery-on-a-committed-log-item-with-no-regions.patch new file mode 100644 index 0000000000..04ecefad52 --- /dev/null +++ b/queue-5.15/xfs-fail-recovery-on-a-committed-log-item-with-no-regions.patch @@ -0,0 +1,69 @@ +From 2094dab19d45c487285617b7b68913d0cc0c1211 Mon Sep 17 00:00:00 2001 +From: Weiming Shi +Date: Thu, 2 Jul 2026 09:20:00 -0700 +Subject: xfs: fail recovery on a committed log item with no regions + +From: Weiming Shi + +commit 2094dab19d45c487285617b7b68913d0cc0c1211 upstream. + +If the first op of a transaction is a bare transaction header +(len == sizeof(struct xfs_trans_header)), xlog_recover_add_to_trans() +adds an item but no region, leaving it on r_itemq with ri_cnt == 0 and +ri_buf == NULL. + +The header can be split across op records, so later ops may still add +regions; the item is only invalid if the transaction commits with none. +The runtime commit path never emits such a transaction, so this only +happens on a crafted log. It came from an AI-assisted code audit of the +recovery parser. + +xlog_recover_reorder_trans() calls ITEM_TYPE() on the item, which reads +*(unsigned short *)item->ri_buf[0].iov_base and faults on the NULL +ri_buf. Reject it there, before the commit handlers that also read +ri_buf[0]. + + KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] + RIP: 0010:xlog_recover_reorder_trans (fs/xfs/xfs_log_recover.c:1836) + xlog_recover_commit_trans (fs/xfs/xfs_log_recover.c:2043) + xlog_recover_process_data (fs/xfs/xfs_log_recover.c:2501) + xlog_do_recovery_pass (fs/xfs/xfs_log_recover.c:3244) + xlog_recover (fs/xfs/xfs_log_recover.c:3493) + xfs_log_mount (fs/xfs/xfs_log.c:618) + xfs_mountfs (fs/xfs/xfs_mount.c:1034) + xfs_fs_fill_super (fs/xfs/xfs_super.c:1938) + vfs_get_tree (fs/super.c:1695) + path_mount (fs/namespace.c:4161) + __x64_sys_mount (fs/namespace.c:4367) + +Fixes: 89cebc847729 ("xfs: validate transaction header length on log recovery") +Cc: stable@vger.kernel.org # v4.3 +Reported-by: Xiang Mei +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Weiming Shi +Reviewed-by: Christoph Hellwig +Reviewed-by: "Darrick J. Wong" +Signed-off-by: Carlos Maiolino +Signed-off-by: Greg Kroah-Hartman +--- + fs/xfs/xfs_log_recover.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/fs/xfs/xfs_log_recover.c ++++ b/fs/xfs/xfs_log_recover.c +@@ -1882,6 +1882,15 @@ xlog_recover_reorder_trans( + list_for_each_entry_safe(item, n, &sort_list, ri_list) { + enum xlog_recover_reorder fate = XLOG_REORDER_ITEM_LIST; + ++ /* a committed item with no regions has a NULL ri_buf[0] */ ++ if (!item->ri_cnt || !item->ri_buf) { ++ xfs_warn(log->l_mp, ++ "%s: committed log item has no regions", ++ __func__); ++ error = -EFSCORRUPTED; ++ break; ++ } ++ + item->ri_ops = xlog_find_item_ops(item); + if (!item->ri_ops) { + xfs_warn(log->l_mp, diff --git a/queue-5.15/xfs-resample-the-data-fork-mapping-after-cycling-ilock.patch b/queue-5.15/xfs-resample-the-data-fork-mapping-after-cycling-ilock.patch new file mode 100644 index 0000000000..36d77174d1 --- /dev/null +++ b/queue-5.15/xfs-resample-the-data-fork-mapping-after-cycling-ilock.patch @@ -0,0 +1,100 @@ +From 2f4acd0fcd862e22eab45690ec2c08c80b6ef2e7 Mon Sep 17 00:00:00 2001 +From: "Darrick J. Wong" +Date: Mon, 13 Jul 2026 23:03:44 -0700 +Subject: xfs: resample the data fork mapping after cycling ILOCK + +From: Darrick J. Wong + +commit 2f4acd0fcd862e22eab45690ec2c08c80b6ef2e7 upstream. + +xfs_reflink_fill_{cow_hole,delalloc} are both presented with an inode, +a data fork mapping, and a cow fork mapping. Unfortunately, these two +helpers cycle the ILOCK to grab a transaction, which means that the +mappings are stale as soon as we reacquire the ILOCK. Currently we +refresh the cow fork mapping by re-calling xfs_find_trim_cow_extent, but +we don't refresh the data fork mapping beforehand, which means that the +xfs_bmap_trim_cow in that function queries the refcount btree about the +wrong physical blocks and returns an inaccurate value in *shared. + +If *shared is now false, the directio write proceeds with a stale data +fork mapping. Fix this by querying the data fork mapping if the +sequence counter changes across the ILOCK cycle. + +Cc: hch@lst.de +Cc: stable@vger.kernel.org # v4.11 +Fixes: 3c68d44a2b49a0 ("xfs: allocate direct I/O COW blocks in iomap_begin") +Signed-off-by: "Darrick J. Wong" +Reviewed-by: Christoph Hellwig +Reviewed-by: Carlos Maiolino +Signed-off-by: Carlos Maiolino +Signed-off-by: Greg Kroah-Hartman +--- + fs/xfs/xfs_reflink.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +--- a/fs/xfs/xfs_reflink.c ++++ b/fs/xfs/xfs_reflink.c +@@ -386,6 +386,7 @@ xfs_reflink_fill_cow_hole( + struct xfs_trans *tp; + xfs_filblks_t resaligned; + xfs_extlen_t resblks; ++ unsigned int seq_before = READ_ONCE(ip->i_df.if_seq); + int nimaps; + int error; + bool found; +@@ -404,6 +405,22 @@ xfs_reflink_fill_cow_hole( + + *lockmode = XFS_ILOCK_EXCL; + ++ /* ++ * The data fork mapping may have changed while we dropped the ILOCK ++ * (a racing O_DIRECT writer under IOLOCK_SHARED can complete a full ++ * CoW cycle including xfs_reflink_end_cow(), which remaps this offset ++ * and drops the refcount of the old shared block). Re-read it so the ++ * shared-status recheck below and the caller's in-place iomap both ++ * operate on the current mapping rather than a stale physical block. ++ */ ++ if (seq_before != READ_ONCE(ip->i_df.if_seq)) { ++ nimaps = 1; ++ error = xfs_bmapi_read(ip, imap->br_startoff, ++ imap->br_blockcount, imap, &nimaps, 0); ++ if (error) ++ goto out_trans_cancel; ++ } ++ + error = xfs_find_trim_cow_extent(ip, imap, cmap, shared, &found); + if (error || !*shared) + goto out_trans_cancel; +@@ -459,6 +476,8 @@ xfs_reflink_fill_delalloc( + bool found; + + do { ++ unsigned int seq_before = READ_ONCE(ip->i_df.if_seq); ++ + xfs_iunlock(ip, *lockmode); + *lockmode = 0; + +@@ -469,6 +488,23 @@ xfs_reflink_fill_delalloc( + + *lockmode = XFS_ILOCK_EXCL; + ++ /* ++ * The data fork mapping may have changed while we dropped the ++ * ILOCK (a racing O_DIRECT writer under IOLOCK_SHARED can ++ * complete a full CoW cycle including xfs_reflink_end_cow(), ++ * which remaps this offset and drops the refcount of the old ++ * shared block). Re-read it so the shared-status recheck ++ * below and the caller's in-place iomap both operate on the ++ * current mapping rather than a stale physical block. ++ */ ++ if (seq_before != READ_ONCE(ip->i_df.if_seq)) { ++ nimaps = 1; ++ error = xfs_bmapi_read(ip, imap->br_startoff, ++ imap->br_blockcount, imap, &nimaps, 0); ++ if (error) ++ goto out_trans_cancel; ++ } ++ + error = xfs_find_trim_cow_extent(ip, imap, cmap, shared, + &found); + if (error || !*shared)