xfsprogs/0028-xfs_repair-check-the-ftype-of-dot-and-dotdot-directo.patch
wguanghao 7fbd36818a backport patches from community
(cherry picked from commit cc60985a665f17f23031c03f1021e886d63b990f)
2023-12-27 16:29:57 +08:00

135 lines
3.7 KiB
Diff

From 5008cbb4b0eaef22e5a0e13a5a2c17457671e34a Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <djwong@kernel.org>
Date: Tue, 17 May 2022 22:48:13 -0400
Subject: [PATCH] xfs_repair: check the ftype of dot and dotdot directory
entries
The long-format directory block checking code skips the filetype check
for the '.' and '..' entries, even though they're part of the ondisk
format. This leads to repair failing to catch subtle corruption at the
start of a directory.
Found by fuzzing bu[0].filetype = zeroes in xfs/386.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
repair/phase6.c | 79 +++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 54 insertions(+), 25 deletions(-)
diff --git a/repair/phase6.c b/repair/phase6.c
index 696a642..06232fb 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -1412,6 +1412,48 @@ dir2_kill_block(
_("directory shrink failed (%d)\n"), error);
}
+static inline void
+check_longform_ftype(
+ struct xfs_mount *mp,
+ struct xfs_inode *ip,
+ xfs_dir2_data_entry_t *dep,
+ ino_tree_node_t *irec,
+ int ino_offset,
+ struct dir_hash_tab *hashtab,
+ xfs_dir2_dataptr_t addr,
+ struct xfs_da_args *da,
+ struct xfs_buf *bp)
+{
+ xfs_ino_t inum = be64_to_cpu(dep->inumber);
+ uint8_t dir_ftype;
+ uint8_t ino_ftype;
+
+ if (!xfs_sb_version_hasftype(&mp->m_sb))
+ return;
+
+ dir_ftype = libxfs_dir2_data_get_ftype(mp, dep);
+ ino_ftype = get_inode_ftype(irec, ino_offset);
+
+ if (dir_ftype == ino_ftype)
+ return;
+
+ if (no_modify) {
+ do_warn(
+_("would fix ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"),
+ dir_ftype, ino_ftype,
+ ip->i_ino, inum);
+ return;
+ }
+
+ do_warn(
+_("fixing ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"),
+ dir_ftype, ino_ftype,
+ ip->i_ino, inum);
+ libxfs_dir2_data_put_ftype(mp, dep, ino_ftype);
+ libxfs_dir2_data_log_entry(da, bp, dep);
+ dir_hash_update_ftype(hashtab, addr, ino_ftype);
+}
+
/*
* process a data block, also checks for .. entry
* and corrects it to match what we think .. should be
@@ -1749,6 +1791,11 @@ longform_dir2_entry_check_data(
libxfs_dir2_data_log_entry(&da, bp, dep);
}
}
+
+ if (!nbad)
+ check_longform_ftype(mp, ip, dep, irec,
+ ino_offset, hashtab, addr, &da,
+ bp);
continue;
}
ASSERT(no_modify || libxfs_verify_dir_ino(mp, inum));
@@ -1777,6 +1824,11 @@ longform_dir2_entry_check_data(
libxfs_dir2_data_log_entry(&da, bp, dep);
}
}
+
+ if (!nbad)
+ check_longform_ftype(mp, ip, dep, irec,
+ ino_offset, hashtab, addr, &da,
+ bp);
*need_dot = 0;
continue;
}
@@ -1787,31 +1839,8 @@ longform_dir2_entry_check_data(
continue;
/* validate ftype field if supported */
- if (xfs_sb_version_hasftype(&mp->m_sb)) {
- uint8_t dir_ftype;
- uint8_t ino_ftype;
-
- dir_ftype = libxfs_dir2_data_get_ftype(mp, dep);
- ino_ftype = get_inode_ftype(irec, ino_offset);
-
- if (dir_ftype != ino_ftype) {
- if (no_modify) {
- do_warn(
- _("would fix ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"),
- dir_ftype, ino_ftype,
- ip->i_ino, inum);
- } else {
- do_warn(
- _("fixing ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"),
- dir_ftype, ino_ftype,
- ip->i_ino, inum);
- libxfs_dir2_data_put_ftype(mp, dep, ino_ftype);
- libxfs_dir2_data_log_entry(&da, bp, dep);
- dir_hash_update_ftype(hashtab, addr,
- ino_ftype);
- }
- }
- }
+ check_longform_ftype(mp, ip, dep, irec, ino_offset, hashtab,
+ addr, &da, bp);
/*
* check easy case first, regular inode, just bump
--
1.8.3.1