CVE-2026-93800: btrfs: fix use-after-free on reloc root after error in insert_dirty_subvol()
In the Linux kernel, the following vulnerability has been resolved:
btrfs: fix use-after-free on reloc root after error in insertdirtysubvol()
If during relocation we fail in insertdirtysubvol() because btrfsupdaterelocroot() returned an error, we will leave a root's relocroot field pointing to a reloc root that was freed instead of NULL, resulting later in a use-after-free, or double free attempt during unmount.
The sequence of steps is this:
1) During relocation the call to btrfsupdaterelocroot() in insertdirtysubvol() fails, so insertdirtysubvol() returns the error to mergerelocroot() without adding the root to the list rc->dirtysubvolroots;
2) Then mergerelocroot() aborts the current transaction because insertdirtysubvol() returned an error;
3) Up the call chain, mergerelocroots() gets the error, adds the reloc root for root X to the local relocroots list and jumps to the 'out' label, where it calls freerelocroots() to free all the reloc roots in the local relocroots list. This frees the reloc root for root X;
4) We go up the call chain to relocateblockgroup() which calls cleandirtysubvols() to go over dirty roots and set their ->relocroot field to NULL, but root X is not in the dirtysubvolroots list, so its ->relocroot still points to a reloc root;
5) Relocation finishes, with an error and a transaction abort, but the ->relocroot field for root X still points to the reloc root that was freed in step 3;
6) When unmounting the fs we end up calling:
btrfsfreefsroots() btrfsdropandfreefsroot() --> calls btrfsputroot() against root X's ->relocroot which is not NULL and points to the already freed reloc root in step 4 above
Resulting in a use-after-free to a double free attempt.
Syzbot reported this with the following dmesg/syslog:
[ 106.004389][ T5339] BTRFS error (device loop0 state A): Transaction aborted (error -5) [ 106.014266][ T5339] BTRFS: error (device loop0 state A) in mergerelocroot:1655: errno=-5 IO failure [ 106.021891][ T1061] BTRFS error (device loop0 state A): error while writing out transaction: -5 [ 106.026964][ T1061] BTRFS warning (device loop0 state A): Skipping commit of aborted transaction. [ 106.033807][ T5340] BTRFS error (device loop0 state A): bdev /dev/loop0 errs: wr 3, rd 0, flush 0, corrupt 0, gen 0 [ 106.039265][ T1061] BTRFS: error (device loop0 state A) in cleanuptransaction:2067: errno=-5 IO failure [ 106.044382][ T5339] BTRFS info (device loop0 state EA): forced readonly [ 106.074329][ T5339] BTRFS: error (device loop0 state EA) in mergerelocroots:1887: errno=-5 IO failure [ 106.081004][ T5356] BTRFS info (device loop0 state EA): scrub: started on devid 1 [ 106.085611][ T5339] BTRFS info (device loop0 state EA): balance: ended with status: -30 [ 106.089517][ T5356] BTRFS info (device loop0 state EA): scrub: not finished on devid 1 with status: -30 [ 106.662365][ T5338] BTRFS info (device loop0 state EA): last unmount of filesystem 3a375e4e-b156-4d76-a2ad-16e198ce1409 [ 106.682946][ T5338] ================================================================== [ 106.686574][ T5338] BUG: KASAN: slab-use-after-free in btrfsputroot+0x2f/0x250 [ 106.690090][ T5338] Write of size 4 at addr ffff88803f978630 by task syz.0.0/5338 [ 106.693173][ T5338] [ 106.694279][ T5338] CPU: 0 UID: 0 PID: 5338 Comm: syz.0.0 Not tainted syzkaller #0 PREEMPT(full) [ 106.694293][ T5338] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 106.694300][ T5338] Call Trace: [ 106.694308][ T5338] <TASK> [ 106.694314][ T5338] dumpstacklvl+0xe8/0x150 [ 106.694331][ T5338] printaddressdescription+0x55/0x1e0 [ 106.694343][ T5338] ? btrfsputroot+0x2f/0x250 [ 106.694358][ T5338] printreport+0x58/0x70 [ 106. ---truncated---
Affected Software
Event History
Frequently Asked Questions
What conditions are required to reach the vulnerable state?
The issue occurs during Btrfs relocation when insert_dirty_subvol() fails because btrfs_update_reloc_root() returns an error. That failure can leave a root's reloc_root field referring to a relocation root that has already been freed.
What can happen after the relocation error?
Later handling can dereference the stale reloc_root pointer, causing a use-after-free. Unmount handling can also attempt to free the same relocation root again, causing a double-free attempt.
Can I determine whether my kernel is affected from the supplied version information?
No affected or fixed kernel version ranges are provided. The available references identify three stable-kernel commits associated with the resolved issue.