From: Serge Hallyn Date: Tue, 11 Feb 2014 19:43:19 +0000 (-0600) Subject: bdev: allow unprivileged overlayfs snapshots X-Git-Tag: lxc-1.0.0.rc1~36 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a7ef8753bcbcd9ad2ff229684bf16bd71764b7be;p=thirdparty%2Flxc.git bdev: allow unprivileged overlayfs snapshots Also make sure to chown the new rootfs path to the container owner. This is how we make sure that the container root is allowed to write under delta0. Signed-off-by: Serge Hallyn Acked-by: Stéphane Graber --- diff --git a/src/lxc/bdev.c b/src/lxc/bdev.c index 01c06e104..7f8ab9cba 100644 --- a/src/lxc/bdev.c +++ b/src/lxc/bdev.c @@ -2129,6 +2129,31 @@ bool bdev_is_dir(const char *path) return ret; } +/* + * is an unprivileged user allowed to make this kind of snapshot + */ +static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap, + bool maybesnap) +{ + if (!t) { + // new type will be same as original + // (unless snap && b->type == dir, in which case it will be + // overlayfs -- which is also allowed) + if (strcmp(b->type, "dir") == 0 || + strcmp(b->type, "overlayfs") == 0 || + strcmp(b->type, "loop") == 0) + return true; + return false; + } + + // 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) + return true; + return false; +} + /* * If we're not snaphotting, then bdev_copy becomes a simple case of mount * the original, mount the new, and rsync the contents. @@ -2180,26 +2205,6 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, } } - /* check for privilege */ - if (am_unpriv()) { - if (snap && !maybe_snap) { - ERROR("Unprivileged users cannot snapshot"); - bdev_put(orig); - return NULL; - } - if (bdevtype && strcmp(bdevtype, "dir") != 0) { - ERROR("Unprivileged users can only make dir copy-clones"); - bdev_put(orig); - return NULL; - } - if (strcmp(orig->type, "dir") != 0) { - ERROR("Unprivileged users can only make dir copy-clones"); - bdev_put(orig); - return NULL; - } - } - - /* * special case for snapshot - if caller requested maybe_snapshot and * keepbdevtype and backing store is directory, then proceed with a copy @@ -2214,6 +2219,12 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, if (!bdevtype && !keepbdevtype && snap && strcmp(orig->type , "dir") == 0) bdevtype = "overlayfs"; + if (am_unpriv() && !unpriv_snap_allowed(orig, bdevtype, snap, maybe_snap)) { + ERROR("Unsupported snapshot type for unprivileged users"); + bdev_put(orig); + return NULL; + } + *needs_rdep = 0; if (bdevtype && strcmp(orig->type, "dir") == 0 && strcmp(bdevtype, "overlayfs") == 0) @@ -2232,6 +2243,10 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, bdev_put(new); return NULL; } + + if (am_unpriv() && chown_mapped_root(new->src, c0->lxc_conf) < 0) + WARN("Failed to update ownership of %s", new->dest); + if (snap) return new; diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 4e25432c4..522c5901c 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -3364,6 +3364,7 @@ int chown_mapped_root(char *path, struct lxc_conf *conf) uid_t rootid; pid_t pid; unsigned long val; + char *chownpath = path; if (!get_mapped_rootid(conf, ID_TYPE_UID, &val)) { ERROR("No mapping for container root"); @@ -3371,6 +3372,24 @@ int chown_mapped_root(char *path, struct lxc_conf *conf) } rootid = (uid_t) val; + /* + * In case of overlay, we want only the writeable layer + * to be chowned + */ + if (strncmp(path, "overlayfs:", 10) == 0) { + chownpath = strchr(path, ':'); + if (!chownpath) { + ERROR("Bad overlay path: %s", path); + return -1; + } + chownpath = strchr(chownpath+1, ':'); + if (!chownpath) { + ERROR("Bad overlay path: %s", path); + return -1; + } + chownpath++; + } + path = chownpath; if (geteuid() == 0) { if (chown(path, rootid, -1) < 0) { ERROR("Error chowning %s", path);