CVE: CVE-2022-49702
Published: 2025-02-26
Description: In the Linux kernel, the following vulnerability has been resolved:

btrfs: fix hang during unmount when block group reclaim task is running

When we start an unmount, at close_ctree(), if we have the reclaim task
running and in the middle of a data block group relocation, we can trigger
a deadlock when stopping an async reclaim task, producing a trace like the
following:

[[PII_REDACTED]85] task:kworker/u16:7   state:D stack:    0 pid:681170 ppid:     2 flags:0x00004000
[[PII_REDACTED]60] Workqueue: events_unbound btrfs_async_reclaim_metadata_space [btrfs]
[[PII_REDACTED]67] Call Trace:
[[PII_REDACTED]59]  <TASK>
[[PII_REDACTED]74]  __schedule+0x3cb/0xed0
[[PII_REDACTED]42]  schedule+0x4e/0xb0
[[PII_REDACTED]47]  btrfs_wait_on_delayed_iputs+0x7c/0xc0 [btrfs]
[[PII_REDACTED]34]  ? prepare_to_wait_exclusive+0xc0/0xc0
[[PII_REDACTED]42]  flush_space+0x423/0x630 [btrfs]
[[PII_REDACTED]96]  ? rcu_read_unlock_trace_special+0x20/0x50
[[PII_REDACTED]59]  ? lock_release+0x220/0x4a0
[[PII_REDACTED]32]  ? btrfs_get_alloc_profile+0xb3/0x290 [btrfs]
[[PII_REDACTED]40]  ? do_raw_spin_unlock+0x4b/0xa0
[[PII_REDACTED]88]  btrfs_async_reclaim_metadata_space+0x139/0x320 [btrfs]
[[PII_REDACTED]22]  process_one_work+0x252/0x5a0
[[PII_REDACTED]94]  ? process_one_work+0x5a0/0x5a0
[[PII_REDACTED]08]  worker_thread+0x52/0x3b0
[[PII_REDACTED]20]  ? process_one_work+0x5a0/0x5a0
[[PII_REDACTED]21]  kthread+0xf2/0x120
[[PII_REDACTED]27]  ? kthread_complete_and_exit+0x20/0x20
[[PII_REDACTED]26]  ret_from_fork+0x22/0x30
[[PII_REDACTED]36]  </TASK>
[[PII_REDACTED]94] task:umount          state:D stack:    0 pid:719055 ppid:695412 flags:0x00004000
[[PII_REDACTED]69] Call Trace:
[[PII_REDACTED]46]  <TASK>
[[PII_REDACTED]60]  __schedule+0x3cb/0xed0
[[PII_REDACTED]35]  schedule+0x4e/0xb0
[[PII_REDACTED]67]  schedule_timeout+0xed/0x130
[[PII_REDACTED]21]  ? lock_release+0x220/0x4a0
[[PII_REDACTED]46]  ? lock_acquired+0x19c/0x420
[[PII_REDACTED]62]  ? trace_hardirqs_on+0x1b/0xe0
[[PII_REDACTED]11]  __wait_for_common+0xaf/0x1f0
[[PII_REDACTED]89]  ? usleep_range_state+0xb0/0xb0
[[PII_REDACTED]97]  __flush_work+0x26d/0x530
[[PII_REDACTED]98]  ? flush_workqueue_prep_pwqs+0x140/0x140
[[PII_REDACTED]80]  ? lock_acquire+0x1a0/0x310
[[PII_REDACTED]24]  __cancel_work_timer+0x137/0x1c0
[[PII_REDACTED]90]  close_ctree+0xfd/0x531 [btrfs]
[[PII_REDACTED]00]  ? evict_inodes+0x166/0x1c0
[[PII_REDACTED]10]  generic_shutdown_super+0x74/0x120
[[PII_REDACTED]03]  kill_anon_super+0x14/0x30
[[PII_REDACTED]11]  btrfs_kill_super+0x12/0x20 [btrfs]
[[PII_REDACTED]46]  deactivate_locked_super+0x31/0xa0
[[PII_REDACTED]17]  cleanup_mnt+0x147/0x1c0
[[PII_REDACTED]19]  task_work_run+0x5c/0xa0
[[PII_REDACTED]84]  exit_to_user_mode_prepare+0x1a6/0x1b0
[[PII_REDACTED]98]  syscall_exit_to_user_mode+0x16/0x40
[[PII_REDACTED]00]  do_syscall_64+0x48/0x90
[[PII_REDACTED]67]  entry_SYSCALL_64_after_hwframe+0x44/0xae
[[PII_REDACTED]18] RIP: 0033:0x7fa2b90437a7
[[PII_REDACTED]04] RSP: 002b:00007ffe0b7e4458 EFLAGS: 00000246 ORIG_RAX:[PII_REDACTED]0000a6
[[PII_REDACTED]12] RAX: [PII_REDACTED] RBX: 00007fa2b9182264 RCX: 00007fa2b90437a7
[[PII_REDACTED]56] RDX: [PII_REDACTED] RSI: [PII_REDACTED] RDI: 0000555d6cf20dd0
[[PII_REDACTED]53] RBP: 0000555d6cf20ba0 R08: [PII_REDACTED] R09: 00007ffe0b7e3200
[[PII_REDACTED]56] R10: [PII_REDACTED] R11: [PII_REDACTED] R12: [PII_REDACTED]
[[PII_REDACTED]83] R13: 0000555d6cf20dd0 R14: 0000555d6cf20cb0 R15: [PII_REDACTED]
[[PII_REDACTED]96]  </TASK>

This happens because:

1) Before entering close_ctree() we have the async block group reclaim
   task running and relocating a data block group;

2) There's an async metadata (or data) space reclaim task running;

3) We enter close_ctree() and park the cleaner kthread;

4) The async space reclaim task is at flush_space() and runs all the
   existing delayed iputs;

5) Before the async space reclaim task calls
   btrfs_wait_on_delayed_iputs(), the block group reclaim task which is
   doing the data block group relocation, creates a delayed iput at
   replace_file_extents() (called when COWing leaves that have file extent
   items pointing to relocated data exten
---truncated---
CVSS Score: 5.5 (MEDIUM)
CWE: CWE-667
References: https://git.kernel.org/stable/c/31e70e527806c546a72262f2fc3d982ee23c42d3; https://git.kernel.org/stable/c/341d33128a940c6634175dcb6ca92dc454cfa7d2; https://git.kernel.org/stable/c/9fadb11f1295289e0da4d3342ecb6b92c1c99540