diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-10-28 01:06:24 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-10-28 01:06:24 +0000 |
commit | c0e6db70c392f86fbaefabad4e38ff9ca1a7423e (patch) | |
tree | 211911b40f11a7e070e60d26679c3e092115c465 | |
parent | 544d4f9679ace838040928c0f860578e86a5eefc (diff) | |
parent | ea48e068e7b02320187ff65c516c15ede376a7a6 (diff) | |
download | f2fs-tools-android14-d2-s4-release.tar.gz |
Snap for 11016864 from ea48e068e7b02320187ff65c516c15ede376a7a6 to udc-d2-releaseandroid-14.0.0_r45android-14.0.0_r44android-14.0.0_r43android-14.0.0_r42android-14.0.0_r41android-14.0.0_r40android-14.0.0_r39android-14.0.0_r38android14-d2-s5-releaseandroid14-d2-s4-releaseandroid14-d2-s3-releaseandroid14-d2-s2-releaseandroid14-d2-s1-releaseandroid14-d2-release
Change-Id: Ia5b39b0a2731414a390361f54cf003411744b614
-rw-r--r-- | fsck/dump.c | 11 | ||||
-rw-r--r-- | fsck/fsck.c | 58 | ||||
-rw-r--r-- | fsck/fsck.h | 4 | ||||
-rw-r--r-- | fsck/mount.c | 20 | ||||
-rw-r--r-- | fsck/xattr.c | 31 | ||||
-rw-r--r-- | fsck/xattr.h | 6 |
6 files changed, 116 insertions, 14 deletions
diff --git a/fsck/dump.c b/fsck/dump.c index b8f6144..0138a18 100644 --- a/fsck/dump.c +++ b/fsck/dump.c @@ -353,18 +353,27 @@ static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype, static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk) { void *xattr; + void *last_base_addr; struct f2fs_xattr_entry *ent; 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; + last_base_addr = (void *)xattr + XATTR_SIZE(&node_blk->i); + list_for_each_xattr(ent, xattr) { char *name = strndup(ent->e_name, ent->e_name_len); void *value = ent->e_name + ent->e_name_len; + if ((void *)(ent) + sizeof(__u32) > last_base_addr || + (void *)XATTR_NEXT_ENTRY(ent) > last_base_addr) { + MSG(0, "xattr entry crosses the end of xattr space\n"); + break; + } + if (!name) continue; diff --git a/fsck/fsck.c b/fsck/fsck.c index 324c3d5..d38ad1e 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -685,6 +685,61 @@ void fsck_reada_all_direct_node_blocks(struct f2fs_sb_info *sbi, } } +static bool is_zeroed(const u8 *p, size_t size) +{ + size_t i; + + for (i = 0; i < size; i++) { + if (p[i]) + return false; + } + return true; +} + +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); + bool need_fix = false; + + 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)); + need_fix = true; + break; + } + } + if (!need_fix && + !is_zeroed((u8 *)ent, (u8 *)last_base_addr - (u8 *)ent)) { + ASSERT_MSG("[0x%x] nonzero bytes in xattr space after " + "end of list", nid); + need_fix = true; + } + if (need_fix && c.fix_on) { + memset(ent, 0, (u8 *)last_base_addr - (u8 *)ent); + write_all_xattrs(sbi, inode, xattr_size, xattr); + FIX_MSG("[0x%x] nullify wrong xattr entries", nid); + free(xattr); + return 1; + } + free(xattr); + 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, @@ -860,6 +915,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 dabd8b9..02ccc93 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -328,6 +328,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 df0314d..5bdac76 100644 --- a/fsck/mount.c +++ b/fsck/mount.c @@ -238,6 +238,7 @@ void print_inode_info(struct f2fs_sb_info *sbi, { struct f2fs_inode *inode = &node->i; void *xattr_addr; + void *last_base_addr; struct f2fs_xattr_entry *ent; char en[F2FS_PRINT_NAMELEN]; unsigned int i = 0; @@ -333,14 +334,23 @@ void print_inode_info(struct f2fs_sb_info *sbi, DISP_u32(inode, i_nid[3]); /* indirect */ DISP_u32(inode, i_nid[4]); /* double indirect */ - xattr_addr = read_all_xattrs(sbi, node); - if (xattr_addr) { - list_for_each_xattr(ent, xattr_addr) { - print_xattr_entry(ent); + xattr_addr = read_all_xattrs(sbi, node, true); + if (!xattr_addr) + goto out; + + last_base_addr = (void *)xattr_addr + XATTR_SIZE(&node->i); + + list_for_each_xattr(ent, xattr_addr) { + if ((void *)(ent) + sizeof(__u32) > last_base_addr || + (void *)XATTR_NEXT_ENTRY(ent) > last_base_addr) { + MSG(0, "xattr entry crosses the end of xattr space\n"); + break; } - free(xattr_addr); + print_xattr_entry(ent); } + free(xattr_addr); +out: printf("\n"); } diff --git a/fsck/xattr.c b/fsck/xattr.c index 8e66873..a77b2e6 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) { struct f2fs_node *node_blk = NULL; struct node_info ni; int ret; @@ -65,11 +66,19 @@ void *read_all_xattrs(struct f2fs_sb_info *sbi, struct f2fs_node *inode) return txattr_addr; } -static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index, - size_t len, const char *name) +static struct f2fs_xattr_entry *__find_xattr(void *base_addr, + void *last_base_addr, int index, + size_t len, const char *name) { struct f2fs_xattr_entry *entry; + list_for_each_xattr(entry, base_addr) { + if ((void *)(entry) + sizeof(__u32) > last_base_addr || + (void *)XATTR_NEXT_ENTRY(entry) > last_base_addr) { + MSG(0, "xattr entry crosses the end of xattr space\n"); + return NULL; + } + if (entry->e_name_index != index) continue; if (entry->e_name_len != len) @@ -80,7 +89,7 @@ static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index, 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; @@ -135,6 +144,7 @@ int f2fs_setxattr(struct f2fs_sb_info *sbi, nid_t ino, int index, const char *na { struct f2fs_node *inode; void *base_addr; + void *last_base_addr; struct f2fs_xattr_entry *here, *last; struct node_info ni; int error = 0; @@ -166,10 +176,17 @@ 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); - here = __find_xattr(base_addr, index, len, name); + last_base_addr = (void *)base_addr + XATTR_SIZE(&inode->i); + + here = __find_xattr(base_addr, last_base_addr, index, len, name); + if (!here) { + MSG(0, "Need to run fsck due to corrupted xattr.\n"); + error = -EINVAL; + goto exit; + } found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1; diff --git a/fsck/xattr.h b/fsck/xattr.h index 22ea35c..5a40018 100644 --- a/fsck/xattr.h +++ b/fsck/xattr.h @@ -132,6 +132,12 @@ static inline int f2fs_acl_count(int size) !IS_XATTR_LAST_ENTRY(entry); \ entry = XATTR_NEXT_ENTRY(entry)) +#define VALID_XATTR_BLOCK_SIZE (F2FS_BLKSIZE - sizeof(struct node_footer)) + +#define XATTR_SIZE(i) ((le32_to_cpu((i)->i_xattr_nid) ? \ + VALID_XATTR_BLOCK_SIZE : 0) + \ + (inline_xattr_size(i))) + #define MIN_OFFSET XATTR_ALIGN(F2FS_BLKSIZE - \ sizeof(struct node_footer) - sizeof(__u32)) |