Unverified Commit 3b9084bc authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!8195 CVE-2024-35956

Merge Pull Request from: @ci-robot 
 
PR sync from: Ye Bin <yebin10@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/COL4UOVOHLSZZ43MPRFXIOLIPK3UCLN3/ 
Boris Burkov (1):
  btrfs: qgroup: fix qgroup prealloc rsv leak in subvolume operations

Omar Sandoval (1):
  btrfs: fix anon_dev leak in create_subvol()


-- 
2.31.1
 
https://gitee.com/src-openeuler/kernel/issues/I9QR71 
 
Link:https://gitee.com/openeuler/kernel/pulls/8195

 

Reviewed-by: default avatarzhangyi (F) <yi.zhang@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents 3edd0f0e 4e8cb33d
Loading
Loading
Loading
Loading
+0 −2
Original line number Original line Diff line number Diff line
@@ -2667,8 +2667,6 @@ enum btrfs_flush_state {
int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
				     struct btrfs_block_rsv *rsv,
				     struct btrfs_block_rsv *rsv,
				     int nitems, bool use_global_rsv);
				     int nitems, bool use_global_rsv);
void btrfs_subvolume_release_metadata(struct btrfs_root *root,
				      struct btrfs_block_rsv *rsv);
void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes);
void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes);


