mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
ext4: check EA value offset when loading
commit a0626e7595
upstream.
When loading extended attributes, check each entry's value offset to
make sure it doesn't collide with the entries.
Without this check it is easy to crash the kernel by mounting a
malicious FS containing a file with an EA wherein e_value_offs = 0 and
e_value_size > 0 and then deleting the EA, which corrupts the name
list.
(See the f_ea_value_crash test's FS image in e2fsprogs for an example.)
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
[lizf: Backported to 3.4: adjust context]
Signed-off-by: Zefan Li <lizefan@huawei.com>
This commit is contained in:
parent
4e2c6422ab
commit
b0fea9c1a0
1 changed files with 24 additions and 8 deletions
|
@ -144,14 +144,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;
|
||||
}
|
||||
|
||||
|
@ -161,7 +175,8 @@ ext4_xattr_check_block(struct buffer_head *bh)
|
|||
if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
|
||||
BHDR(bh)->h_blocks != cpu_to_le32(1))
|
||||
return -EIO;
|
||||
return ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size);
|
||||
return ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size,
|
||||
bh->b_data);
|
||||
}
|
||||
|
||||
static inline int
|
||||
|
@ -274,7 +289,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,
|
||||
|
@ -402,7 +417,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),
|
||||
|
@ -914,7 +929,8 @@ 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. */
|
||||
|
|
Loading…
Reference in a new issue