]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
btrfs: hold block group reference during entire move_existing_remap()
authorMark Harmstone <mark@harmstone.com>
Thu, 19 Feb 2026 17:03:53 +0000 (17:03 +0000)
committerDavid Sterba <dsterba@suse.com>
Tue, 17 Mar 2026 10:43:08 +0000 (11:43 +0100)
There is a potential use-after-free in move_existing_remap(): we're calling
btrfs_put_block_group() on dest_bg, then passing it to
btrfs_add_block_group_free_space() a few lines later.

Fix this by getting the BG at the start of the function and putting it
near the end. This also means we're not doing a lookup twice for the
same thing.

Reported-by: Chris Mason <clm@fb.com>
Link: https://lore.kernel.org/linux-btrfs/20260125123908.2096548-1-clm@meta.com/
Fixes: bbea42dfb91f ("btrfs: move existing remaps before relocating block group")
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Mark Harmstone <mark@harmstone.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/relocation.c

index 2625a66054d06be1cf05b50a3a2b5ff0c57c7113..0f61bdf7f5d116710f466303c7f36c73c7f594c1 100644 (file)
@@ -4185,6 +4185,8 @@ static int move_existing_remap(struct btrfs_fs_info *fs_info,
        dest_addr = ins.objectid;
        dest_length = ins.offset;
 
+       dest_bg = btrfs_lookup_block_group(fs_info, dest_addr);
+
        if (!is_data && !IS_ALIGNED(dest_length, fs_info->nodesize)) {
                u64 new_length = ALIGN_DOWN(dest_length, fs_info->nodesize);
 
@@ -4295,15 +4297,12 @@ static int move_existing_remap(struct btrfs_fs_info *fs_info,
        if (unlikely(ret))
                goto end;
 
-       dest_bg = btrfs_lookup_block_group(fs_info, dest_addr);
-
        adjust_block_group_remap_bytes(trans, dest_bg, dest_length);
 
        mutex_lock(&dest_bg->free_space_lock);
        bg_needs_free_space = test_bit(BLOCK_GROUP_FLAG_NEEDS_FREE_SPACE,
                                       &dest_bg->runtime_flags);
        mutex_unlock(&dest_bg->free_space_lock);
-       btrfs_put_block_group(dest_bg);
 
        if (bg_needs_free_space) {
                ret = btrfs_add_block_group_free_space(trans, dest_bg);
@@ -4333,13 +4332,13 @@ end:
                        btrfs_end_transaction(trans);
                }
        } else {
-               dest_bg = btrfs_lookup_block_group(fs_info, dest_addr);
                btrfs_free_reserved_bytes(dest_bg, dest_length, 0);
-               btrfs_put_block_group(dest_bg);
 
                ret = btrfs_commit_transaction(trans);
        }
 
+       btrfs_put_block_group(dest_bg);
+
        return ret;
 }