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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Darrick J. Wong <djwong@xxxxxxxxxx>

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


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





[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux