On 2023/11/10 22:18, Lizhi Xu wrote:
r0 = open(&(0x7f0000000080)='./file0\x00', 0x0, 0x0) ioctl$BTRFS_IOC_QUOTA_CTL(r0, 0xc0109428, &(0x7f0000000000)={0x1}) r1 = openat$cgroup_ro(0xffffffffffffff9c, &(0x7f0000000100)='blkio.bfq.time_recursive\x00', 0x275a, 0x0) ioctl$BTRFS_IOC_QGROUP_CREATE(r1, 0x4010942a, &(0x7f0000000640)={0x1, 0x100}) r2 = openat(0xffffffffffffff9c, &(0x7f0000000500)='.\x00', 0x0, 0x0) ioctl$BTRFS_IOC_SNAP_CREATE(r0, 0x50009401, &(0x7f0000000a80)={{r2}, From the logs, it can be seen that syz can execute to btrfs_ioctl_qgroup_create() through two paths. Syz enters btrfs_ioctl_qgroup_create() by calling ioctl$BTRFS_IOC_QGROUP_CREATE( r1, 0x4010942a,&(0x7f000000 640)={0x1, 0x100}) or ioctl$BTRFS_IOC_SNAP_CREATE(r0, 0x50009401,&(0x7f000000 a80)={r2}," respectively; The most crucial thing is that when calling ioctl$BTRFS_IOC_QGROUP_CREATE, the passed parameter qgroupid value is 256, while BTRFS_FIRST_FREE_OBJECTID is also equal to 256, indicating that the passed parameter qgroupid is obviously incorrect.
This conclusion looks incorrect to me. Subvolumes are allowed to have any id in the range [BTRFS_FIRST_TREE_OBJECTID, BTRFS_LAST_TREE_OBJECTID]. In fact, you can easily create a subvolume with 256 as its subvolumeid. Just create an empty fs, and create a new subvolume in it, then you got; item 11 key (256 ROOT_ITEM 0) itemoff 12961 itemsize 439 generation 7 root_dirid 256 bytenr 30441472 byte_limit 0 bytes_used 16384 ... So it's completely valid. The root cause is just snapshot creation conflicts with an existing qgroup. Thanks, Qu
Reported-and-tested-by: syzbot+4d81015bc10889fd12ea@xxxxxxxxxxxxxxxxxxxxxxxxx Fixes: 6ed05643ddb1 ("btrfs: create qgroup earlier in snapshot creation") Signed-off-by: Lizhi Xu <lizhi.xu@xxxxxxxxxxxxx> --- fs/btrfs/ioctl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 752acff2c734..21cf7a7f18ab 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -3799,6 +3799,11 @@ static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg) goto out; } + if (sa->create && sa->qgroupid == BTRFS_FIRST_FREE_OBJECTID) { > + ret = -EINVAL; + goto out; + } + trans = btrfs_join_transaction(root); if (IS_ERR(trans)) { ret = PTR_ERR(trans);