Unverified Commit 290da172 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!13051 ext4: fix CVE-2024-47701

Merge Pull Request from: @ci-robot 
 
PR sync from: Baokun Li <libaokun1@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/WDIUM45LKOGIUNAERWKZ3LU4GYYEM2RV/ 
Thadeu Lima de Souza Cascardo (4):
  ext4: ext4_search_dir should return a proper error
  ext4: return error on ext4_find_inline_entry
  ext4: explicitly exit when ext4_find_inline_entry returns an error
  ext4: avoid OOB when system.data xattr changes underneath the
    filesystem


-- 
2.46.1
 
https://gitee.com/src-openeuler/kernel/issues/IAYPK6 
 
Link:https://gitee.com/openeuler/kernel/pulls/13051 
parents af51a473 613d7dab
Loading
Loading
Loading
Loading
+25 −10
Original line number Diff line number Diff line
@@ -1654,24 +1654,36 @@ struct buffer_head *ext4_find_inline_entry(struct inode *dir,
					struct ext4_dir_entry_2 **res_dir,
					int *has_inline_data)
{
	struct ext4_xattr_ibody_find is = {
		.s = { .not_found = -ENODATA, },
	};
	struct ext4_xattr_info i = {
		.name_index = EXT4_XATTR_INDEX_SYSTEM,
		.name = EXT4_XATTR_SYSTEM_DATA,
	};
	int ret;
	struct ext4_iloc iloc;
	void *inline_start;
	int inline_size;

	if (ext4_get_inode_loc(dir, &iloc))
		return NULL;
	ret = ext4_get_inode_loc(dir, &is.iloc);
	if (ret)
		return ERR_PTR(ret);

	down_read(&EXT4_I(dir)->xattr_sem);

	ret = ext4_xattr_ibody_find(dir, &i, &is);
	if (ret)
		goto out;

	if (!ext4_has_inline_data(dir)) {
		*has_inline_data = 0;
		goto out;
	}

	inline_start = (void *)ext4_raw_inode(&iloc)->i_block +
	inline_start = (void *)ext4_raw_inode(&is.iloc)->i_block +
						EXT4_INLINE_DOTDOT_SIZE;
	inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DOTDOT_SIZE;
	ret = ext4_search_dir(iloc.bh, inline_start, inline_size,
	ret = ext4_search_dir(is.iloc.bh, inline_start, inline_size,
			      dir, fname, 0, res_dir);
	if (ret == 1)
		goto out_find;
@@ -1681,20 +1693,23 @@ struct buffer_head *ext4_find_inline_entry(struct inode *dir,
	if (ext4_get_inline_size(dir) == EXT4_MIN_INLINE_DATA_SIZE)
		goto out;

	inline_start = ext4_get_inline_xattr_pos(dir, &iloc);
	inline_start = ext4_get_inline_xattr_pos(dir, &is.iloc);
	inline_size = ext4_get_inline_size(dir) - EXT4_MIN_INLINE_DATA_SIZE;

	ret = ext4_search_dir(iloc.bh, inline_start, inline_size,
	ret = ext4_search_dir(is.iloc.bh, inline_start, inline_size,
			      dir, fname, 0, res_dir);
	if (ret == 1)
		goto out_find;

out:
	brelse(iloc.bh);
	iloc.bh = NULL;
	brelse(is.iloc.bh);
	if (ret < 0)
		is.iloc.bh = ERR_PTR(ret);
	else
		is.iloc.bh = NULL;
out_find:
	up_read(&EXT4_I(dir)->xattr_sem);
	return iloc.bh;
	return is.iloc.bh;
}

int ext4_delete_inline_entry(handle_t *handle,
+8 −6
Original line number Diff line number Diff line
@@ -1448,7 +1448,7 @@ static inline bool ext4_match(const struct inode *parent,
}

/*
 * Returns 0 if not found, -1 on failure, and 1 on success
 * Returns 0 if not found, -EFSCORRUPTED on failure, and 1 on success
 */
int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
		    struct inode *dir, struct ext4_filename *fname,
@@ -1469,7 +1469,7 @@ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
			 * a full check */
			if (ext4_check_dir_entry(dir, NULL, de, bh, search_buf,
						 buf_size, offset))
				return -1;
				return -EFSCORRUPTED;
			*res_dir = de;
			return 1;
		}
@@ -1477,7 +1477,7 @@ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
		de_len = ext4_rec_len_from_disk(de->rec_len,
						dir->i_sb->s_blocksize);
		if (de_len <= 0)
			return -1;
			return -EFSCORRUPTED;
		offset += de_len;
		de = (struct ext4_dir_entry_2 *) ((char *) de + de_len);
	}
@@ -1540,7 +1540,7 @@ static struct buffer_head *__ext4_find_entry(struct inode *dir,
					     &has_inline_data);
		if (inlined)
			*inlined = has_inline_data;
		if (has_inline_data)
		if (has_inline_data || IS_ERR(ret))
			goto cleanup_and_exit;
	}

@@ -1629,9 +1629,11 @@ static struct buffer_head *__ext4_find_entry(struct inode *dir,
			goto cleanup_and_exit;
		} else {
			brelse(bh);
			if (i < 0)
			if (i < 0) {
				ret = ERR_PTR(i);
				goto cleanup_and_exit;
			}
		}
	next:
		if (++block >= nblocks)
			block = 0;
@@ -1724,7 +1726,7 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir,
		if (retval == 1)
			goto success;
		brelse(bh);
		if (retval == -1) {
		if (retval < 0) {
			bh = ERR_PTR(ERR_BAD_DX_DIR);
			goto errout;
		}