linux/fs
ZhengYuan Huang bedaf7d0b9 btrfs: reject root items with drop_progress and zero drop_level
[ Upstream commit b17b79ff89 ]

[BUG]
When recovering relocation at mount time, merge_reloc_root() and
btrfs_drop_snapshot() both use BUG_ON(level == 0) to guard against
an impossible state: a non-zero drop_progress combined with a zero
drop_level in a root_item, which can be triggered:

------------[ cut here ]------------
kernel BUG at fs/btrfs/relocation.c:1545!
Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
CPU: 1 UID: 0 PID: 283 ... Tainted: 6.18.0+ #16 PREEMPT(voluntary)
Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE
Hardware name: QEMU Ubuntu 24.04 PC v2, BIOS 1.16.3-debian-1.16.3-2
RIP: 0010:merge_reloc_root+0x1266/0x1650 fs/btrfs/relocation.c:1545
Code: ffff0000 00004589 d7e9acfa ffffe8a1 79bafebe 02000000
Call Trace:
 merge_reloc_roots+0x295/0x890 fs/btrfs/relocation.c:1861
 btrfs_recover_relocation+0xd6e/0x11d0 fs/btrfs/relocation.c:4195
 btrfs_start_pre_rw_mount+0xa4d/0x1810 fs/btrfs/disk-io.c:3130
 open_ctree+0x5824/0x5fe0 fs/btrfs/disk-io.c:3640
 btrfs_fill_super fs/btrfs/super.c:987 [inline]
 btrfs_get_tree_super fs/btrfs/super.c:1951 [inline]
 btrfs_get_tree_subvol fs/btrfs/super.c:2094 [inline]
 btrfs_get_tree+0x111c/0x2190 fs/btrfs/super.c:2128
 vfs_get_tree+0x9a/0x370 fs/super.c:1758
 fc_mount fs/namespace.c:1199 [inline]
 do_new_mount_fc fs/namespace.c:3642 [inline]
 do_new_mount fs/namespace.c:3718 [inline]
 path_mount+0x5b8/0x1ea0 fs/namespace.c:4028
 do_mount fs/namespace.c:4041 [inline]
 __do_sys_mount fs/namespace.c:4229 [inline]
 __se_sys_mount fs/namespace.c:4206 [inline]
 __x64_sys_mount+0x282/0x320 fs/namespace.c:4206
 ...
RIP: 0033:0x7f969c9a8fde
Code: 0f1f4000 48c7c2b0 fffffff7 d8648902 b8ffffff ffc3660f
---[ end trace 0000000000000000 ]---

The bug is reproducible on 7.0.0-rc2-next-20260310 with our dynamic
metadata fuzzing tool that corrupts btrfs metadata at runtime.

[CAUSE]
A non-zero drop_progress.objectid means an interrupted
btrfs_drop_snapshot() left a resume point on disk, and in that case
drop_level must be greater than 0 because the checkpoint is only
saved at internal node levels.

Although this invariant is enforced when the kernel writes the root
item, it is not validated when the root item is read back from disk.
That allows on-disk corruption to provide an invalid state with
drop_progress.objectid != 0 and drop_level == 0.

When relocation recovery later processes such a root item,
merge_reloc_root() reads drop_level and hits BUG_ON(level == 0). The
same invalid metadata can also trigger the corresponding BUG_ON() in
btrfs_drop_snapshot().

[FIX]
Fix this by validating the root_item invariant in tree-checker when
reading root items from disk: if drop_progress.objectid is non-zero,
drop_level must also be non-zero. Reject such malformed metadata with
-EUCLEAN before it reaches merge_reloc_root() or btrfs_drop_snapshot()
and triggers the BUG_ON.

