Commit 2659c7cb by Serge Hallyn Committed by Stéphane Graber

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: 's avatarSerge Hallyn <serge.hallyn@ubuntu.com> Acked-by: 's avatarStéphane Graber <stgraber@ubuntu.com>
parent 391260dc
...@@ -66,6 +66,11 @@ ...@@ -66,6 +66,11 @@
lxc_log_define(bdev, lxc); lxc_log_define(bdev, lxc);
struct rsync_data_char {
char *src;
char *dest;
};
static int do_rsync(const char *src, const char *dest) static int do_rsync(const char *src, const char *dest)
{ {
// call out to rsync // call out to rsync
...@@ -1433,6 +1438,22 @@ out: ...@@ -1433,6 +1438,22 @@ out:
return ret; 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, static int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
const char *cname, const char *oldpath, const char *lxcpath, int snap, const char *cname, const char *oldpath, const char *lxcpath, int snap,
uint64_t newsize, struct lxc_conf *conf) uint64_t newsize, struct lxc_conf *conf)
...@@ -1467,8 +1488,14 @@ static int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *old ...@@ -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) if (orig->mntopts && (new->mntopts = strdup(orig->mntopts)) == NULL)
return -1; return -1;
if (snap) if (snap) {
return btrfs_snapshot(orig->dest, new->dest); 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) { if (rmdir(new->dest) < 0 && errno != -ENOENT) {
SYSERROR("removing %s", new->dest); SYSERROR("removing %s", new->dest);
...@@ -1510,6 +1537,8 @@ static int btrfs_destroy(struct bdev *orig) ...@@ -1510,6 +1537,8 @@ static int btrfs_destroy(struct bdev *orig)
args.name[BTRFS_SUBVOL_NAME_MAX-1] = 0; args.name[BTRFS_SUBVOL_NAME_MAX-1] = 0;
ret = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args); ret = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
INFO("btrfs: snapshot create ioctl returned %d", ret); 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); free(newfull);
close(fd); close(fd);
...@@ -1887,11 +1916,6 @@ static int overlayfs_umount(struct bdev *bdev) ...@@ -1887,11 +1916,6 @@ static int overlayfs_umount(struct bdev *bdev)
return umount(bdev->dest); return umount(bdev->dest);
} }
struct rsync_data_char {
char *src;
char *dest;
};
static int rsync_delta(struct rsync_data_char *data) static int rsync_delta(struct rsync_data_char *data)
{ {
if (setgid(0) < 0) { if (setgid(0) < 0) {
...@@ -2538,6 +2562,7 @@ static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap, ...@@ -2538,6 +2562,7 @@ static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
// overlayfs -- which is also allowed) // overlayfs -- which is also allowed)
if (strcmp(b->type, "dir") == 0 || if (strcmp(b->type, "dir") == 0 ||
strcmp(b->type, "overlayfs") == 0 || strcmp(b->type, "overlayfs") == 0 ||
strcmp(b->type, "btrfs") == 0 ||
strcmp(b->type, "loop") == 0) strcmp(b->type, "loop") == 0)
return true; return true;
return false; return false;
...@@ -2546,7 +2571,7 @@ static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap, ...@@ -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, // unprivileged users can copy and snapshot dir, overlayfs,
// and loop. In particular, not zfs, btrfs, or lvm. // and loop. In particular, not zfs, btrfs, or lvm.
if (strcmp(t, "dir") == 0 || strcmp(t, "overlayfs") == 0 || if (strcmp(t, "dir") == 0 || strcmp(t, "overlayfs") == 0 ||
strcmp(t, "loop") == 0) strcmp(t, "btrfs") == 0 || strcmp(t, "loop") == 0)
return true; return true;
return false; return false;
} }
......
...@@ -229,8 +229,9 @@ int main(int argc, char *argv[]) ...@@ -229,8 +229,9 @@ int main(int argc, char *argv[])
fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]); fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
exit(1); exit(1);
} }
if (strcmp(my_args.bdevtype, "dir") && strcmp(my_args.bdevtype, "_unset")) { if (strcmp(my_args.bdevtype, "dir") && strcmp(my_args.bdevtype, "_unset") &&
fprintf(stderr, "Unprivileged users can only create directory backed containers\n"); strcmp(my_args.bdevtype, "btrfs")) {
fprintf(stderr, "Unprivileged users cannot create %s containers", my_args.bdevtype);
exit(1); exit(1);
} }
} }
......
...@@ -918,9 +918,9 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet ...@@ -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) { 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); exit(1);
} }
if (bdev->ops->mount(bdev) < 0) { if (bdev->ops->mount(bdev) < 0) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment