Skip to content

Commit c1b5ac8

Browse files
fdmananakdave
authored andcommitted
btrfs: fix invalid pointer dereference in __btrfs_run_delayed_refs()
In the beginning of the loop, we try to obtain a locked delayed ref head, if 'locked_ref' is currently NULL, by calling btrfs_select_ref_head(), which can return an error pointer. If the error pointer is -EAGAIN we do a continue and go back to the beginning of the loop, which will not try again to call btrfs_select_ref_head() since 'locked_ref' is no longer NULL but it's ERR_PTR(-EAGAIN), and then we do: spin_lock(&locked_ref->lock); against a ERR_PTR(-EAGAIN) value, generating an invalid pointer dereference. Fix this by ensuring that 'locked_ref' is set to NULL when btrfs_select_ref_head() returns ERR_PTR(-EAGAIN) and incrementing 'count' as well, to prevent infinite looping. We do this by doing a goto to the bottom of the loop that already sets 'locked_ref' to NULL and does a cond_resched(), with an increment to 'count' right before the goto. These measures were in place before the refactoring in commit 0110a4c ("btrfs: refactor __btrfs_run_delayed_refs loop") but were unintentionally lost afterwards. Reported-by: Dan Carpenter <error27@gmail.com> Link: https://lore.kernel.org/linux-btrfs/ag8ARRwykv8bpJ87@stanley.mountain/ Fixes: 0110a4c ("btrfs: refactor __btrfs_run_delayed_refs loop") Reviewed-by: Boris Burkov <boris@bur.io> Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 7ce2e7d commit c1b5ac8

1 file changed

Lines changed: 3 additions & 2 deletions

File tree

fs/btrfs/extent-tree.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2108,7 +2108,8 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
21082108
locked_ref = btrfs_select_ref_head(fs_info, delayed_refs);
21092109
if (IS_ERR_OR_NULL(locked_ref)) {
21102110
if (PTR_ERR(locked_ref) == -EAGAIN) {
2111-
continue;
2111+
count++;
2112+
goto again;
21122113
} else {
21132114
break;
21142115
}
@@ -2156,7 +2157,7 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
21562157
* Either success case or btrfs_run_delayed_refs_for_head
21572158
* returned -EAGAIN, meaning we need to select another head
21582159
*/
2159-
2160+
again:
21602161
locked_ref = NULL;
21612162
cond_resched();
21622163
} while ((min_bytes != U64_MAX && bytes_processed < min_bytes) ||

0 commit comments

Comments
 (0)