forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit 1d2c8bb
btrfs: fix a use-after-free race if btrfs_open_devices() failed
[BUG]
With the latest v5 version patchset "btrfs: use fs_holder_ops for btrfs"
merged into linux-next, syzbot reported an use-after-free:
==================================================================
BUG: KASAN: slab-use-after-free in close_fs_devices+0x81f/0x870 fs/btrfs/volumes.c:1182
Read of size 4 at addr ffff88802fe14930 by task syz.4.616/8589
CPU: 0 UID: 0 PID: 8589 Comm: syz.4.616 Not tainted 6.16.0-rc3-next-20250626-syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/07/2025
Call Trace:
<TASK>
dump_stack_lvl+0x189/0x250 lib/dump_stack.c:120
print_address_description mm/kasan/report.c:408 [inline]
print_report+0xd2/0x2b0 mm/kasan/report.c:521
kasan_report+0x118/0x150 mm/kasan/report.c:634
close_fs_devices+0x81f/0x870 fs/btrfs/volumes.c:1182
btrfs_close_devices+0xc5/0x560 fs/btrfs/volumes.c:1201
btrfs_free_fs_info+0x4f/0x3c0 fs/btrfs/disk-io.c:1250
deactivate_locked_super+0xbc/0x130 fs/super.c:474
btrfs_get_tree_super fs/btrfs/super.c:-1 [inline]
btrfs_get_tree_subvol fs/btrfs/super.c:2073 [inline]
btrfs_get_tree+0xd1e/0x17f0 fs/btrfs/super.c:2107
vfs_get_tree+0x92/0x2b0 fs/super.c:1804
do_new_mount+0x24a/0xa40 fs/namespace.c:3902
do_mount fs/namespace.c:4239 [inline]
__do_sys_mount fs/namespace.c:4450 [inline]
__se_sys_mount+0x317/0x410 fs/namespace.c:4427
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xfa/0x3b0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fedccd900ca
Code: d8 64 89 02 48 c7 c0 ff ff ff ff eb a6 e8 de 1a 00 00 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 49 89 ca b8 a5 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007fedcdc28e68 EFLAGS: 00000246 ORIG_RAX: 00000000000000a5
RAX: ffffffffffffffda RBX: 00007fedcdc28ef0 RCX: 00007fedccd900ca
RDX: 00002000000055c0 RSI: 0000200000005600 RDI: 00007fedcdc28eb0
RBP: 00002000000055c0 R08: 00007fedcdc28ef0 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000200000005600
R13: 00007fedcdc28eb0 R14: 000000000000559d R15: 0000200000000440
</TASK>
Allocated by task 8589:
kasan_save_stack mm/kasan/common.c:47 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:68
poison_kmalloc_redzone mm/kasan/common.c:377 [inline]
__kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:394
kasan_kmalloc include/linux/kasan.h:260 [inline]
__kmalloc_cache_noprof+0x230/0x3d0 mm/slub.c:4396
kmalloc_noprof include/linux/slab.h:905 [inline]
kzalloc_noprof include/linux/slab.h:1039 [inline]
alloc_fs_devices+0x4f/0x1d0 fs/btrfs/volumes.c:384
device_list_add+0x6b7/0x20b0 fs/btrfs/volumes.c:813
btrfs_scan_one_device+0x3fd/0x5b0 fs/btrfs/volumes.c:1487
btrfs_get_tree_super fs/btrfs/super.c:1856 [inline]
btrfs_get_tree_subvol fs/btrfs/super.c:2073 [inline]
btrfs_get_tree+0x433/0x17f0 fs/btrfs/super.c:2107
vfs_get_tree+0x92/0x2b0 fs/super.c:1804
do_new_mount+0x24a/0xa40 fs/namespace.c:3902
do_mount fs/namespace.c:4239 [inline]
__do_sys_mount fs/namespace.c:4450 [inline]
__se_sys_mount+0x317/0x410 fs/namespace.c:4427
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xfa/0x3b0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Freed by task 7454:
kasan_save_stack mm/kasan/common.c:47 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:68
kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:576
poison_slab_object mm/kasan/common.c:247 [inline]
__kasan_slab_free+0x62/0x70 mm/kasan/common.c:264
kasan_slab_free include/linux/kasan.h:233 [inline]
slab_free_hook mm/slub.c:2417 [inline]
slab_free mm/slub.c:4680 [inline]
kfree+0x18e/0x440 mm/slub.c:4879
btrfs_free_stale_devices+0x61c/0x6b0 fs/btrfs/volumes.c:564
btrfs_scan_one_device+0x3d5/0x5b0 fs/btrfs/volumes.c:1481
btrfs_control_ioctl+0x11f/0x360 fs/btrfs/super.c:2256
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:907 [inline]
__se_sys_ioctl+0xf9/0x170 fs/ioctl.c:893
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xfa/0x3b0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
[CAUSE]
The patch "btrfs: delay btrfs_open_devices() until super block is created"
changed the timing when btrfs_open_devices() is called.
Now it's called after sget_fc(), the changed timing is required for
using super blocks as bdev holder.
The problem is the changed error handling.
Before the change if btrfs_open_devices() failed we error out directly,
but now we need to call deactivate_locked_super().
However since btrfs_open_devices() failed, fs_devices->opened is still
0, meaning any reclaim request can free the fs_devices.
But at the same time, deactivate_locked_super() will also cleanup the
fs_info with btrfs_free_fs_info(), which calls btrfs_close_devices().
This leads to the following race:
Mount process | Scan process
----------------------------------+--------------------------------
btrfs_get_tree_super() |
|- mutex_lock(&uuid_mutex) |
|- btrfs_open_devices() |
| Which failed. |
| fs_devices->opened is still 0. |
|- mutex_unlock(&uuid_mutex) |
| | btrfs_control_ioctl()
| | |- btrfs_scan_one_device()
| | |- btrfs_free_stale_devices()
| | That fs_devices is freed
|- deactivate_locked_super() |
|- btrfs_free_fs_info() |
|- btrfs_close_devices()
Now try to free the same
fs_devices that is freed
by the scan process.
[FIX]
If btrfs_open_devices() failed, we should not keep a pointer to it, as
it can be freed at any time after uuid_mutex unlocked.
So add an extra handling for btrfs_open_devices() to reset
fs_info->fs_devices to NULL.
This will be folded into the patch "btrfs: delay btrfs_open_devices()
until super block is created".
Reported-by: [email protected]
Signed-off-by: Qu Wenruo <[email protected]>
Signed-off-by: David Sterba <[email protected]>1 parent c4f6252 commit 1d2c8bbCopy full SHA for 1d2c8bb
File tree
Expand file treeCollapse file tree
1 file changed
+11
-0
lines changedFilter options
- fs/btrfs
Expand file treeCollapse file tree
1 file changed
+11
-0
lines changed+11Lines changed: 11 additions & 0 deletions
Original file line number | Diff line number | Diff line change | |
---|---|---|---|
| |||
1921 | 1921 |
| |
1922 | 1922 |
| |
1923 | 1923 |
| |
| 1924 | + | |
| 1925 | + | |
| 1926 | + | |
| 1927 | + | |
| 1928 | + | |
| 1929 | + | |
| 1930 | + | |
| 1931 | + | |
| 1932 | + | |
| 1933 | + | |
| 1934 | + | |
1924 | 1935 |
| |
1925 | 1936 |
| |
1926 | 1937 |
| |
|
0 commit comments