]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs_repair: fix infinite loop in longform_dir2_entry_check*
authorDarrick J. Wong <djwong@kernel.org>
Fri, 21 Mar 2025 16:32:02 +0000 (09:32 -0700)
committerAndrey Albershteyn <aalbersh@kernel.org>
Mon, 31 Mar 2025 09:45:45 +0000 (11:45 +0200)
If someone corrupts the data fork of a directory to have a bmap record
whose br_startoff only has bits set in the upper 32 bits, the code will
suffer an integer overflow when assigning the 64-bit next_da_bno to the
32-bit da_bno.  This leads to an infinite loop.

Found by fuzzing xfs/812 with u3.bmx[0].startoff = firstbit.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
libxfs/libxfs_api_defs.h
repair/phase6.c

index 14a67c8c24dd7e5ccfc7f41111eb72f5d6148f70..dcb5dec0a7abd2c2efe0cc847003b5e79f30bb98 100644 (file)
 #define xfs_verify_agbext              libxfs_verify_agbext
 #define xfs_verify_agino               libxfs_verify_agino
 #define xfs_verify_cksum               libxfs_verify_cksum
+#define xfs_verify_dablk               libxfs_verify_dablk
 #define xfs_verify_dir_ino             libxfs_verify_dir_ino
 #define xfs_verify_fsbext              libxfs_verify_fsbext
 #define xfs_verify_fsbno               libxfs_verify_fsbno
index c16164c171d07d67fbe084056e09f7b0fb3c2ac5..44b9bfc3b7e69f1f566421bfb51d383cf5c40eaa 100644 (file)
@@ -2169,6 +2169,13 @@ longform_dir2_check_node(
                if (bmap_next_offset(ip, &next_da_bno))
                        break;
 
+               if (next_da_bno != NULLFILEOFF &&
+                   !libxfs_verify_dablk(mp, next_da_bno)) {
+                       do_warn(_("invalid dir leaf block 0x%llx\n"),
+                                       (unsigned long long)next_da_bno);
+                       return 1;
+               }
+
                /*
                 * we need to use the da3 node verifier here as it handles the
                 * fact that reading the leaf hash tree blocks can return either
@@ -2244,6 +2251,13 @@ longform_dir2_check_node(
                if (bmap_next_offset(ip, &next_da_bno))
                        break;
 
+               if (next_da_bno != NULLFILEOFF &&
+                   !libxfs_verify_dablk(mp, next_da_bno)) {
+                       do_warn(_("invalid dir free block 0x%llx\n"),
+                                       (unsigned long long)next_da_bno);
+                       return 1;
+               }
+
                error = dir_read_buf(ip, da_bno, &bp, &xfs_dir3_free_buf_ops,
                                &fixit);
                if (error) {
@@ -2379,6 +2393,14 @@ longform_dir2_entry_check(
                        break;
                }
 
+               if (next_da_bno != NULLFILEOFF &&
+                   !libxfs_verify_dablk(mp, next_da_bno)) {
+                       do_warn(_("invalid dir data block 0x%llx\n"),
+                                       (unsigned long long)next_da_bno);
+                       fixit++;
+                       goto out_fix;
+               }
+
                if (fmt == XFS_DIR2_FMT_BLOCK)
                        ops = &xfs_dir3_block_buf_ops;
                else