From: Serge Hallyn <serge.hal...@ubuntu.com> It needs to be done from the handler, not the container, since the container may not have the rights.
Signed-off-by: Serge Hallyn <serge.hal...@ubuntu.com> --- src/lxc/conf.c | 126 +++++++++++++++++++++++-------------------------- src/lxc/conf.h | 6 +-- src/lxc/lxccontainer.c | 53 +-------------------- src/lxc/start.c | 10 ++-- 4 files changed, 69 insertions(+), 126 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 2e202ec..e8399a9 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -2615,7 +2615,7 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid) * return the host uid to which the container root is mapped, or -1 on * error */ -int get_mapped_rootid(struct lxc_conf *conf) +uid_t get_mapped_rootid(struct lxc_conf *conf) { struct lxc_list *it; struct id_map *map; @@ -2626,9 +2626,9 @@ int get_mapped_rootid(struct lxc_conf *conf) continue; if (map->nsid != 0) continue; - return map->hostid; + return (uid_t) map->hostid; } - return -1; + return (uid_t)-1; } bool hostid_is_mapped(int id, struct lxc_conf *conf) @@ -2772,89 +2772,81 @@ void lxc_delete_tty(struct lxc_tty_info *tty_info) } /* - * given a host uid, return the ns uid if it is mapped. - * if it is not mapped, return the original host id. + * chown_mapped_root: for an unprivileged user with uid X to chown a dir + * to subuid Y, he needs to run chown as root in a userns where + * nsid 0 is mapped to hostuid Y, and nsid Y is mapped to hostuid + * X. That way, the container root is privileged with respect to + * hostuid X, allowing him to do the chown. */ -static int shiftid(struct lxc_conf *c, int uid, enum idtype w) +int chown_mapped_root(char *path, struct lxc_conf *conf) { - struct lxc_list *iterator; - struct id_map *map; - int low, high; + uid_t rootid; + pid_t pid; - lxc_list_for_each(iterator, &c->id_map) { - map = iterator->elem; - if (map->idtype != w) - continue; - - low = map->nsid; - high = map->nsid + map->range; - if (uid < low || uid >= high) - continue; - - return uid - low + map->hostid; + if ((rootid = get_mapped_rootid(conf)) <= 0) { + ERROR("No mapping for container root"); + return -1; } - - return uid; -} - -/* - * Take a pathname for a file created on the host, and map the uid and gid - * into the container if needed. (Used for ttys) - */ -static int uid_shift_file(char *path, struct lxc_conf *c) -{ - struct stat statbuf; - int newuid, newgid; - - if (stat(path, &statbuf)) { - SYSERROR("stat(%s)", path); + if (geteuid() == 0) { + if (chown(path, rootid, -1) < 0) { + ERROR("Error chowning %s", path); + return -1; + } + return 0; + } + pid = fork(); + if (pid < 0) { + SYSERROR("Failed forking"); return -1; } + if (!pid) { + int hostuid = geteuid(), ret; + char map1[100], map2[100]; + char *args[] = {"usernsexec", "-m", map1, "-m", map2, "--", "/bin/chown", + "0", path, NULL}; - newuid = shiftid(c, statbuf.st_uid, ID_TYPE_UID); - newgid = shiftid(c, statbuf.st_gid, ID_TYPE_GID); - if (newuid != statbuf.st_uid || newgid != statbuf.st_gid) { - DEBUG("chowning %s from %d:%d to %d:%d\n", path, (int)statbuf.st_uid, (int)statbuf.st_gid, newuid, newgid); - if (chown(path, newuid, newgid)) { - SYSERROR("chown(%s)", path); + // "b:0:rootid:1" + ret = snprintf(map1, 100, "b:0:%d:1", rootid); + if (ret < 0 || ret >= 100) { + ERROR("Error uid printing map string"); return -1; } + + // "b:hostuid:hostuid:1" + ret = snprintf(map2, 100, "b:%d:%d:1", hostuid, hostuid); + if (ret < 0 || ret >= 100) { + ERROR("Error uid printing map string"); + return -1; + } + + ret = execvp("usernsexec", args); + SYSERROR("Failed executing usernsexec"); + exit(1); } - return 0; + return wait_for_pid(pid); } -int uid_shift_ttys(int pid, struct lxc_conf *conf) +int ttys_shift_ids(struct lxc_conf *c) { - int i, ret; - struct lxc_tty_info *tty_info = &conf->tty_info; - char path[MAXPATHLEN]; - char *ttydir = conf->ttydir; + int i; - if (!conf->rootfs.path) + if (lxc_list_empty(&c->id_map)) return 0; - /* first the console */ - ret = snprintf(path, sizeof(path), "/proc/%d/root/dev/%s/console", pid, ttydir ? ttydir : ""); - if (ret < 0 || ret >= sizeof(path)) { - ERROR("console path too long\n"); - return -1; - } - if (uid_shift_file(path, conf)) { - DEBUG("Failed to chown the console %s.\n", path); - return -1; - } - for (i=0; i< tty_info->nbtty; i++) { - ret = snprintf(path, sizeof(path), "/proc/%d/root/dev/%s/tty%d", - pid, ttydir ? ttydir : "", i + 1); - if (ret < 0 || ret >= sizeof(path)) { - ERROR("pathname too long for ttys"); - return -1; - } - if (uid_shift_file(path, conf)) { - DEBUG("Failed to chown pty %s.\n", path); + + for (i = 0; i < c->tty_info.nbtty; i++) { + struct lxc_pty_info *pty_info = &c->tty_info.pty_info[i]; + + if (chown_mapped_root(pty_info->name, c) < 0) { + ERROR("Failed to chown %s", pty_info->name); return -1; } } + if (chown_mapped_root(c->console.name, c) < 0) { + ERROR("Failed to chown %s", c->console.name); + return -1; + } + return 0; } diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 065b1df..bb3b456 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -321,8 +321,6 @@ extern int lxc_clear_cgroups(struct lxc_conf *c, const char *key); extern int lxc_clear_mount_entries(struct lxc_conf *c); extern int lxc_clear_hooks(struct lxc_conf *c, const char *key); -extern int uid_shift_ttys(int pid, struct lxc_conf *conf); - /* * Configure the container from inside */ @@ -332,7 +330,9 @@ extern int lxc_setup(const char *name, struct lxc_conf *lxc_conf, extern void lxc_rename_phys_nics_on_shutdown(struct lxc_conf *conf); -extern int get_mapped_rootid(struct lxc_conf *conf); +extern uid_t get_mapped_rootid(struct lxc_conf *conf); extern int find_unmapped_nsuid(struct lxc_conf *conf); extern bool hostid_is_mapped(int id, struct lxc_conf *conf); +extern int chown_mapped_root(char *path, struct lxc_conf *conf); +extern int ttys_shift_ids(struct lxc_conf *c); #endif diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index f9ce7d3..6790ac6 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -677,48 +677,6 @@ static bool create_container_dir(struct lxc_container *c) static const char *lxcapi_get_config_path(struct lxc_container *c); static bool lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v); -/* - * chown_mapped: for an unprivileged user with uid X to chown a dir - * to subuid Y, he needs to run chown as root in a userns where - * nsid 0 is mapped to hostuid Y, and nsid Y is mapped to hostuid - * X. That way, the container root is privileged with respect to - * hostuid X, allowing him to do the chown. - */ -static int chown_mapped(int nsrootid, char *path) -{ - if (nsrootid < 0) - return nsrootid; - pid_t pid = fork(); - if (pid < 0) { - SYSERROR("Failed forking"); - return -1; - } - if (!pid) { - int hostuid = geteuid(), ret; - char map1[100], map2[100]; - char *args[] = {"usernsexec", "-m", map1, "-m", map2, "--", "/bin/chown", - "0", path, NULL}; - - // "b:0:nsrootid:1" - ret = snprintf(map1, 100, "b:0:%d:1", nsrootid); - if (ret < 0 || ret >= 100) { - ERROR("Error uid printing map string"); - return -1; - } - - // "b:hostuid:hostuid:1" - ret = snprintf(map2, 100, "b:%d:%d:1", hostuid, hostuid); - if (ret < 0 || ret >= 100) { - ERROR("Error uid printing map string"); - return -1; - } - - ret = execvp("usernsexec", args); - SYSERROR("Failed executing usernsexec"); - exit(1); - } - return wait_for_pid(pid); -} /* * do_bdev_create: thin wrapper around bdev_create(). Like bdev_create(), @@ -749,15 +707,8 @@ static struct bdev *do_bdev_create(struct lxc_container *c, const char *type, * target uidmap */ if (geteuid() != 0) { - int rootid; - if ((rootid = get_mapped_rootid(c->lxc_conf)) <= 0) { - ERROR("No mapping for container root"); - bdev_put(bdev); - return NULL; - } - ret = chown_mapped(rootid, bdev->dest); - if (ret < 0) { - ERROR("Error chowning %s to %d\n", bdev->dest, rootid); + if (chown_mapped_root(bdev->dest, c->lxc_conf) < 0) { + ERROR("Error chowning %s to container root\n", bdev->dest); bdev_put(bdev); return NULL; } diff --git a/src/lxc/start.c b/src/lxc/start.c index 00020de..745e677 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -333,6 +333,11 @@ struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf, const char goto out_restore_sigmask; } + if (ttys_shift_ids(conf) < 0) { + ERROR("Failed to shift tty into container"); + goto out_restore_sigmask; + } + INFO("'%s' is initialized", name); return handler; @@ -731,11 +736,6 @@ int lxc_spawn(struct lxc_handler *handler) if (detect_shared_rootfs()) umount2(handler->conf->rootfs.mount, MNT_DETACH); - /* If child is in a fresh user namespace, chown his ptys for - * it */ - if (uid_shift_ttys(handler->pid, handler->conf)) - DEBUG("Failed to chown ptys.\n"); - if (handler->ops->post_start(handler, handler->data)) goto out_abort; -- 1.8.3.2 ------------------------------------------------------------------------------ See everything from the browser to the database with AppDynamics Get end-to-end visibility with application monitoring from AppDynamics Isolate bottlenecks and diagnose root cause in seconds. Start your free trial of AppDynamics Pro today! http://pubads.g.doubleclick.net/gampad/clk?id=48808831&iu=/4140/ostg.clktrk _______________________________________________ Lxc-devel mailing list Lxc-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/lxc-devel