]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
btrfs: support unprivileged create and clone
authorSerge Hallyn <serge.hallyn@ubuntu.com>
Tue, 6 May 2014 20:50:45 +0000 (20:50 +0000)
committerStéphane Graber <stgraber@ubuntu.com>
Wed, 7 May 2014 03:54:39 +0000 (22:54 -0500)
btrfs subvolume ioctls are usable by unprivileged users, so allow
unprivileged containers to reside on btrfs.

This patch does not yet enable destroy.

Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
src/lxc/bdev.c
src/lxc/lxc_create.c
src/lxc/lxccontainer.c

index 49ba8ae674e6ac23846eab7f93f019e380971b65..20e9fb3ad3856f4342ecaea0ac302a8edecda582 100644 (file)
 
 lxc_log_define(bdev, lxc);
 
+struct rsync_data_char {
+       char *src;
+       char *dest;
+};
+
 static int do_rsync(const char *src, const char *dest)
 {
        // call out to rsync
@@ -1433,6 +1438,22 @@ out:
        return ret;
 }
 
+static int btrfs_snapshot_wrapper(void *data)
+{
+       struct rsync_data_char *arg = data;
+       if (setgid(0) < 0) {
+               ERROR("Failed to setgid to 0");
+               return -1;
+       }
+       if (setgroups(0, NULL) < 0)
+               WARN("Failed to clear groups");
+       if (setuid(0) < 0) {
+               ERROR("Failed to setuid to 0");
+               return -1;
+       }
+       return btrfs_snapshot(arg->src, arg->dest);
+}
+
 static int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
                const char *cname, const char *oldpath, const char *lxcpath, int snap,
                uint64_t newsize, struct lxc_conf *conf)
@@ -1467,8 +1488,14 @@ static int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *old
        if (orig->mntopts && (new->mntopts = strdup(orig->mntopts)) == NULL)
                return -1;
 
-       if (snap)
-               return btrfs_snapshot(orig->dest, new->dest);
+       if (snap) {
+               struct rsync_data_char sdata;
+               if (!am_unpriv())
+                       return btrfs_snapshot(orig->dest, new->dest);
+               sdata.dest = new->dest;
+               sdata.src = orig->dest;
+               return userns_exec_1(conf, btrfs_snapshot_wrapper, &sdata);
+       }
 
        if (rmdir(new->dest) < 0 && errno != -ENOENT) {
                SYSERROR("removing %s", new->dest);
@@ -1510,6 +1537,8 @@ static int btrfs_destroy(struct bdev *orig)
        args.name[BTRFS_SUBVOL_NAME_MAX-1] = 0;
        ret = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
        INFO("btrfs: snapshot create ioctl returned %d", ret);
+       if (ret < 0 && errno == EPERM)
+               INFO("Is the rootfs mounted with -o user_subvol_rm_allowed?");
 
        free(newfull);
        close(fd);
@@ -1887,11 +1916,6 @@ static int overlayfs_umount(struct bdev *bdev)
        return umount(bdev->dest);
 }
 
-struct rsync_data_char {
-       char *src;
-       char *dest;
-};
-
 static int rsync_delta(struct rsync_data_char *data)
 {
        if (setgid(0) < 0) {
@@ -2538,6 +2562,7 @@ static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
                // overlayfs -- which is also allowed)
                if (strcmp(b->type, "dir") == 0 ||
                                strcmp(b->type, "overlayfs") == 0 ||
+                               strcmp(b->type, "btrfs") == 0 ||
                                strcmp(b->type, "loop") == 0)
                        return true;
                return false;
@@ -2546,7 +2571,7 @@ static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
        // unprivileged users can copy and snapshot dir, overlayfs,
        // and loop.  In particular, not zfs, btrfs, or lvm.
        if (strcmp(t, "dir") == 0 || strcmp(t, "overlayfs") == 0 ||
-                       strcmp(t, "loop") == 0)
+                       strcmp(t, "btrfs") == 0 || strcmp(t, "loop") == 0)
                return true;
        return false;
 }
index caca056ef4ce28aa18bf038bb1e77a4a3d3cc335..2cc866a32d730c3fd9039047fc2f2f8709100818 100644 (file)
@@ -229,8 +229,9 @@ int main(int argc, char *argv[])
                        fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
                        exit(1);
                }
-               if (strcmp(my_args.bdevtype, "dir") && strcmp(my_args.bdevtype, "_unset")) {
-                       fprintf(stderr, "Unprivileged users can only create directory backed containers\n");
+               if (strcmp(my_args.bdevtype, "dir") && strcmp(my_args.bdevtype, "_unset") &&
+                               strcmp(my_args.bdevtype, "btrfs")) {
+                       fprintf(stderr, "Unprivileged users cannot create %s containers", my_args.bdevtype);
                        exit(1);
                }
        }
index 270b8fc2a3bb28b57460138fe6ed0e8461b53aa7..9e23c7b08cd1d6d946fd459fb7dfb1bae2217843 100644 (file)
@@ -918,9 +918,9 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet
                                }
                        }
                }
-               if (strcmp(bdev->type, "dir") != 0) {
+               if (strcmp(bdev->type, "dir") && strcmp(bdev->type, "btrfs")) {
                        if (geteuid() != 0) {
-                               ERROR("non-root users can only create directory-backed containers");
+                               ERROR("non-root users can only create btrfs and directory-backed containers");
                                exit(1);
                        }
                        if (bdev->ops->mount(bdev) < 0) {