Unverified Commit 2644e97c authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!4925 v2 btrfs: do not ASSERT() if the newly created subvolume already got read

Merge Pull Request from: @ci-robot 
 
PR sync from: Long Li <leo.lilong@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/C6Q372RAQA75LJQUYR4774CD5PS7XQF3/ 
This patch set fix CVE-2024-23850.

Filipe Manana (1):
  btrfs: fix double free of anonymous device after snapshot creation
    failure

Qu Wenruo (1):
  btrfs: do not ASSERT() if the newly created subvolume already got read


-- 
2.31.1
 
https://gitee.com/src-openeuler/kernel/issues/I8YCA2 
 
Link:https://gitee.com/openeuler/kernel/pulls/4925

 

Reviewed-by: default avatarzhangyi (F) <yi.zhang@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents 0547e83f 81af5454
Loading
Loading
Loading
Loading
+19 −10
Original line number Diff line number Diff line
@@ -1534,12 +1534,12 @@ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info)
 *
 * @objectid:	root id
 * @anon_dev:	preallocated anonymous block device number for new roots,
 * 		pass 0 for new allocation.
 *		pass NULL for a new allocation.
 * @check_ref:	whether to check root item references, If true, return -ENOENT
 *		for orphan roots
 */
static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info,
					     u64 objectid, dev_t anon_dev,
					     u64 objectid, dev_t *anon_dev,
					     bool check_ref)
{
	struct btrfs_root *root;
@@ -1553,8 +1553,17 @@ static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info,
again:
	root = btrfs_lookup_fs_root(fs_info, objectid);
	if (root) {
		/* Shouldn't get preallocated anon_dev for cached roots */
		ASSERT(!anon_dev);
		/*
		 * Some other caller may have read out the newly inserted
		 * subvolume already (for things like backref walk etc).  Not
		 * that common but still possible.  In that case, we just need
		 * to free the anon_dev.
		 */
		if (unlikely(anon_dev && *anon_dev)) {
			free_anon_bdev(*anon_dev);
			*anon_dev = 0;
		}

		if (check_ref && btrfs_root_refs(&root->root_item) == 0) {
			btrfs_put_root(root);
			return ERR_PTR(-ENOENT);
@@ -1574,7 +1583,7 @@ static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info,
		goto fail;
	}

	ret = btrfs_init_fs_root(root, anon_dev);
	ret = btrfs_init_fs_root(root, anon_dev ? *anon_dev : 0);
	if (ret)
		goto fail;

@@ -1610,7 +1619,7 @@ static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info,
	 * root's anon_dev to 0 to avoid a double free, once by btrfs_put_root()
	 * and once again by our caller.
	 */
	if (anon_dev)
	if (anon_dev && *anon_dev)
		root->anon_dev = 0;
	btrfs_put_root(root);
	return ERR_PTR(ret);
@@ -1626,7 +1635,7 @@ static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info,
struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
				     u64 objectid, bool check_ref)
{
	return btrfs_get_root_ref(fs_info, objectid, 0, check_ref);
	return btrfs_get_root_ref(fs_info, objectid, NULL, check_ref);
}

/*
@@ -1634,11 +1643,11 @@ struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
 * the anonymous block device id
 *
 * @objectid:	tree objectid
 * @anon_dev:	if zero, allocate a new anonymous block device or use the
 *		parameter value
 * @anon_dev:	if NULL, allocate a new anonymous block device or use the
 *		parameter value if not NULL
 */
struct btrfs_root *btrfs_get_new_fs_root(struct btrfs_fs_info *fs_info,
					 u64 objectid, dev_t anon_dev)
					 u64 objectid, dev_t *anon_dev)
{
	return btrfs_get_root_ref(fs_info, objectid, anon_dev, true);
}
+1 −1
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info);
struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
				     u64 objectid, bool check_ref);
struct btrfs_root *btrfs_get_new_fs_root(struct btrfs_fs_info *fs_info,
					 u64 objectid, dev_t anon_dev);
					 u64 objectid, dev_t *anon_dev);
struct btrfs_root *btrfs_get_fs_root_commit_root(struct btrfs_fs_info *fs_info,
						 struct btrfs_path *path,
						 u64 objectid);
+1 −1
Original line number Diff line number Diff line
@@ -704,7 +704,7 @@ static noinline int create_subvol(struct inode *dir,
	leaf = NULL;

	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)) {
		free_anon_bdev(anon_dev);
		ret = PTR_ERR(new_root);
+1 −1
Original line number Diff line number Diff line
@@ -1686,7 +1686,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
	}

	key.offset = (u64)-1;
	pending->snap = btrfs_get_new_fs_root(fs_info, objectid, pending->anon_dev);
	pending->snap = btrfs_get_new_fs_root(fs_info, objectid, &pending->anon_dev);
	if (IS_ERR(pending->snap)) {
		ret = PTR_ERR(pending->snap);
		pending->snap = NULL;