Commit 5f8e97a8 authored by Jan Kara's avatar Jan Kara Committed by Yifan Qiao
Browse files

ext4: fold quota accounting into ext4_xattr_inode_lookup_create()

mainline inclusion
from mainline-v6.9-rc1
commit 8208c41c43ad5e9b63dce6c45a73e326109ca658
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IAD03M
CVE: CVE-2024-40972

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8208c41c43ad5e9b63dce6c45a73e326109ca658



--------------------------------

When allocating EA inode, quota accounting is done just before
ext4_xattr_inode_lookup_create(). Logically these two operations belong
together so just fold quota accounting into
ext4_xattr_inode_lookup_create(). We also make
ext4_xattr_inode_lookup_create() return the looked up / created inode to
convert the function to a more standard calling convention.

Signed-off-by: default avatarJan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20240209112107.10585-1-jack@suse.cz


Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
Conflicts:
	fs/ext4/xattr.c
[context differences]
Signed-off-by: default avatarYifan Qiao <qiaoyifan4@huawei.com>
parent 9bb937dc
Loading
Loading
Loading
Loading
+24 −25
Original line number Diff line number Diff line
@@ -1512,45 +1512,49 @@ ext4_xattr_inode_cache_find(struct inode *inode, const void *value,
/*
 * Add value of the EA in an inode.
 */
static int ext4_xattr_inode_lookup_create(handle_t *handle, struct inode *inode,
					  const void *value, size_t value_len,
					  struct inode **ret_inode)
static struct inode *ext4_xattr_inode_lookup_create(handle_t *handle,
		struct inode *inode, const void *value, size_t value_len)
{
	struct inode *ea_inode;
	u32 hash;
	int err;

	/* Account inode & space to quota even if sharing... */
	err = ext4_xattr_inode_alloc_quota(inode, value_len);
	if (err)
		return ERR_PTR(err);

	hash = ext4_xattr_inode_hash(EXT4_SB(inode->i_sb), value, value_len);
	ea_inode = ext4_xattr_inode_cache_find(inode, value, value_len, hash);
	if (ea_inode) {
		err = ext4_xattr_inode_inc_ref(handle, ea_inode);
		if (err) {
			iput(ea_inode);
			return err;
		}

		*ret_inode = ea_inode;
		return 0;
		if (err)
			goto out_err;
		return ea_inode;
	}

	/* Create an inode for the EA value */
	ea_inode = ext4_xattr_inode_create(handle, inode, hash);
	if (IS_ERR(ea_inode))
		return PTR_ERR(ea_inode);
	if (IS_ERR(ea_inode)) {
		ext4_xattr_inode_free_quota(inode, NULL, value_len);
		return ea_inode;
	}

	err = ext4_xattr_inode_write(handle, ea_inode, value, value_len);
	if (err) {
		ext4_xattr_inode_dec_ref(handle, ea_inode);
		iput(ea_inode);
		return err;
		goto out_err;
	}

	if (EA_INODE_CACHE(inode))
		mb_cache_entry_create(EA_INODE_CACHE(inode), GFP_NOFS, hash,
				      ea_inode->i_ino, true /* reusable */);

	*ret_inode = ea_inode;
	return 0;
	return ea_inode;
out_err:
	iput(ea_inode);
	ext4_xattr_inode_free_quota(inode, NULL, value_len);
	return ERR_PTR(err);
}

/*
@@ -1658,16 +1662,11 @@ static int ext4_xattr_set_entry(struct ext4_xattr_info *i,
	if (i->value && in_inode) {
		WARN_ON_ONCE(!i->value_len);

		ret = ext4_xattr_inode_alloc_quota(inode, i->value_len);
		if (ret)
			goto out;

		ret = ext4_xattr_inode_lookup_create(handle, inode, i->value,
						     i->value_len,
						     &new_ea_inode);
		if (ret) {
		new_ea_inode = ext4_xattr_inode_lookup_create(handle, inode,
					i->value, i->value_len);
		if (IS_ERR(new_ea_inode)) {
			ret = PTR_ERR(new_ea_inode);
			new_ea_inode = NULL;
			ext4_xattr_inode_free_quota(inode, NULL, i->value_len);
			goto out;
		}
	}