In the Linux kernel, the following vulnerability has been resolved:
btrfs: do not ASSERT() if the newly created subvolume already got read
[BUG] There is a syzbot crash, triggered by the ASSERT() during subvolume creation:
assertion failed: !anondev, in fs/btrfs/disk-io.c:1319 ------------[ cut here ]------------ kernel BUG at fs/btrfs/disk-io.c:1319! invalid opcode: 0000 [#1] PREEMPT SMP KASAN RIP: 0010:btrfsgetrootref.part.0+0x9aa/0xa60 <TASK> btrfsgetnewfsroot+0xd3/0xf0 createsubvol+0xd02/0x1650 btrfsmksubvol+0xe95/0x12b0 _btrfsioctlsnapcreate+0x2f9/0x4f0 btrfsioctlsnapcreate+0x16b/0x200 btrfsioctl+0x35f0/0x5cf0 _x64sysioctl+0x19d/0x210 dosyscall64+0x3f/0xe0 entrySYSCALL64after_hwframe+0x63/0x6b ---[ end trace 0000000000000000 ]---
[CAUSE] During createsubvol(), after inserting root item for the newly created subvolume, we would trigger btrfsgetnewfsroot() to get the btrfsroot of that subvolume.
The idea here is, we have preallocated an anonymous device number for the subvolume, thus we can assign it to the new subvolume.
But there is really nothing preventing things like backref walk to read the new subvolume. If that happens before we call btrfsgetnewfsroot(), the subvolume would be read out, with a new anonymous device number assigned already.
In that case, we would trigger ASSERT(), as we really expect no one to read out that subvolume (which is not yet accessible from the fs). But things like backref walk is still possible to trigger the read on the subvolume.
Thus our assumption on the ASSERT() is not correct in the first place.
[FIX] Fix it by removing the ASSERT(), and just free the @anon_dev, reset it to 0, and continue.
If the subvolume tree is read out by something else, it should have already get a new anon_dev assigned thus we only need to free the preallocated one.