[lxc-devel] [PATCH 8/8] fix chowning of tty and console uids
serge.hallyn at ubuntu.com
serge.hallyn at ubuntu.com
Fri Jul 19 15:02:31 UTC 2013
From: Serge Hallyn <serge.hallyn at 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.hallyn at 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
More information about the lxc-devel
mailing list