[PATCH] btrfs: prevent deleting the wrong subvolume by ID
From: guolingxing
Date: Sun Oct 18 2026 - 03:43:01 EST
When deleting a subvolume by ID, btrfs_ioctl_snap_destroy() first
resolves the requested ID to a name, then looks up that name again
under the parent directory lock.
A concurrent rename can change which subvolume is associated with
the name between these operations. Since the deletion path does not
verify the ID of the resolved subvolume, it can delete a different
subvolume while leaving the requested one intact.
This was reproduced by repeatedly exchanging the names of two
subvolumes using renameat2(RENAME_EXCHANGE) while deleting one of
them by ID. The wrong subvolume was deleted in 9 out of 14 independent
tests.
Fix this by checking that the resolved subvolume ID matches the
requested ID while holding the parent directory lock. Return -ENOENT
if the IDs differ, preventing deletion of the wrong subvolume.
Fixes: 949964c92843 ("btrfs: add new BTRFS_IOC_SNAP_DESTROY_V2 ioctl")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: guolingxing <guolingxing@xxxxxxxxxx>
---
fs/btrfs/ioctl.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 576cd76ca0bf..39eb7722998d 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2380,6 +2380,17 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
inode = d_inode(dentry);
dest = BTRFS_I(inode)->root;
+
+ /*
+ * A concurrent rename may have changed which subvolume the name
+ * refers to. Verify that the resolved ID still matches the requested ID.
+ */
+ if (destroy_v2 && (vol_args2->flags & BTRFS_SUBVOL_SPEC_BY_ID) &&
+ btrfs_root_id(dest) != vol_args2->subvolid) {
+ ret = -ENOENT;
+ goto out_end_removing;
+ }
+
if (!capable(CAP_SYS_ADMIN)) {
/*
* Regular user. Only allow this with a special mount
--
2.34.1