In the Linux kernel, the following vulnerability has been resolved:
btrfs: unset reloc control if transaction commit fails in preparetorelocate()
In btrfsrelocateblockgroup(), the rc is allocated. Then btrfsrelocateblockgroup() calls
relocateblockgroup() preparetorelocate() setreloccontrol()
that assigns rc to the variable fsinfo->relocctl. When preparetorelocate() returns, it calls
btrfscommittransaction() btrfsstartdirtyblockgroups() btrfsallocpath() kmemcachezalloc()
which may fail for example (or other errors could happen). When the failure occurs, btrfsrelocateblockgroup() detects the error and frees rc and doesn't set fsinfo->relocctl to NULL. After that, in btrfsinitrelocroot(), rc is retrieved from fsinfo->relocctl and then used, which may cause a use-after-free bug.
This possible bug can be triggered by calling btrfsioctlbalance() before calling btrfsioctldefrag().
To fix this possible bug, in preparetorelocate(), check if btrfscommittransaction() fails. If the failure occurs, unsetreloccontrol() is called to set fsinfo->relocctl to NULL.
The error log in our fault-injection testing is shown as follows:
[ 58.751070] BUG: KASAN: use-after-free in btrfsinitrelocroot+0x7ca/0x920 [btrfs] ... [ 58.753577] Call Trace: ... [ 58.755800] kasanreport+0x45/0x60 [ 58.756066] btrfsinitrelocroot+0x7ca/0x920 [btrfs] [ 58.757304] recordrootintrans+0x792/0xa10 [btrfs] [ 58.757748] btrfsrecordrootintrans+0x463/0x4f0 [btrfs] [ 58.758231] starttransaction+0x896/0x2950 [btrfs] [ 58.758661] btrfsdefragroot+0x250/0xc00 [btrfs] [ 58.759083] btrfsioctldefrag+0x467/0xa00 [btrfs] [ 58.759513] btrfsioctl+0x3c95/0x114e0 [btrfs] ... [ 58.768510] Allocated by task 23683: [ 58.768777] _kasankmalloc+0xb5/0xf0 [ 58.769069] _kmalloc+0x227/0x3d0 [ 58.769325] allocreloccontrol+0x10a/0x3d0 [btrfs] [ 58.769755] btrfsrelocateblockgroup+0x7aa/0x1e20 [btrfs] [ 58.770228] btrfsrelocatechunk+0xf1/0x760 [btrfs] [ 58.770655] _btrfsbalance+0x1326/0x1f10 [btrfs] [ 58.771071] btrfsbalance+0x3150/0x3d30 [btrfs] [ 58.771472] btrfsioctlbalance+0xd84/0x1410 [btrfs] [ 58.771902] btrfsioctl+0x4caa/0x114e0 [btrfs] ... [ 58.773337] Freed by task 23683: ... [ 58.774815] kfree+0xda/0x2b0 [ 58.775038] freereloccontrol+0x1d6/0x220 [btrfs] [ 58.775465] btrfsrelocateblockgroup+0x115c/0x1e20 [btrfs] [ 58.775944] btrfsrelocatechunk+0xf1/0x760 [btrfs] [ 58.776369] _btrfsbalance+0x1326/0x1f10 [btrfs] [ 58.776784] btrfsbalance+0x3150/0x3d30 [btrfs] [ 58.777185] btrfsioctlbalance+0xd84/0x1410 [btrfs] [ 58.777621] btrfs_ioctl+0x4caa/0x114e0 [btrfs] ...