fsck.f2fs: fix to check validation of i_xattr_nid
authorChao Yu <yuchao0@huawei.com>
Tue, 7 Apr 2020 10:01:07 +0000 (18:01 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 6 May 2020 14:41:06 +0000 (07:41 -0700)
Otherwise, fsck.f2fs will access invalid memory address as below:

- fsck_verify
 - dump_node
  - dump_file
   - dump_inode_blk
    - dump_xattr
     - read_all_xattrs
       - get_node_info
        access &(F2FS_FSCK(sbi)->entries[nid])

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fsck/dump.c
fsck/fsck.c
fsck/fsck.h
fsck/mount.c
fsck/xattr.c

index 144c10e..001b7cb 100644 (file)
@@ -309,6 +309,8 @@ static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk)
        int ret;
 
        xattr = read_all_xattrs(sbi, node_blk);
+       if (!xattr)
+               return;
 
        list_for_each_xattr(ent, xattr) {
                char *name = strndup(ent->e_name, ent->e_name_len);
index a08a8cb..0389146 100644 (file)
@@ -487,6 +487,14 @@ static int sanity_check_nid(struct f2fs_sb_info *sbi, u32 nid,
        return 0;
 }
 
+int fsck_sanity_check_nid(struct f2fs_sb_info *sbi, u32 nid,
+                       struct f2fs_node *node_blk,
+                       enum FILE_TYPE ftype, enum NODE_TYPE ntype,
+                       struct node_info *ni)
+{
+       return sanity_check_nid(sbi, nid, node_blk, ftype, ntype, ni);
+}
+
 static int fsck_chk_xattr_blk(struct f2fs_sb_info *sbi, u32 ino,
                                        u32 x_nid, u32 *blk_cnt)
 {
index c4432e8..2de6f62 100644 (file)
@@ -144,6 +144,9 @@ static inline bool need_fsync_data_record(struct f2fs_sb_info *sbi)
 extern int fsck_chk_orphan_node(struct f2fs_sb_info *);
 extern int fsck_chk_quota_node(struct f2fs_sb_info *);
 extern int fsck_chk_quota_files(struct f2fs_sb_info *);
+extern int fsck_sanity_check_nid(struct f2fs_sb_info *, u32,
+                       struct f2fs_node *, enum FILE_TYPE, enum NODE_TYPE,
+                       struct node_info *);
 extern int fsck_chk_node_blk(struct f2fs_sb_info *, struct f2fs_inode *, u32,
                enum FILE_TYPE, enum NODE_TYPE, u32 *,
                struct child_info *);
index 4d16659..0aab071 100644 (file)
@@ -257,10 +257,12 @@ void print_inode_info(struct f2fs_sb_info *sbi,
        DISP_u32(inode, i_nid[4]);      /* double indirect */
 
        xattr_addr = read_all_xattrs(sbi, node);
-       list_for_each_xattr(ent, xattr_addr) {
-               print_xattr_entry(ent);
+       if (xattr_addr) {
+               list_for_each_xattr(ent, xattr_addr) {
+                       print_xattr_entry(ent);
+               }
+               free(xattr_addr);
        }
-       free(xattr_addr);
 
        printf("\n");
 }
index d5350e3..e9dcb52 100644 (file)
@@ -22,6 +22,22 @@ void *read_all_xattrs(struct f2fs_sb_info *sbi, struct f2fs_node *inode)
        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 (xnid) {
+               struct f2fs_node *node_blk = NULL;
+               struct node_info ni;
+               int ret;
+
+               node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1);
+               ASSERT(node_blk != NULL);
+
+               ret = fsck_sanity_check_nid(sbi, xnid, node_blk,
+                                       F2FS_FT_XATTR, TYPE_XATTR, &ni);
+               free(node_blk);
+               if (ret)
+                       return NULL;
+       }
 
        txattr_addr = calloc(inline_size + BLOCK_SZ, 1);
        ASSERT(txattr_addr);
@@ -30,11 +46,11 @@ void *read_all_xattrs(struct f2fs_sb_info *sbi, struct f2fs_node *inode)
                memcpy(txattr_addr, inline_xattr_addr(&inode->i), inline_size);
 
        /* Read from xattr node block. */
-       if (inode->i.i_xattr_nid) {
+       if (xnid) {
                struct node_info ni;
                int ret;
 
-               get_node_info(sbi, le32_to_cpu(inode->i.i_xattr_nid), &ni);
+               get_node_info(sbi, xnid, &ni);
                ret = dev_read_block(txattr_addr + inline_size, ni.blk_addr);
                ASSERT(ret >= 0);
        }