diff mbox series

[f2fs-dev] f2fs-tools: fix corrupted xattr entry

Message ID 20231023155005.2259554-1-jaegeuk@kernel.org (mailing list archive)
State New
Headers show
Series [f2fs-dev] f2fs-tools: fix corrupted xattr entry | expand

Commit Message

Jaegeuk Kim Oct. 23, 2023, 3:50 p.m. UTC
From: Daeho Jeong <daehojeong@google.com>

Detect and fix a corrupted xattr entry.

Signed-off-by: Daeho Jeong <daehojeong@google.com>
---
 fsck/dump.c  |  2 +-
 fsck/fsck.c  | 40 ++++++++++++++++++++++++++++++++++++++++
 fsck/fsck.h  |  4 +++-
 fsck/mount.c |  2 +-
 fsck/xattr.c |  9 +++++----
 5 files changed, 50 insertions(+), 7 deletions(-)

Comments

Chao Yu Nov. 15, 2023, 8:34 a.m. UTC | #1
On 2023/10/23 23:50, Jaegeuk Kim wrote:
> From: Daeho Jeong <daehojeong@google.com>
> 
> Detect and fix a corrupted xattr entry.
> 
> Signed-off-by: Daeho Jeong <daehojeong@google.com>

Reviewed-by: Chao Yu <chao@kernel.org>

Thanks,
diff mbox series

Patch

diff --git a/fsck/dump.c b/fsck/dump.c
index ecadfdd9b988..864a3c3bb624 100644
--- a/fsck/dump.c
+++ b/fsck/dump.c
@@ -359,7 +359,7 @@  static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk)
 	char xattr_name[F2FS_NAME_LEN] = {0};
 	int ret;
 
-	xattr = read_all_xattrs(sbi, node_blk);
+	xattr = read_all_xattrs(sbi, node_blk, true);
 	if (!xattr)
 		return;
 
diff --git a/fsck/fsck.c b/fsck/fsck.c
index 69417ca6081c..72daa719bc27 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -834,6 +834,43 @@  void fsck_reada_all_direct_node_blocks(struct f2fs_sb_info *sbi,
 	}
 }
 
+int chk_extended_attributes(struct f2fs_sb_info *sbi, u32 nid,
+		struct f2fs_node *inode)
+{
+	void *xattr;
+	void *last_base_addr;
+	struct f2fs_xattr_entry *ent;
+	__u32 xattr_size = XATTR_SIZE(&inode->i);
+
+	if (xattr_size == 0)
+		return 0;
+
+	xattr = read_all_xattrs(sbi, inode, false);
+	ASSERT(xattr);
+
+	last_base_addr = (void *)xattr + xattr_size;
+
+	list_for_each_xattr(ent, xattr) {
+		if ((void *)(ent) + sizeof(__u32) > last_base_addr ||
+			(void *)XATTR_NEXT_ENTRY(ent) > last_base_addr) {
+			ASSERT_MSG("[0x%x] last xattr entry (offset: %lx) "
+					"crosses the boundary",
+					nid, (long int)((void *)ent - xattr));
+			if (c.fix_on) {
+				memset(ent, 0,
+					(char *)last_base_addr - (char *)ent);
+				write_all_xattrs(sbi, inode, xattr_size, xattr);
+				FIX_MSG("[0x%x] nullify wrong xattr entries",
+						nid);
+				return 1;
+			}
+			break;
+		}
+	}
+
+	return 0;
+}
+
 /* start with valid nid and blkaddr */
 void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
 		enum FILE_TYPE ftype, struct f2fs_node *node_blk,
@@ -1008,6 +1045,9 @@  check_next:
 		}
 	}
 
+	if (chk_extended_attributes(sbi, nid, node_blk))
+		need_fix = 1;
+
 	if ((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
 		unsigned int inline_size = MAX_INLINE_DATA(node_blk);
 		if (cur_qtype != -1)
diff --git a/fsck/fsck.h b/fsck/fsck.h
index 091b5d863d34..c25f3819f980 100644
--- a/fsck/fsck.h
+++ b/fsck/fsck.h
@@ -330,6 +330,8 @@  struct hardlink_cache_entry *f2fs_search_hardlink(struct f2fs_sb_info *sbi,
 						struct dentry *de);
 
 /* xattr.c */
-void *read_all_xattrs(struct f2fs_sb_info *, struct f2fs_node *);
+void *read_all_xattrs(struct f2fs_sb_info *, struct f2fs_node *, bool);
+void write_all_xattrs(struct f2fs_sb_info *sbi,
+		struct f2fs_node *inode, __u32 hsize, void *txattr_addr);
 
 #endif /* _FSCK_H_ */
diff --git a/fsck/mount.c b/fsck/mount.c
index a1389ed61c24..3b02d73fee93 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -370,7 +370,7 @@  void print_inode_info(struct f2fs_sb_info *sbi,
 	DISP_u32(F2FS_INODE_NIDS(inode), i_nid[3]);	/* indirect */
 	DISP_u32(F2FS_INODE_NIDS(inode), i_nid[4]);	/* double indirect */
 
-	xattr_addr = read_all_xattrs(sbi, node);
+	xattr_addr = read_all_xattrs(sbi, node, true);
 	if (!xattr_addr)
 		goto out;
 
diff --git a/fsck/xattr.c b/fsck/xattr.c
index fe28437b81ea..9ccf3615229e 100644
--- a/fsck/xattr.c
+++ b/fsck/xattr.c
@@ -17,14 +17,15 @@ 
 #include "node.h"
 #include "xattr.h"
 
-void *read_all_xattrs(struct f2fs_sb_info *sbi, struct f2fs_node *inode)
+void *read_all_xattrs(struct f2fs_sb_info *sbi, struct f2fs_node *inode,
+			bool sanity_check)
 {
 	struct f2fs_xattr_header *header;
 	void *txattr_addr;
 	u64 inline_size = inline_xattr_size(&inode->i);
 	nid_t xnid = le32_to_cpu(inode->i.i_xattr_nid);
 
-	if (c.func == FSCK && xnid) {
+	if (c.func == FSCK && xnid && sanity_check) {
 		if (fsck_sanity_check_nid(sbi, xnid, F2FS_FT_XATTR, TYPE_XATTR))
 			return NULL;
 	}
@@ -78,7 +79,7 @@  static struct f2fs_xattr_entry *__find_xattr(void *base_addr,
 	return entry;
 }
 
-static void write_all_xattrs(struct f2fs_sb_info *sbi,
+void write_all_xattrs(struct f2fs_sb_info *sbi,
 		struct f2fs_node *inode, __u32 hsize, void *txattr_addr)
 {
 	void *xattr_addr;
@@ -165,7 +166,7 @@  int f2fs_setxattr(struct f2fs_sb_info *sbi, nid_t ino, int index, const char *na
 	ret = dev_read_block(inode, ni.blk_addr);
 	ASSERT(ret >= 0);
 
-	base_addr = read_all_xattrs(sbi, inode);
+	base_addr = read_all_xattrs(sbi, inode, true);
 	ASSERT(base_addr);
 
 	last_base_addr = (void *)base_addr + XATTR_SIZE(&inode->i);