]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/commitdiff
UBUNTU: SAUCE: shiftfs: let userns root destroy subvolumes from other users
authorChristian Brauner <christian.brauner@ubuntu.com>
Wed, 20 May 2020 11:44:27 +0000 (13:44 +0200)
committerMarcelo Henrique Cerri <marcelo.cerri@canonical.com>
Mon, 22 Jun 2020 20:21:13 +0000 (17:21 -0300)
BugLink: https://bugs.launchpad.net/bugs/1879688
Stéphane reported a bug found during NorthSec that makes heavy use of
shiftfs. When a subvolume or snapshot is created as userns root in the
container and then chowned to another user a delete as the root user
will fail. The reason for this is that we drop all capabilities as a
safety measure before calling btrfs ioctls. The only workable fix I
could think of is to retain the CAP_DAC_OVERRIDE capability for the
BTRFS_IOC_SNAP_DESTROY ioctl. All other solutions would be way more
invasive.

Cc: Seth Forshee <seth.forshee@canonical.com>
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Acked-by: Kleber Souza <kleber.souza@canonical.com>
Acked-by: Seth Forshee <seth.forshee@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
fs/shiftfs.c

index 39b878a6f820a67f1a58cb59e547b19035ee4b9c..f5c709805fb887a61769072767289f232563c982 100644 (file)
@@ -1337,7 +1337,7 @@ static int shiftfs_fadvise(struct file *file, loff_t offset, loff_t len,
        return ret;
 }
 
-static int shiftfs_override_ioctl_creds(const struct super_block *sb,
+static int shiftfs_override_ioctl_creds(int cmd, const struct super_block *sb,
                                        const struct cred **oldcred,
                                        struct cred **newcred)
 {
@@ -1362,6 +1362,16 @@ static int shiftfs_override_ioctl_creds(const struct super_block *sb,
        cap_clear((*newcred)->cap_inheritable);
        cap_clear((*newcred)->cap_permitted);
 
+       if (cmd == BTRFS_IOC_SNAP_DESTROY) {
+               kuid_t kuid_root = make_kuid(sb->s_user_ns, 0);
+               /*
+                * Allow the root user in the container to remove subvolumes
+                * from other users.
+                */
+               if (uid_valid(kuid_root) && uid_eq(fsuid, kuid_root))
+                       cap_raise((*newcred)->cap_effective, CAP_DAC_OVERRIDE);
+       }
+
        put_cred(override_creds(*newcred));
        return 0;
 }
@@ -1494,7 +1504,7 @@ static long shiftfs_real_ioctl(struct file *file, unsigned int cmd,
        if (ret)
                goto out_restore;
 
-       ret = shiftfs_override_ioctl_creds(sb, &oldcred, &newcred);
+       ret = shiftfs_override_ioctl_creds(cmd, sb, &oldcred, &newcred);
        if (ret)
                goto out_fdput;