After the fix, the same corruption is correctly rejected by tree-checker
and the BUG_ON is no longer triggered.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
History 2026-04-18 10:33:29 +02:00
..
9p 9p: sysfs_init: don't hardcode error to ENOMEM 2025-12-07 06:09:25 +09:00
adfs mm: require ->set_page_dirty to be explicitly wired up 2021-06-29 10:53:48 -07:00
affs affs: don't write overlarge OFS data block size fields 2025-04-10 14:32:03 +02:00
afs afs: Fix the server_list to unuse a displaced server rather than putting it 2025-03-13 12:50:56 +01:00
autofs autofs: fix memory leak of waitqueues in autofs_catatonic_mode 2023-09-23 11:09:54 +02:00
befs isystem: ship and use stdarg.h 2021-08-19 09:02:55 +09:00
bfs bfs: Reconstruct file type when loading from disk 2026-01-19 13:09:21 +01:00
btrfs btrfs: reject root items with drop_progress and zero drop_level 2026-04-18 10:33:29 +02:00
cachefiles cachefiles: fix memory leak in cachefiles_add_cache() 2024-03-06 14:38:50 +00:00
ceph ceph: fix i_nlink underrun during async unlink 2026-04-18 10:33:14 +02:00
cifs smb: client: Don't log plaintext credentials in cifs_set_cifscreds 2026-04-18 10:33:19 +02:00
coda coda: Avoid partial allocation of sig_inputArgs 2023-03-10 09:39:50 +01:00
configfs configfs: Do not override creating attribute file failure in populate_attrs() 2025-06-27 11:05:22 +01:00
cramfs cramfs: Verify inode mode when loading from disk 2025-10-19 16:21:54 +02:00
crypto fscrypt: fix keyring memory leak on mount failure 2022-11-10 18:15:37 +01:00
debugfs debugfs: fix automount d_fsdata usage 2024-01-25 14:52:27 -08:00
devpts fsnotify: fix fsnotify hooks in pseudo filesystems 2022-02-01 17:27:01 +01:00
dlm dlm: check for defined force value in dlm_lockspace_release 2025-10-29 14:03:10 +01:00
ecryptfs ecryptfs: Fix buffer size for tag 66 packet 2024-06-16 13:39:16 +02:00
efivarfs efivarfs: Fix slab-out-of-bounds in efivarfs_d_compare 2025-09-04 14:28:46 +02:00
efs [PATCH] reduce boilerplate in fsid handling 2020-09-18 16:45:50 -04:00
erofs erofs: add GFP_NOIO in the bio completion if needed 2026-04-18 10:33:27 +02:00
exfat exfat: fix remount failure in different process environments 2026-01-19 13:09:47 +01:00
exportfs exportfs: use pr_debug for unreachable debug statements 2024-04-10 16:19:21 +02:00
ext2 minmax: add in_range() macro 2025-10-19 16:21:28 +02:00
ext4 ext4: always drain queued discard work in ext4_mb_release() 2026-04-18 10:33:28 +02:00
f2fs f2fs: fix out-of-bounds access in sysfs attribute read/write 2026-02-19 16:21:47 +01:00
fat fat: avoid parent link count underflow in rmdir 2026-03-04 07:19:35 -05:00
freevxfs fs: Fill in max and min timestamps in superblock 2019-08-30 07:27:17 -07:00
fscache fscache: Remove an unused static variable 2021-10-04 22:13:12 +01:00
fuse fuse: fix readahead reclaim deadlock 2026-01-19 13:10:08 +01:00
gfs2 gfs2: fiemap page fault fix 2026-03-04 07:19:57 -05:00
hfs hfs: fix KMSAN uninit-value issue in hfs_find_set_zero_bits() 2025-10-29 14:03:10 +01:00
hfsplus hfsplus: pretend special inodes as regular files 2026-03-04 07:19:56 -05:00
hostfs hostfs: support splice_write 2021-08-26 22:28:02 +02:00
hpfs fs/hpfs: Fix error code for new_inode() failure in mkdir/create/mknod/symlink 2025-12-07 06:09:24 +09:00
hugetlbfs mm/hugetlb: fix folio is still mapped when deleted 2025-10-02 13:39:14 +02:00
iomap iomap: fix submission side handling of completion side errors 2026-03-04 07:19:22 -05:00
isofs isofs: Verify inode mode when loading from disk 2025-08-28 16:23:59 +02:00
jbd2 jbd2: gracefully abort on checkpointing state corruptions 2026-04-18 10:33:27 +02:00
jffs2 jffs2: check jffs2_prealloc_raw_node_refs() result in few other places 2025-06-27 11:05:34 +01:00
jfs jfs: nlink overflow in jfs_rename 2026-03-04 07:20:07 -05:00
kernfs fs/kernfs/dir: obey S_ISGID 2024-02-23 08:54:51 +01:00
ksmbd ksmbd: fix use-after-free of share_conf in compound request 2026-04-18 10:33:22 +02:00
lockd lockd: fix vfs_test_lock() calls 2026-01-19 13:10:10 +01:00
minix minix: Add required sanity checking to minix_check_superblock() 2026-03-04 07:19:57 -05:00
netfs netfs: fix parameter of cleanup() 2021-12-29 12:28:59 +01:00
nfs pNFS: fix a missing wake up while waiting on NFS_LAYOUT_DRAIN 2026-03-04 07:19:44 -05:00
nfs_common NFSD: Remove NFSERR_EAGAIN 2026-01-19 13:10:18 +01:00
nfsd nfsd: fix return error code for nfsd_map_name_to_[ug]id 2026-03-04 07:20:31 -05:00
nilfs2 nilfs2: Fix potential block overflow that cause system hang 2026-02-19 16:21:43 +01:00
nls fs/nls: Fix inconsistency between utf8_to_utf32() and utf32_to_utf8() 2026-01-19 13:09:38 +01:00
notify fsnotify: do not generate ACCESS/MODIFY events on child for special files 2026-01-19 13:09:53 +01:00
ntfs ntfs: check overflow when iterating ATTR_RECORDs 2022-11-26 09:24:52 +01:00
ntfs3 fs/ntfs3: avoid calling run_get_entry() when run == NULL in ntfs_read_run_nb_ra() 2026-03-04 07:20:18 -05:00
ocfs2 ocfs2: fix reflink preserve cleanup issue 2026-03-04 07:20:32 -05:00
omfs mm: require ->set_page_dirty to be explicitly wired up 2021-06-29 10:53:48 -07:00
openpromfs openpromfs: finish conversion to the new mount API 2024-06-16 13:39:16 +02:00
orangefs orangefs: fix xattr related buffer overflow... 2025-12-07 06:09:24 +09:00
overlayfs ovl: Fix uninit-value in ovl_fill_real 2026-03-04 07:19:47 -05:00
proc procfs: fix missing RCU protection when reading real_parent in do_task_stat() 2026-03-04 07:19:37 -05:00
pstore pstore: ram_core: fix incorrect success return when vmap() fails 2026-03-04 07:20:01 -05:00
qnx4 qnx4: work around gcc false positive warning bug 2021-09-21 08:36:48 -07:00
qnx6 [PATCH] reduce boilerplate in fsid handling 2020-09-18 16:45:50 -04:00
quota quota: flush quota_release_work upon quota writeback 2024-12-14 19:51:22 +01:00
ramfs shmem: use ramfs_kill_sb() for kill_sb method of ramfs-based tmpfs 2023-07-23 13:47:33 +02:00
reiserfs reiserfs: Check the return value from __getblk() 2023-09-19 12:22:30 +02:00
romfs romfs: check sb_set_blocksize() return value 2026-02-19 16:21:44 +01:00
smbfs_common cifs: Fix crash on unload of cifs_arc4.ko 2021-12-14 10:57:12 +01:00
squashfs Squashfs: check metadata block offset is within range 2026-04-18 10:33:09 +02:00
sysfs fs: sysfs: Fix reference leak in sysfs_break_active_protection() 2024-04-27 17:05:28 +02:00
sysv sysv: don't call sb_bread() with pointers_lock held 2024-04-13 13:01:44 +02:00
tracefs tracefs: Add missing lockdown check to tracefs_create_dir() 2023-09-23 11:10:02 +02:00
ubifs ubifs: skip dumping tnc tree when zroot is null 2025-03-13 12:50:11 +01:00
udf fs: udf: fix OOB read in lengthAllocDescs handling 2025-10-19 16:21:38 +02:00
ufs minmax: add in_range() macro 2025-10-19 16:21:28 +02:00
unicode Revert "unicode: Don't special case ignorable code points" 2024-12-14 19:51:44 +01:00
vboxsf vboxsf: fix building with GCC 15 2025-04-10 14:31:50 +02:00
verity fsverity: skip PKCS#7 parser when keyring is empty 2023-09-19 12:22:52 +02:00
xfs xfs: stop reclaim before pushing AIL during unmount 2026-04-18 10:33:27 +02:00
zonefs zonefs: Improve error handling 2024-03-01 13:21:43 +01:00
aio.c fs/aio: Check IOCB_AIO_RW before the struct aio_kiocb conversion 2024-04-10 16:18:46 +02:00
anon_inodes.c fs: anon_inodes: rephrase to appropriate kernel-doc 2021-01-15 12:17:25 -05:00
attr.c attr: block mode changes of symlinks 2023-09-23 11:10:01 +02:00
bad_inode.c vfs: add rcu argument to ->get_acl() callback 2021-08-18 22:08:24 +02:00
binfmt_aout.c binfmt: a.out: Fix bogus semicolon 2021-09-05 10:15:05 -07:00
binfmt_elf.c fs/binfmt_elf: Fix memory leak in load_elf_binary() 2022-11-03 23:59:12 +09:00
binfmt_elf_fdpic.c fs: binfmt_elf_efpic: don't use missing interpreter's properties 2024-09-04 13:23:24 +02:00
binfmt_flat.c binfmt_flat: Fix integer overflow bug on 32 bit systems 2025-03-13 12:50:24 +01:00
binfmt_misc.c binfmt_misc: cleanup on filesystem umount 2024-09-04 13:23:22 +02:00
binfmt_script.c Merge branch 'akpm' (patches from Andrew) 2020-06-04 19:18:29 -07:00
buffer.c fs/buffer: fix use-after-free when call bh_read() helper 2025-08-28 16:24:34 +02:00
char_dev.c chardev: fix error handling in cdev_device_add() 2022-12-31 13:14:30 +01:00
compat_binfmt_elf.c get rid of COMPAT_ELF_EXEC_PAGESIZE 2021-01-06 08:42:51 -05:00
coredump.c coredump: hand a pidfd to the usermode coredump helper 2025-06-04 14:38:07 +02:00
d_path.c d_path: make 'prepend()' fill up the buffer exactly on overflow 2021-09-02 10:07:29 -07:00
dax.c dax: skip read lock assertion for read-only filesystems 2025-10-29 14:03:07 +01:00
dcache.c vfs: Don't leak disconnected dentries on umount 2025-10-29 14:03:14 +01:00
direct-io.c fs: direct-io: fix missing sdio->boundary 2021-04-09 14:54:23 -07:00
drop_caches.c fs: drop_caches: fix skipping over shadow cache inodes 2021-09-03 09:58:10 -07:00
eventfd.c eventfd: prevent underflow for eventfd semaphores 2023-09-19 12:22:30 +02:00
eventpoll.c eventpoll: Fix integer overflow in ep_loop_check_proc() 2026-04-18 10:33:08 +02:00
exec.c exec: Fix incorrect type for ret 2025-10-29 14:03:09 +01:00
fcntl.c fs: Fix file_set_fowner LSM hook inconsistencies 2024-10-17 15:11:15 +02:00
fhandle.c do_sys_name_to_handle(): use kzalloc() to fix kernel-infoleak 2024-03-26 18:21:14 -04:00
file.c fs: always return zero on success from replace_fd() 2025-10-19 16:21:39 +02:00
file_table.c fs: fix proc_handler for sysctl_nr_open 2025-03-13 12:49:50 +01:00
filesystems.c fs/filesystems: Fix potential unsigned integer underflow in fs_name() 2025-06-27 11:05:20 +01:00
fs-writeback.c writeback: fix 100% CPU usage when dirtytime_expire_interval is 0 2026-02-06 16:42:05 +01:00
fs_context.c fs: avoid empty option when generating legacy mount string 2023-07-23 13:47:34 +02:00
fs_parser.c namei: Standardize callers of filename_lookup() 2021-09-07 16:07:47 -04:00
fs_pin.c switch the remnants of releasing the mountpoint away from fs_pin 2019-07-16 22:52:37 -04:00
fs_struct.c fs: add <linux/init_task.h> for 'init_fs' 2026-03-04 07:19:21 -05:00
fs_types.c fs: common implementation of file type 2019-01-21 17:48:13 +01:00
fsopen.c fscontext: do not consume log entries when returning -EMSGSIZE 2025-10-19 16:21:51 +02:00
init.c init: handle idmapped mounts 2021-01-24 14:27:19 +01:00
inode.c fs: move inode sysctls to its own file 2025-03-13 12:49:50 +01:00
internal.h nfs: use vfs setgid helper 2023-08-30 16:18:19 +02:00
ioctl.c lsm: new security_file_ioctl_compat() hook 2024-02-23 08:54:25 +01:00
Kconfig nfs: add missing selections of CONFIG_CRC32 2025-05-02 07:44:12 +02:00
Kconfig.binfmt binfmt: remove support for em86 (alpha only) 2021-07-25 22:33:03 -07:00
kernel_read_file.c vfs: check fd has read access in kernel_read_file_from_fd() 2021-10-18 20:22:03 -10:00
libfs.c better lockdep annotations for simple_recursive_removal() 2025-08-28 16:24:16 +02:00
locks.c lockd: fix vfs_test_lock() calls 2026-01-19 13:10:10 +01:00
Makefile io_uring: move to separate directory 2022-12-14 11:37:31 +01:00
mbcache.c mbcache: Avoid nesting of cache->c_list_lock under bit locks 2023-01-12 11:59:20 +01:00
mount.h mount: make {lock,unlock}_mount_hash() static 2021-01-24 14:29:34 +01:00
mpage.c block: rename BIO_MAX_PAGES to BIO_MAX_VECS 2021-03-11 07:47:48 -07:00
namei.c openat2: don't trigger automounts with RESOLVE_NO_XDEV 2025-10-19 16:21:46 +02:00
namespace.c fs: Add 'initramfs_options' to set initramfs mount options 2025-10-19 16:21:54 +02:00
no-block.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 152 2019-05-30 11:26:32 -07:00
nsfs.c nsproxy: attach to namespaces via pidfds 2020-05-13 11:41:22 +02:00
open.c allow finish_no_open(file, ERR_PTR(-E...)) 2025-12-07 06:09:22 +09:00
pipe.c fs/pipe: Fix lockdep false-positive in watchqueue pipe_write() 2024-04-10 16:19:42 +02:00
pnode.c pnode: terminate at peers of source 2023-01-12 11:58:47 +01:00
pnode.h mount: fix mounting of detached mounts onto targets that reside on shared mounts 2021-03-08 15:18:43 +01:00
posix_acl.c fs: fix acl translation 2022-07-02 16:41:17 +02:00
proc_namespace.c fs: add is_idmapped_mnt() helper 2022-07-02 16:41:14 +02:00
read_write.c vfs: fix copy_file_range() averts filesystem freeze protection 2022-12-19 12:36:39 +01:00
readdir.c readdir: make sure to verify directory entry for legacy interfaces too 2021-04-17 11:39:49 -07:00
remap_range.c fs/remap: constrain dedupe of EOF blocks 2022-07-21 21:24:14 +02:00
select.c select: Fix unbalanced user_access_end() 2025-03-13 12:49:51 +01:00
seq_file.c rxrpc: Fix locking issue 2022-07-12 16:35:08 +02:00
signalfd.c signalfd: use wake_up_pollfree() 2021-12-14 10:57:15 +01:00
splice.c splice, net: Add a splice_eof op to file-ops and socket-ops 2025-10-29 14:03:08 +01:00
stack.c sched/rt, fs: Use CONFIG_PREEMPTION 2019-12-08 14:37:36 +01:00
stat.c stat: fix inconsistency between struct stat and struct compat_stat 2022-04-27 14:38:57 +02:00
statfs.c statfs: enforce statfs[64] structure initialization 2023-05-24 17:36:54 +01:00
super.c fs: explicitly unregister per-superblock BDIs 2024-10-17 15:10:43 +02:00
sync.c vfs: make sync_filesystem return errors from ->sync_fs 2022-04-27 14:38:50 +02:00
timerfd.c timerfd: Provide timerfd_resume() 2021-08-10 17:57:22 +02:00
userfaultfd.c Fix userfaultfd_api to return EINVAL as expected 2024-07-18 13:07:42 +02:00
utimes.c utimes: handle idmapped mounts 2021-01-24 14:27:18 +01:00
xattr.c fs: don't audit the capability check in simple_xattr_list() 2022-12-31 13:14:01 +01:00