From: Darrick J. Wong Date: Fri, 21 Mar 2025 16:32:02 +0000 (-0700) Subject: xfs_repair: fix infinite loop in longform_dir2_entry_check* X-Git-Tag: v6.14.0~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bbd8ba73e64b43b29e96b813173aafd6da4ab1fc;p=thirdparty%2Fxfsprogs-dev.git xfs_repair: fix infinite loop in longform_dir2_entry_check* 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 Reviewed-by: Christoph Hellwig --- diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 14a67c8c..dcb5dec0 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -399,6 +399,7 @@ #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 diff --git a/repair/phase6.c b/repair/phase6.c index c16164c1..44b9bfc3 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -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