aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-15 09:21:29 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-15 09:21:29 +0000
commitf2034481b5bb5a93c7aab40d857618aa0913a208 (patch)
tree211911b40f11a7e070e60d26679c3e092115c465
parentf293fb346587de170b675378815f966b55691a34 (diff)
parent8540e122d808430da8c3640e7f1976358e3b3d7f (diff)
downloadf2fs-tools-aml_tz5_341510010.tar.gz
Snap for 11224086 from 8540e122d808430da8c3640e7f1976358e3b3d7f to mainline-tzdata5-releaseaml_tz5_341510070aml_tz5_341510050aml_tz5_341510010aml_tz5_341510010
Change-Id: I1b532163403947e10a3cc8fe547e1e6755ae7777
-rw-r--r--fsck/dump.c11
-rw-r--r--fsck/fsck.c58
-rw-r--r--fsck/fsck.h4
-rw-r--r--fsck/mount.c20
-rw-r--r--fsck/xattr.c31
-rw-r--r--fsck/xattr.h6
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))