diff --git a/lib/ext2fs/ext_attr.c b/lib/ext2fs/ext_attr.c index f9b92084..b52abb5b 100644 --- a/lib/ext2fs/ext_attr.c +++ b/lib/ext2fs/ext_attr.c @@ -618,7 +618,7 @@ static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle, size_t *nr_read) { struct ext2_xattr *x; - struct ext2_ext_attr_entry *entry; + struct ext2_ext_attr_entry *entry, *end; const char *prefix; unsigned int remain, prefix_len; errcode_t err; @@ -629,6 +629,24 @@ static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle, while (x->name) x++; + /* find the end */ + end = entries; + remain = storage_size; + while (remain >= sizeof(struct ext2_ext_attr_entry) && + !EXT2_EXT_IS_LAST_ENTRY(end)) { + + /* header eats this space */ + remain -= sizeof(struct ext2_ext_attr_entry); + + /* is attribute name valid? */ + if (EXT2_EXT_ATTR_SIZE(end->e_name_len) > remain) + return EXT2_ET_EA_BAD_NAME_LEN; + + /* attribute len eats this space */ + remain -= EXT2_EXT_ATTR_SIZE(end->e_name_len); + end = EXT2_EXT_ATTR_NEXT(end); + } + entry = entries; remain = storage_size; while (remain >= sizeof(struct ext2_ext_attr_entry) && @@ -638,10 +656,6 @@ static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle, /* header eats this space */ remain -= sizeof(struct ext2_ext_attr_entry); - /* is attribute name valid? */ - if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) - return EXT2_ET_EA_BAD_NAME_LEN; - /* attribute len eats this space */ remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len); @@ -652,6 +666,11 @@ static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle, if (entry->e_value_offs + entry->e_value_size > values_size) return EXT2_ET_EA_BAD_VALUE_OFFSET; + if (entry->e_value_size > 0 && + value_start + entry->e_value_offs < + (void *)end + sizeof(__u32)) + return EXT2_ET_EA_BAD_VALUE_OFFSET; + /* e_value_block must be 0 in inode's ea */ if (entry->e_value_block != 0) return EXT2_ET_BAD_EA_BLOCK_NUM; diff --git a/tests/f_ea_value_crash/expect.1 b/tests/f_ea_value_crash/expect.1 new file mode 100644 index 00000000..8315358c --- /dev/null +++ b/tests/f_ea_value_crash/expect.1 @@ -0,0 +1,15 @@ +Pass 1: Checking inodes, blocks, and sizes +Inode 12 has INLINE_DATA_FL flag but extended attribute not found. Truncate? yes + +Inode 12 extended attribute is corrupt (allocation collision). Clear? yes + +Inode 13 extended attribute is corrupt (allocation collision). Clear? yes + +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 13/128 files (0.0% non-contiguous), 17/512 blocks +Exit status is 1 diff --git a/tests/f_ea_value_crash/expect.2 b/tests/f_ea_value_crash/expect.2 new file mode 100644 index 00000000..06886a4b --- /dev/null +++ b/tests/f_ea_value_crash/expect.2 @@ -0,0 +1,7 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +test_filesys: 13/128 files (0.0% non-contiguous), 17/512 blocks +Exit status is 0 diff --git a/tests/f_ea_value_crash/image.gz b/tests/f_ea_value_crash/image.gz new file mode 100644 index 00000000..c45fb0e1 Binary files /dev/null and b/tests/f_ea_value_crash/image.gz differ diff --git a/tests/f_ea_value_crash/name b/tests/f_ea_value_crash/name new file mode 100644 index 00000000..194bbed3 --- /dev/null +++ b/tests/f_ea_value_crash/name @@ -0,0 +1 @@ +extended attribute value conflicts with key