int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes);
int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes);
+12 −1
Original line number Original line Diff line number Diff line
@@ -4021,6 +4021,7 @@ int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry)
	struct btrfs_block_rsv block_rsv;
	struct btrfs_block_rsv block_rsv;
	u64 root_flags;
	u64 root_flags;
	int ret;
	int ret;
	u64 qgroup_reserved = 0;
	int err;
	int err;


	/*
	/*
@@ -4063,12 +4064,20 @@ int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry)
	err = btrfs_subvolume_reserve_metadata(root, &block_rsv, 5, true);
	err = btrfs_subvolume_reserve_metadata(root, &block_rsv, 5, true);
	if (err)
	if (err)
		goto out_up_write;
		goto out_up_write;
	qgroup_reserved = block_rsv.qgroup_rsv_reserved;


	trans = btrfs_start_transaction(root, 0);
	trans = btrfs_start_transaction(root, 0);
	if (IS_ERR(trans)) {
	if (IS_ERR(trans)) {
		err = PTR_ERR(trans);
		err = PTR_ERR(trans);
		goto out_release;
		goto out_release;
	}
	}
	ret = btrfs_record_root_in_trans(trans, root);
	if (ret) {
		btrfs_abort_transaction(trans, ret);
		goto out_end_trans;
	}
	btrfs_qgroup_convert_reserved_meta(root, qgroup_reserved);
	qgroup_reserved = 0;
	trans->block_rsv = &block_rsv;
	trans->block_rsv = &block_rsv;
	trans->bytes_reserved = block_rsv.size;
	trans->bytes_reserved = block_rsv.size;


@@ -4129,7 +4138,9 @@ int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry)
		err = ret;
		err = ret;
	inode->i_flags |= S_DEAD;
	inode->i_flags |= S_DEAD;
out_release:
out_release:
	btrfs_subvolume_release_metadata(root, &block_rsv);
	btrfs_block_rsv_release(fs_info, &block_rsv, (u64)-1, NULL);
	if (qgroup_reserved)
		btrfs_qgroup_free_meta_prealloc(root, qgroup_reserved);
out_up_write:
out_up_write:
	up_write(&fs_info->subvol_sem);
	up_write(&fs_info->subvol_sem);
	if (err) {
	if (err) {
+49 −32
Original line number Original line Diff line number Diff line
@@ -592,8 +592,9 @@ static noinline int create_subvol(struct inode *dir,
	struct inode *inode;
	struct inode *inode;
	int ret;
	int ret;
	int err;
	int err;
	dev_t anon_dev = 0;
	dev_t anon_dev;
	u64 objectid;
	u64 objectid;
	u64 qgroup_reserved = 0;
	u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
	u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
	u64 index = 0;
	u64 index = 0;


@@ -603,11 +604,7 @@ static noinline int create_subvol(struct inode *dir,


	ret = btrfs_find_free_objectid(fs_info->tree_root, &objectid);
	ret = btrfs_find_free_objectid(fs_info->tree_root, &objectid);
	if (ret)
	if (ret)
		goto fail_free;
		goto out_root_item;

	ret = get_anon_bdev(&anon_dev);
	if (ret < 0)
		goto fail_free;


	/*
	/*
	 * Don't create subvolume whose level is not zero. Or qgroup will be
	 * Don't create subvolume whose level is not zero. Or qgroup will be
@@ -615,9 +612,13 @@ static noinline int create_subvol(struct inode *dir,
	 */
	 */
	if (btrfs_qgroup_level(objectid)) {
	if (btrfs_qgroup_level(objectid)) {
		ret = -ENOSPC;
		ret = -ENOSPC;
		goto fail_free;
		goto out_root_item;
	}
	}


	ret = get_anon_bdev(&anon_dev);
	if (ret < 0)
		goto out_root_item;

	btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
	btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
	/*
	/*
	 * The same as the snapshot creation, please see the comment
	 * The same as the snapshot creation, please see the comment
@@ -625,26 +626,31 @@ static noinline int create_subvol(struct inode *dir,
	 */
	 */
	ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 8, false);
	ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 8, false);
	if (ret)
	if (ret)
		goto fail_free;
		goto out_anon_dev;
	qgroup_reserved = block_rsv.qgroup_rsv_reserved;


	trans = btrfs_start_transaction(root, 0);
	trans = btrfs_start_transaction(root, 0);
	if (IS_ERR(trans)) {
	if (IS_ERR(trans)) {
		ret = PTR_ERR(trans);
		ret = PTR_ERR(trans);
		btrfs_subvolume_release_metadata(root, &block_rsv);
		goto out_release_rsv;
		goto fail_free;
	}
	}
	ret = btrfs_record_root_in_trans(trans, BTRFS_I(dir)->root);
	if (ret)
		goto out;
	btrfs_qgroup_convert_reserved_meta(root, qgroup_reserved);
	qgroup_reserved = 0;
	trans->block_rsv = &block_rsv;
	trans->block_rsv = &block_rsv;
	trans->bytes_reserved = block_rsv.size;
	trans->bytes_reserved = block_rsv.size;


	ret = btrfs_qgroup_inherit(trans, 0, objectid, inherit);
	ret = btrfs_qgroup_inherit(trans, 0, objectid, inherit);
	if (ret)
	if (ret)
		goto fail;
		goto out;


	leaf = btrfs_alloc_tree_block(trans, root, 0, objectid, NULL, 0, 0, 0,
	leaf = btrfs_alloc_tree_block(trans, root, 0, objectid, NULL, 0, 0, 0,
				      BTRFS_NESTING_NORMAL);
				      BTRFS_NESTING_NORMAL);
	if (IS_ERR(leaf)) {
	if (IS_ERR(leaf)) {
		ret = PTR_ERR(leaf);
		ret = PTR_ERR(leaf);
		goto fail;
		goto out;
	}
	}


	btrfs_mark_buffer_dirty(leaf);
	btrfs_mark_buffer_dirty(leaf);
@@ -697,7 +703,7 @@ static noinline int create_subvol(struct inode *dir,
		 */
		 */
		btrfs_free_tree_block(trans, root, leaf, 0, 1);
		btrfs_free_tree_block(trans, root, leaf, 0, 1);
		free_extent_buffer(leaf);
		free_extent_buffer(leaf);
		goto fail;
		goto out;
	}
	}


	free_extent_buffer(leaf);
	free_extent_buffer(leaf);
