[ Sasha's backport helper bot ] Hi, The upstream commit SHA1 provided is correct: 74e97958121aa1f5854da6effba70143f051b0cd WARNING: Author mismatch between patch and upstream commit: Backport author: Xiangyu Chen <xiangyu.chen@xxxxxxxxxxxxxxxxx> Commit author: Boris Burkov <boris@xxxxxx> Status in newer kernel trees: 6.12.y | Present (exact SHA1) 6.11.y | Present (exact SHA1) 6.6.y | Present (different SHA1: 14431815a4ae) 6.1.y | Not found Note: The patch differs from the upstream commit: --- 1: 74e97958121aa ! 1: bd47b55888ef7 btrfs: qgroup: fix qgroup prealloc rsv leak in subvolume operations @@ Metadata ## Commit message ## btrfs: qgroup: fix qgroup prealloc rsv leak in subvolume operations + commit 74e97958121aa1f5854da6effba70143f051b0cd upstream. + Create subvolume, create snapshot and delete subvolume all use btrfs_subvolume_reserve_metadata() to reserve metadata for the changes done to the parent subvolume's fs tree, which cannot be mediated in the @@ Commit message Reviewed-by: Qu Wenruo <wqu@xxxxxxxx> Signed-off-by: Boris Burkov <boris@xxxxxx> Signed-off-by: David Sterba <dsterba@xxxxxxxx> + Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> + [Xiangyu: BP to fix CVE-2024-35956, due to 6.1 btrfs_subvolume_release_metadata() + defined in ctree.h, modified the header file name from root-tree.h to ctree.h] + Signed-off-by: Xiangyu Chen <xiangyu.chen@xxxxxxxxxxxxx> + + ## fs/btrfs/ctree.h ## +@@ fs/btrfs/ctree.h: enum btrfs_flush_state { + int btrfs_subvolume_reserve_metadata(struct btrfs_root *root, + struct btrfs_block_rsv *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); + + int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes, ## fs/btrfs/inode.c ## -@@ fs/btrfs/inode.c: int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry) +@@ fs/btrfs/inode.c: int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry) struct btrfs_trans_handle *trans; struct btrfs_block_rsv block_rsv; u64 root_flags; @@ fs/btrfs/inode.c: int btrfs_delete_subvolume(struct btrfs_inode *dir, struct den int ret; down_write(&fs_info->subvol_sem); -@@ fs/btrfs/inode.c: int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry) +@@ fs/btrfs/inode.c: int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry) ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 5, true); if (ret) goto out_undead; @@ fs/btrfs/inode.c: int btrfs_delete_subvolume(struct btrfs_inode *dir, struct den trans->block_rsv = &block_rsv; trans->bytes_reserved = block_rsv.size; -@@ fs/btrfs/inode.c: int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry) +@@ fs/btrfs/inode.c: int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry) ret = btrfs_end_transaction(trans); inode->i_flags |= S_DEAD; out_release: @@ fs/btrfs/inode.c: int btrfs_delete_subvolume(struct btrfs_inode *dir, struct den spin_lock(&dest->root_item_lock); ## fs/btrfs/ioctl.c ## -@@ fs/btrfs/ioctl.c: static noinline int create_subvol(struct mnt_idmap *idmap, +@@ fs/btrfs/ioctl.c: static noinline int create_subvol(struct user_namespace *mnt_userns, int ret; dev_t anon_dev; u64 objectid; @@ fs/btrfs/ioctl.c: static noinline int create_subvol(struct mnt_idmap *idmap, root_item = kzalloc(sizeof(*root_item), GFP_KERNEL); if (!root_item) -@@ fs/btrfs/ioctl.c: static noinline int create_subvol(struct mnt_idmap *idmap, +@@ fs/btrfs/ioctl.c: static noinline int create_subvol(struct user_namespace *mnt_userns, trans_num_items, false); if (ret) goto out_new_inode_args; @@ fs/btrfs/ioctl.c: static noinline int create_subvol(struct mnt_idmap *idmap, + qgroup_reserved = 0; trans->block_rsv = &block_rsv; trans->bytes_reserved = block_rsv.size; - /* Tree log can't currently deal with an inode which is a new root. */ -@@ fs/btrfs/ioctl.c: static noinline int create_subvol(struct mnt_idmap *idmap, + +@@ fs/btrfs/ioctl.c: static noinline int create_subvol(struct user_namespace *mnt_userns, out: trans->block_rsv = NULL; trans->bytes_reserved = 0; - btrfs_subvolume_release_metadata(root, &block_rsv); -- - btrfs_end_transaction(trans); + + if (ret) + btrfs_end_transaction(trans); + else + ret = btrfs_commit_transaction(trans); +out_release_rsv: + btrfs_block_rsv_release(fs_info, &block_rsv, (u64)-1, NULL); + if (qgroup_reserved) @@ fs/btrfs/root-tree.c: int btrfs_subvolume_reserve_metadata(struct btrfs_root *ro - btrfs_block_rsv_release(fs_info, rsv, (u64)-1, &qgroup_to_release); - btrfs_qgroup_convert_reserved_meta(root, qgroup_to_release); -} - - ## fs/btrfs/root-tree.h ## -@@ fs/btrfs/root-tree.h: struct btrfs_trans_handle; - int btrfs_subvolume_reserve_metadata(struct btrfs_root *root, - struct btrfs_block_rsv *rsv, - int nitems, bool use_global_rsv); --void btrfs_subvolume_release_metadata(struct btrfs_root *root, -- struct btrfs_block_rsv *rsv); - int btrfs_add_root_ref(struct btrfs_trans_handle *trans, u64 root_id, - u64 ref_id, u64 dirid, u64 sequence, - const struct fscrypt_str *name); --- Results of testing on various branches: | Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | stable/linux-6.1.y | Success | Success |