[PATCH v2] btrfs: fix use-after-free on quota enable allocation failure
From: pavankumaryalagada
Date: Wed Oct 07 2026 - 11:56:58 EST
From: Yalagada Pavan Kumar <pavankumaryalagada@xxxxxxxxx>
The quota root remains on the transaction's dirty root list when
btrfs_quota_enable() fails to allocate a qgroup structure and releases the
quota root. Later add_root_to_dirty_list() accesses the freed dirty_list,
causing a slab-use-after-free.
Abort the transaction on allocation failure to clean up the dirty root
before releasing the quota root. Also remove the quota root from the dirty
root list under trans_lock before releasing it.
Reported-by: syzbot+947286c775f432b073a8@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://syzkaller.appspot.com/bug?extid=947286c775f432b073a8
Fixes: 8d54518b5e52 ("btrfs: qgroup: pre-allocate btrfs_qgroup to reduce GFP_ATOMIC usage")
Signed-off-by: Yalagada Pavan Kumar <pavankumaryalagada@xxxxxxxxx>
---
v2:
- Keep the transaction abort from v1.
- Remove the quota root from the dirty root list under trans_lock before
releasing it, as suggested by Qu.
---
fs/btrfs/qgroup.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index cf8dfd5c692b..d5eaed5eec03 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -1207,6 +1207,7 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
prealloc = kzalloc_obj(*prealloc, GFP_NOFS);
if (!prealloc) {
ret = -ENOMEM;
+ btrfs_abort_transaction(trans, ret);
goto out;
}
qgroup = add_qgroup_rb(fs_info, prealloc, BTRFS_FS_TREE_OBJECTID);
@@ -1296,6 +1297,14 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
* sysfs entries.
*/
btrfs_free_qgroup_config(fs_info);
+
+ if (quota_root) {
+ spin_lock(&fs_info->trans_lock);
+ if (!list_empty("a_root->dirty_list))
+ list_del_init("a_root->dirty_list);
+ spin_unlock(&fs_info->trans_lock);
+ }
+
btrfs_put_root(quota_root);
}
mutex_unlock(&fs_info->qgroup_ioctl_lock);
--
2.43.0