From: Serge Hallyn Date: Tue, 6 May 2014 20:50:45 +0000 (+0000) Subject: btrfs: support unprivileged create and clone X-Git-Tag: lxc-1.1.0.alpha1~109 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2659c7cbd55beee72b9b1740f48f48ad9d7d89da;p=thirdparty%2Flxc.git btrfs: support unprivileged create and clone 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 Acked-by: Stéphane Graber --- diff --git a/src/lxc/bdev.c b/src/lxc/bdev.c index 49ba8ae67..20e9fb3ad 100644 --- a/src/lxc/bdev.c +++ b/src/lxc/bdev.c @@ -66,6 +66,11 @@ 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; } diff --git a/src/lxc/lxc_create.c b/src/lxc/lxc_create.c index caca056ef..2cc866a32 100644 --- a/src/lxc/lxc_create.c +++ b/src/lxc/lxc_create.c @@ -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); } } diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 270b8fc2a..9e23c7b08 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -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) {