Commit 9e92f48c authored by Theodore Ts'o's avatar Theodore Ts'o

ext4: check if in-inode xattr is corrupted in ext4_expand_extra_isize_ea()

We aren't checking to see if the in-inode extended attribute is
corrupted before we try to expand the inode's extra isize fields.

This can lead to potential crashes caused by the BUG_ON() check in
ext4_xattr_shift_entries().
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent 243d5067
...@@ -230,6 +230,27 @@ ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh) ...@@ -230,6 +230,27 @@ ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh)
return error; return error;
} }
static int
__xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header,
void *end, const char *function, unsigned int line)
{
struct ext4_xattr_entry *entry = IFIRST(header);
int error = -EFSCORRUPTED;
if (((void *) header >= end) ||
(header->h_magic != le32_to_cpu(EXT4_XATTR_MAGIC)))
goto errout;
error = ext4_xattr_check_names(entry, end, entry);
errout:
if (error)
__ext4_error_inode(inode, function, line, 0,
"corrupted in-inode xattr");
return error;
}
#define xattr_check_inode(inode, header, end) \
__xattr_check_inode((inode), (header), (end), __func__, __LINE__)
static inline int static inline int
ext4_xattr_check_entry(struct ext4_xattr_entry *entry, size_t size) ext4_xattr_check_entry(struct ext4_xattr_entry *entry, size_t size)
{ {
...@@ -341,7 +362,7 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, ...@@ -341,7 +362,7 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
header = IHDR(inode, raw_inode); header = IHDR(inode, raw_inode);
entry = IFIRST(header); entry = IFIRST(header);
end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
error = ext4_xattr_check_names(entry, end, entry); error = xattr_check_inode(inode, header, end);
if (error) if (error)
goto cleanup; goto cleanup;
error = ext4_xattr_find_entry(&entry, name_index, name, error = ext4_xattr_find_entry(&entry, name_index, name,
...@@ -477,7 +498,7 @@ ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size) ...@@ -477,7 +498,7 @@ ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size)
raw_inode = ext4_raw_inode(&iloc); raw_inode = ext4_raw_inode(&iloc);
header = IHDR(inode, raw_inode); header = IHDR(inode, raw_inode);
end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
error = ext4_xattr_check_names(IFIRST(header), end, IFIRST(header)); error = xattr_check_inode(inode, header, end);
if (error) if (error)
goto cleanup; goto cleanup;
error = ext4_xattr_list_entries(dentry, IFIRST(header), error = ext4_xattr_list_entries(dentry, IFIRST(header),
...@@ -1040,8 +1061,7 @@ int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i, ...@@ -1040,8 +1061,7 @@ int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i,
is->s.here = is->s.first; is->s.here = is->s.first;
is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) {
error = ext4_xattr_check_names(IFIRST(header), is->s.end, error = xattr_check_inode(inode, header, is->s.end);
IFIRST(header));
if (error) if (error)
return error; return error;
/* Find the named attribute. */ /* Find the named attribute. */
...@@ -1356,6 +1376,10 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, ...@@ -1356,6 +1376,10 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
last = entry; last = entry;
total_ino = sizeof(struct ext4_xattr_ibody_header); total_ino = sizeof(struct ext4_xattr_ibody_header);
error = xattr_check_inode(inode, header, end);
if (error)
goto cleanup;
free = ext4_xattr_free_space(last, &min_offs, base, &total_ino); free = ext4_xattr_free_space(last, &min_offs, base, &total_ino);
if (free >= new_extra_isize) { if (free >= new_extra_isize) {
entry = IFIRST(header); entry = IFIRST(header);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment