From: Daeho Jeong <[email protected]>

Detect and fix a corrupted xattr entry.

Signed-off-by: Daeho Jeong <[email protected]>
---
 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(-)

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);
-- 
2.42.0.655.g421f12c284-goog



_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to