]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.6-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 17 Jul 2026 09:34:02 +0000 (11:34 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 17 Jul 2026 09:34:02 +0000 (11:34 +0200)
added patches:
xfs-fail-recovery-on-a-committed-log-item-with-no-regions.patch
xfs-resample-the-data-fork-mapping-after-cycling-ilock.patch

queue-6.6/series
queue-6.6/xfs-fail-recovery-on-a-committed-log-item-with-no-regions.patch [new file with mode: 0644]
queue-6.6/xfs-resample-the-data-fork-mapping-after-cycling-ilock.patch [new file with mode: 0644]

index 4598da6ab04d9cc797573f43c199e12e2811ecc6..6e3fb39d7652deda92e6167421c9c01689c8a73f 100644 (file)
@@ -321,3 +321,5 @@ 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
 smb-client-reject-overlapping-data-areas-in-smb2-responses.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-6.6/xfs-fail-recovery-on-a-committed-log-item-with-no-regions.patch b/queue-6.6/xfs-fail-recovery-on-a-committed-log-item-with-no-regions.patch
new file mode 100644 (file)
index 0000000..67c5ca4
--- /dev/null
@@ -0,0 +1,69 @@
+From 2094dab19d45c487285617b7b68913d0cc0c1211 Mon Sep 17 00:00:00 2001
+From: Weiming Shi <bestswngs@gmail.com>
+Date: Thu, 2 Jul 2026 09:20:00 -0700
+Subject: xfs: fail recovery on a committed log item with no regions
+
+From: Weiming Shi <bestswngs@gmail.com>
+
+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 <xmei5@asu.edu>
+Assisted-by: Claude:claude-opus-4-8
+Signed-off-by: Weiming Shi <bestswngs@gmail.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
+Signed-off-by: Carlos Maiolino <cem@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -1872,6 +1872,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-6.6/xfs-resample-the-data-fork-mapping-after-cycling-ilock.patch b/queue-6.6/xfs-resample-the-data-fork-mapping-after-cycling-ilock.patch
new file mode 100644 (file)
index 0000000..3454330
--- /dev/null
@@ -0,0 +1,100 @@
+From 2f4acd0fcd862e22eab45690ec2c08c80b6ef2e7 Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <djwong@kernel.org>
+Date: Mon, 13 Jul 2026 23:03:44 -0700
+Subject: xfs: resample the data fork mapping after cycling ILOCK
+
+From: Darrick J. Wong <djwong@kernel.org>
+
+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" <djwong@kernel.org>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
+Signed-off-by: Carlos Maiolino <cem@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/xfs/xfs_reflink.c |   36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+--- a/fs/xfs/xfs_reflink.c
++++ b/fs/xfs/xfs_reflink.c
+@@ -389,6 +389,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;
+@@ -407,6 +408,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;
+@@ -453,6 +470,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;
+@@ -463,6 +482,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)