|
@@ -190,14 +190,28 @@ ext4_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
-ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end)
|
|
|
+ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end,
|
|
|
+ void *value_start)
|
|
|
{
|
|
|
- while (!IS_LAST_ENTRY(entry)) {
|
|
|
- struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(entry);
|
|
|
+ struct ext4_xattr_entry *e = entry;
|
|
|
+
|
|
|
+ while (!IS_LAST_ENTRY(e)) {
|
|
|
+ struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(e);
|
|
|
if ((void *)next >= end)
|
|
|
return -EIO;
|
|
|
- entry = next;
|
|
|
+ e = next;
|
|
|
}
|
|
|
+
|
|
|
+ while (!IS_LAST_ENTRY(entry)) {
|
|
|
+ if (entry->e_value_size != 0 &&
|
|
|
+ (value_start + le16_to_cpu(entry->e_value_offs) <
|
|
|
+ (void *)e + sizeof(__u32) ||
|
|
|
+ value_start + le16_to_cpu(entry->e_value_offs) +
|
|
|
+ le32_to_cpu(entry->e_value_size) > end))
|
|
|
+ return -EIO;
|
|
|
+ entry = EXT4_XATTR_NEXT(entry);
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -214,7 +228,8 @@ ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh)
|
|
|
return -EIO;
|
|
|
if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh)))
|
|
|
return -EIO;
|
|
|
- error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size);
|
|
|
+ error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size,
|
|
|
+ bh->b_data);
|
|
|
if (!error)
|
|
|
set_buffer_verified(bh);
|
|
|
return error;
|
|
@@ -331,7 +346,7 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
|
|
|
header = IHDR(inode, raw_inode);
|
|
|
entry = IFIRST(header);
|
|
|
end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
|
|
|
- error = ext4_xattr_check_names(entry, end);
|
|
|
+ error = ext4_xattr_check_names(entry, end, entry);
|
|
|
if (error)
|
|
|
goto cleanup;
|
|
|
error = ext4_xattr_find_entry(&entry, name_index, name,
|
|
@@ -463,7 +478,7 @@ ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size)
|
|
|
raw_inode = ext4_raw_inode(&iloc);
|
|
|
header = IHDR(inode, raw_inode);
|
|
|
end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
|
|
|
- error = ext4_xattr_check_names(IFIRST(header), end);
|
|
|
+ error = ext4_xattr_check_names(IFIRST(header), end, IFIRST(header));
|
|
|
if (error)
|
|
|
goto cleanup;
|
|
|
error = ext4_xattr_list_entries(dentry, IFIRST(header),
|
|
@@ -980,7 +995,8 @@ int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i,
|
|
|
is->s.here = is->s.first;
|
|
|
is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
|
|
|
if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) {
|
|
|
- error = ext4_xattr_check_names(IFIRST(header), is->s.end);
|
|
|
+ error = ext4_xattr_check_names(IFIRST(header), is->s.end,
|
|
|
+ IFIRST(header));
|
|
|
if (error)
|
|
|
return error;
|
|
|
/* Find the named attribute. */
|