diff mbox series

[3/4] xfs_repair: fix infinite loop in longform_dir2_entry_check*

Message ID 174257453651.474645.12262367407953457434.stgit@frogsfrogsfrogs (mailing list archive)
State New
Headers show
Series [1/4] xfs_repair: don't recreate /quota metadir if there are no quota inodes | expand

Commit Message

Darrick J. Wong March 21, 2025, 4:32 p.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

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>
---
 libxfs/libxfs_api_defs.h |    1 +
 repair/phase6.c          |   22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+)

Comments

Christoph Hellwig March 23, 2025, 6:34 a.m. UTC | #1
Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>
diff mbox series

Patch

diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index 14a67c8c24dd7e..dcb5dec0a7abd2 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 c16164c171d07d..44b9bfc3b7e69f 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