Re: [PATCH] btrfs: fix use-after-free in mark_block_group_to_copy

Qu Wenruo <[email protected]>
Newsgroups org.kernel.vger.linux-btrfs,org.kernel.vger.stable
Message-ID <[email protected]>

在 2026/8/17 11:15, Hongling Zeng 写道:
> mark_block_group_to_copy() iterates over the commit root with
> skip_locking=true to avoid lock contention. Without holding
> commit_root_sem,a concurrent transaction commit can swap and free
> the commit root during iteration, leading to use-after-free when
> accessing extent buffers.
> 
> The fix adds commit_root_sem locking, but CRITICALLY must only cover the
> actual search period (btrfs_for_each_slot), NOT the preceding while loop
> which calls btrfs_commit_transaction(). If held during that loop, we get
> self-deadlock: down_read(commit_root_sem) → btrfs_commit_transaction()
> → switch_commit_roots() → down_write(commit_root_sem), blocking forever
> on our own read lock.
> 
> Lock scope:
> - down_read() after path setup, before btrfs_for_each_slot
> - up_read() immediately after btrfs_for_each_slot completes
> - NOT held during while loop (btrfs_commit_transaction) path
> - NOT held on the !path error path (goto unlock before lock
>    acquisition)
> 
> This matches the established btrfs pattern used in send.c, backref.c, etc.:
> hold commit_root_sem read lock ONLY while searching commit root, never
> across transaction commits.
> 
> Fixes: 78ce9fc269af ("btrfs: zoned: mark block groups to copy for device-replace")
> Cc: [email protected]
> Signed-off-by: Hongling Zeng <[email protected]>

Please disclose LLM usage.

> ---
>   fs/btrfs/dev-replace.c | 3 +++
>   1 file changed, 3 insertions(+)
> 
> diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
> index dc0834f920c3..734807bf48b3 100644
> --- a/fs/btrfs/dev-replace.c
> +++ b/fs/btrfs/dev-replace.c
> @@ -499,6 +499,7 @@ static int mark_block_group_to_copy(struct btrfs_fs_info *fs_info,
>   	key.type = BTRFS_DEV_EXTENT_KEY;
>   	key.offset = 0;
>   
> +	down_read(&fs_info->commit_root_sem);
>   	btrfs_for_each_slot(root, &key, &found_key, path, iter_ret) {
>   		struct extent_buffer *leaf = path->nodes[0];
>   
> @@ -525,6 +526,8 @@ static int mark_block_group_to_copy(struct btrfs_fs_info *fs_info,
>   	if (iter_ret < 0)
>   		ret = iter_ret;
>   
> +	up_read(&fs_info->commit_root_sem);
> +
>   	btrfs_free_path(path);
>   unlock:
>   	mutex_unlock(&fs_info->chunk_mutex);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.