@@ -706,12 +712,11 @@ static noinline int create_subvol(struct inode *dir,
	key.offset = (u64)-1;
	key.offset = (u64)-1;
	new_root = btrfs_get_new_fs_root(fs_info, objectid, &anon_dev);
	new_root = btrfs_get_new_fs_root(fs_info, objectid, &anon_dev);
	if (IS_ERR(new_root)) {
	if (IS_ERR(new_root)) {
		free_anon_bdev(anon_dev);
		ret = PTR_ERR(new_root);
		ret = PTR_ERR(new_root);
		btrfs_abort_transaction(trans, ret);
		btrfs_abort_transaction(trans, ret);
		goto fail;
		goto out;
	}
	}
	/* Freeing will be done in btrfs_put_root() of new_root */
	/* anon_dev is owned by new_root now. */
	anon_dev = 0;
	anon_dev = 0;


	btrfs_record_root_in_trans(trans, new_root);
	btrfs_record_root_in_trans(trans, new_root);
@@ -721,7 +726,7 @@ static noinline int create_subvol(struct inode *dir,
	if (ret) {
	if (ret) {
		/* We potentially lose an unused inode item here */
		/* We potentially lose an unused inode item here */
		btrfs_abort_transaction(trans, ret);
		btrfs_abort_transaction(trans, ret);
		goto fail;
		goto out;
	}
	}


	mutex_lock(&new_root->objectid_mutex);
	mutex_lock(&new_root->objectid_mutex);
@@ -734,28 +739,28 @@ static noinline int create_subvol(struct inode *dir,
	ret = btrfs_set_inode_index(BTRFS_I(dir), &index);
	ret = btrfs_set_inode_index(BTRFS_I(dir), &index);
	if (ret) {
	if (ret) {
		btrfs_abort_transaction(trans, ret);
		btrfs_abort_transaction(trans, ret);
		goto fail;
		goto out;
	}
	}


	ret = btrfs_insert_dir_item(trans, name, namelen, BTRFS_I(dir), &key,
	ret = btrfs_insert_dir_item(trans, name, namelen, BTRFS_I(dir), &key,
				    BTRFS_FT_DIR, index);
				    BTRFS_FT_DIR, index);
	if (ret) {
	if (ret) {
		btrfs_abort_transaction(trans, ret);
		btrfs_abort_transaction(trans, ret);
		goto fail;
		goto out;
	}
	}


	btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2);
	btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2);
	ret = btrfs_update_inode(trans, root, dir);
	ret = btrfs_update_inode(trans, root, dir);
	if (ret) {
	if (ret) {
		btrfs_abort_transaction(trans, ret);
		btrfs_abort_transaction(trans, ret);
		goto fail;
		goto out;
	}
	}


	ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid,
	ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid,
				 btrfs_ino(BTRFS_I(dir)), index, name, namelen);
				 btrfs_ino(BTRFS_I(dir)), index, name, namelen);
	if (ret) {
	if (ret) {
		btrfs_abort_transaction(trans, ret);
		btrfs_abort_transaction(trans, ret);
		goto fail;
		goto out;
	}
	}


	ret = btrfs_uuid_tree_add(trans, root_item->uuid,
	ret = btrfs_uuid_tree_add(trans, root_item->uuid,
@@ -763,11 +768,9 @@ static noinline int create_subvol(struct inode *dir,
	if (ret)
	if (ret)
		btrfs_abort_transaction(trans, ret);
		btrfs_abort_transaction(trans, ret);


fail:
out:
	kfree(root_item);
	trans->block_rsv = NULL;
	trans->block_rsv = NULL;
	trans->bytes_reserved = 0;
	trans->bytes_reserved = 0;
	btrfs_subvolume_release_metadata(root, &block_rsv);


	err = btrfs_commit_transaction(trans);
	err = btrfs_commit_transaction(trans);
	if (err && !ret)
	if (err && !ret)
@@ -779,11 +782,14 @@ static noinline int create_subvol(struct inode *dir,
			return PTR_ERR(inode);
			return PTR_ERR(inode);
		d_instantiate(dentry, inode);
		d_instantiate(dentry, inode);
	}
	}
	return ret;
out_release_rsv:

	btrfs_block_rsv_release(fs_info, &block_rsv, (u64)-1, NULL);
fail_free:
	if (qgroup_reserved)
		btrfs_qgroup_free_meta_prealloc(root, qgroup_reserved);
out_anon_dev:
	if (anon_dev)
	if (anon_dev)
		free_anon_bdev(anon_dev);
		free_anon_bdev(anon_dev);
out_root_item:
	kfree(root_item);
	kfree(root_item);
	return ret;
	return ret;
}
}
@@ -796,6 +802,8 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
	struct inode *inode;
	struct inode *inode;
	struct btrfs_pending_snapshot *pending_snapshot;
	struct btrfs_pending_snapshot *pending_snapshot;
	struct btrfs_trans_handle *trans;
	struct btrfs_trans_handle *trans;
	struct btrfs_block_rsv *block_rsv;
	u64 qgroup_reserved = 0;
	int ret;
	int ret;


	if (btrfs_root_refs(&root->root_item) == 0)
	if (btrfs_root_refs(&root->root_item) == 0)
