[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20220607164953.640287176@linuxfoundation.org>
Date: Tue, 7 Jun 2022 18:55:48 +0200
From: Greg Kroah-Hartman <gregkh@...uxfoundation.org>
To: linux-kernel@...r.kernel.org
Cc: Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
stable@...r.kernel.org,
Sweet Tea Dorminy <sweettea-kernel@...miny.me>,
Omar Sandoval <osandov@...com>,
David Sterba <dsterba@...e.com>,
Sasha Levin <sashal@...nel.org>
Subject: [PATCH 5.17 156/772] btrfs: fix anon_dev leak in create_subvol()
From: Omar Sandoval <osandov@...com>
[ Upstream commit 2256e901f5bddc56e24089c96f27b77da932dfcc ]
When btrfs_qgroup_inherit(), btrfs_alloc_tree_block, or
btrfs_insert_root() fail in create_subvol(), we return without freeing
anon_dev. Reorganize the error handling in create_subvol() to fix this.
Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@...miny.me>
Signed-off-by: Omar Sandoval <osandov@...com>
Reviewed-by: David Sterba <dsterba@...e.com>
Signed-off-by: David Sterba <dsterba@...e.com>
Signed-off-by: Sasha Levin <sashal@...nel.org>
---
fs/btrfs/ioctl.c | 49 +++++++++++++++++++++++-------------------------
1 file changed, 23 insertions(+), 26 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 8fe9d55d6862..072cdcab3061 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -544,7 +544,7 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
struct timespec64 cur_time = current_time(dir);
struct inode *inode;
int ret;
- dev_t anon_dev = 0;
+ dev_t anon_dev;
u64 objectid;
u64 index = 0;
@@ -554,11 +554,7 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
ret = btrfs_get_free_objectid(fs_info->tree_root, &objectid);
if (ret)
- goto fail_free;
-
- ret = get_anon_bdev(&anon_dev);
- if (ret < 0)
- goto fail_free;
+ goto out_root_item;
/*
* Don't create subvolume whose level is not zero. Or qgroup will be
@@ -566,9 +562,13 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
*/
if (btrfs_qgroup_level(objectid)) {
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);
/*
* The same as the snapshot creation, please see the comment
@@ -576,26 +576,26 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
*/
ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 8, false);
if (ret)
- goto fail_free;
+ goto out_anon_dev;
trans = btrfs_start_transaction(root, 0);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
btrfs_subvolume_release_metadata(root, &block_rsv);
- goto fail_free;
+ goto out_anon_dev;
}
trans->block_rsv = &block_rsv;
trans->bytes_reserved = block_rsv.size;
ret = btrfs_qgroup_inherit(trans, 0, objectid, inherit);
if (ret)
- goto fail;
+ goto out;
leaf = btrfs_alloc_tree_block(trans, root, 0, objectid, NULL, 0, 0, 0,
BTRFS_NESTING_NORMAL);
if (IS_ERR(leaf)) {
ret = PTR_ERR(leaf);
- goto fail;
+ goto out;
}
btrfs_mark_buffer_dirty(leaf);
@@ -650,7 +650,7 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
btrfs_tree_unlock(leaf);
btrfs_free_tree_block(trans, objectid, leaf, 0, 1);
free_extent_buffer(leaf);
- goto fail;
+ goto out;
}
free_extent_buffer(leaf);
@@ -659,19 +659,18 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
key.offset = (u64)-1;
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);
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;
ret = btrfs_record_root_in_trans(trans, new_root);
if (ret) {
btrfs_put_root(new_root);
btrfs_abort_transaction(trans, ret);
- goto fail;
+ goto out;
}
ret = btrfs_create_subvol_root(trans, new_root, root, mnt_userns);
@@ -679,7 +678,7 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
if (ret) {
/* We potentially lose an unused inode item here */
btrfs_abort_transaction(trans, ret);
- goto fail;
+ goto out;
}
/*
@@ -688,28 +687,28 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
ret = btrfs_set_inode_index(BTRFS_I(dir), &index);
if (ret) {
btrfs_abort_transaction(trans, ret);
- goto fail;
+ goto out;
}
ret = btrfs_insert_dir_item(trans, name, namelen, BTRFS_I(dir), &key,
BTRFS_FT_DIR, index);
if (ret) {
btrfs_abort_transaction(trans, ret);
- goto fail;
+ goto out;
}
btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2);
ret = btrfs_update_inode(trans, root, BTRFS_I(dir));
if (ret) {
btrfs_abort_transaction(trans, ret);
- goto fail;
+ goto out;
}
ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid,
btrfs_ino(BTRFS_I(dir)), index, name, namelen);
if (ret) {
btrfs_abort_transaction(trans, ret);
- goto fail;
+ goto out;
}
ret = btrfs_uuid_tree_add(trans, root_item->uuid,
@@ -717,8 +716,7 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
if (ret)
btrfs_abort_transaction(trans, ret);
-fail:
- kfree(root_item);
+out:
trans->block_rsv = NULL;
trans->bytes_reserved = 0;
btrfs_subvolume_release_metadata(root, &block_rsv);
@@ -734,11 +732,10 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
return PTR_ERR(inode);
d_instantiate(dentry, inode);
}
- return ret;
-
-fail_free:
+out_anon_dev:
if (anon_dev)
free_anon_bdev(anon_dev);
+out_root_item:
kfree(root_item);
return ret;
}
--
2.35.1
Powered by blists - more mailing lists