Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 86098795 authored by Theodore Ts'o's avatar Theodore Ts'o Committed by Gerrit - the friendly Code Review server
Browse files

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().

Upstream commit: 9e92f48c34eb2b9af9d12f892e2fe1fce5e8ce35
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
Change-Id: Ia66e005d04bf9eccb7febd8cb0733a67f9a4faf4
Git-commit: 1f002539e6da1e03cede84fb3416c58dae2f6f66
Git-repo: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git


Signed-off-by: default avatarAndrey Markovytch <andreym@codeaurora.org>
parent 92d978db
Loading
Loading
Loading
Loading
+28 −4
Original line number Diff line number Diff line
@@ -232,6 +232,27 @@ ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh)
	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
ext4_xattr_check_entry(struct ext4_xattr_entry *entry, size_t size)
{
@@ -343,7 +364,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, entry);
	error = xattr_check_inode(inode, header, end);
	if (error)
		goto cleanup;
	error = ext4_xattr_find_entry(&entry, name_index, name,
@@ -474,7 +495,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, IFIRST(header));
	error = xattr_check_inode(inode, header, end);
	if (error)
		goto cleanup;
	error = ext4_xattr_list_entries(dentry, IFIRST(header),
@@ -990,8 +1011,7 @@ 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,
					       IFIRST(header));
		error = xattr_check_inode(inode, header, is->s.end);
		if (error)
			return error;
		/* Find the named attribute. */
@@ -1288,6 +1308,10 @@ retry:
	last = entry;
	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);
	if (free >= new_extra_isize) {
		entry = IFIRST(header);