@@ -825,8 +833,8 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
		goto free_pending;
		goto free_pending;
	}
	}


	btrfs_init_block_rsv(&pending_snapshot->block_rsv,
	block_rsv = &pending_snapshot->block_rsv;
			     BTRFS_BLOCK_RSV_TEMP);
	btrfs_init_block_rsv(block_rsv, BTRFS_BLOCK_RSV_TEMP);
	/*
	/*
	 * 1 - parent dir inode
	 * 1 - parent dir inode
	 * 2 - dir entries
	 * 2 - dir entries
@@ -836,10 +844,10 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
	 * 1 - UUID item
	 * 1 - UUID item
	 */
	 */
	ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root,
	ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root,
					&pending_snapshot->block_rsv, 8,
					       block_rsv, 8, false);
					false);
	if (ret)
	if (ret)
		goto free_pending;
		goto free_pending;
	qgroup_reserved = block_rsv->qgroup_rsv_reserved;


	pending_snapshot->dentry = dentry;
	pending_snapshot->dentry = dentry;
	pending_snapshot->root = root;
	pending_snapshot->root = root;
@@ -852,6 +860,13 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
		ret = PTR_ERR(trans);
		ret = PTR_ERR(trans);
		goto fail;
		goto fail;
	}
	}
	ret = btrfs_record_root_in_trans(trans, BTRFS_I(dir)->root);
	if (ret) {
		btrfs_end_transaction(trans);
		goto fail;
	}
	btrfs_qgroup_convert_reserved_meta(root, qgroup_reserved);
	qgroup_reserved = 0;


	spin_lock(&fs_info->trans_lock);
	spin_lock(&fs_info->trans_lock);
	list_add(&pending_snapshot->list,
	list_add(&pending_snapshot->list,
@@ -884,7 +899,9 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
	if (ret && pending_snapshot->snap)
	if (ret && pending_snapshot->snap)
		pending_snapshot->snap->anon_dev = 0;
		pending_snapshot->snap->anon_dev = 0;
	btrfs_put_root(pending_snapshot->snap);
	btrfs_put_root(pending_snapshot->snap);
	btrfs_subvolume_release_metadata(root, &pending_snapshot->block_rsv);
	btrfs_block_rsv_release(fs_info, block_rsv, (u64)-1, NULL);
	if (qgroup_reserved)
		btrfs_qgroup_free_meta_prealloc(root, qgroup_reserved);
free_pending:
free_pending:
	if (pending_snapshot->anon_dev)
	if (pending_snapshot->anon_dev)
		free_anon_bdev(pending_snapshot->anon_dev);
		free_anon_bdev(pending_snapshot->anon_dev);
+0 −10
Original line number Original line Diff line number Diff line
@@ -521,13 +521,3 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
	}
	}
	return ret;
	return ret;
}
}

void btrfs_subvolume_release_metadata(struct btrfs_root *root,
				      struct btrfs_block_rsv *rsv)
{
	struct btrfs_fs_info *fs_info = root->fs_info;
	u64 qgroup_to_release;

	btrfs_block_rsv_release(fs_info, rsv, (u64)-1, &qgroup_to_release);
	btrfs_qgroup_convert_reserved_meta(root, qgroup_to_release);
}