]> git.baikalelectronics.ru Git - kernel.git/commitdiff
btrfs: relax restrictions for SNAP_DESTROY_V2 with subvolids
authorChristian Brauner <christian.brauner@ubuntu.com>
Tue, 27 Jul 2021 10:48:54 +0000 (12:48 +0200)
committerDavid Sterba <dsterba@suse.com>
Mon, 23 Aug 2021 11:19:14 +0000 (13:19 +0200)
So far we prevented the deletion of subvolumes and snapshots using
subvolume ids possible with the BTRFS_SUBVOL_SPEC_BY_ID flag.

This restriction is necessary on idmapped mounts as this allows
filesystem wide subvolume and snapshot deletions and thus can escape the
scope of what's exposed under the mount identified by the fd passed with
the ioctl.

Deletion by subvolume id works by looking for an alias of the parent of
the subvolume or snapshot to be deleted. The parent alias can be
anywhere in the filesystem. However, as long as the alias of the parent
that is found is the same as the one identified by the file descriptor
passed through the ioctl we can allow the deletion.

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/ioctl.c

index 6ec30e11ad22bd88f30b3acd2bcb98ae78c3f9a2..63e7b2616302dcbeae15a9fceaf990201cffc16d 100644 (file)
@@ -2936,17 +2936,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                        if (err)
                                goto out;
                } else {
-                       /*
-                        * Deleting by subvolume id can be used to delete
-                        * subvolumes/snapshots anywhere in the filesystem.
-                        * Ensure that users can't abuse idmapped mounts of
-                        * btrfs subvolumes/snapshots to perform operations in
-                        * the whole filesystem.
-                        */
-                       if (mnt_userns != &init_user_ns) {
-                               err = -EOPNOTSUPP;
-                               goto out;
-                       }
+                       struct inode *old_dir;
 
                        if (vol_args2->subvolid < BTRFS_FIRST_FREE_OBJECTID) {
                                err = -EINVAL;
@@ -2984,6 +2974,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                                err = PTR_ERR(parent);
                                goto out_drop_write;
                        }
+                       old_dir = dir;
                        dir = d_inode(parent);
 
                        /*
@@ -2994,6 +2985,20 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                         */
                        destroy_parent = true;
 
+                       /*
+                        * On idmapped mounts, deletion via subvolid is
+                        * restricted to subvolumes that are immediate
+                        * ancestors of the inode referenced by the file
+                        * descriptor in the ioctl. Otherwise the idmapping
+                        * could potentially be abused to delete subvolumes
+                        * anywhere in the filesystem the user wouldn't be able
+                        * to delete without an idmapped mount.
+                        */
+                       if (old_dir != dir && mnt_userns != &init_user_ns) {
+                               err = -EOPNOTSUPP;
+                               goto free_parent;
+                       }
+
                        subvol_name_ptr = btrfs_get_subvol_name_from_objectid(
                                                fs_info, vol_args2->subvolid);
                        if (IS_ERR(subvol_name_ptr)) {