]> git.proxmox.com Git - mirror_lxc.git/commitdiff
fix chowning of tty and console uids
authorSerge Hallyn <serge.hallyn@ubuntu.com>
Wed, 23 Oct 2013 01:02:58 +0000 (01:02 +0000)
committerSerge Hallyn <serge.hallyn@ubuntu.com>
Thu, 24 Oct 2013 17:13:22 +0000 (12:13 -0500)
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@ubuntu.com>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
Changelog:
    Jul 22: remove hardcoded path for /bin/chown
    Jul 22: use new lxc-usernsexec

Conflicts:
src/lxc/lxccontainer.c

src/lxc/conf.c
src/lxc/conf.h
src/lxc/lxccontainer.c
src/lxc/start.c

index 8c48377ffa8e481098054dbd81bb0cc5f98f2550..043719cdeba76f36c3b141b3d4ee477ee942da82 100644 (file)
@@ -2858,7 +2858,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;
@@ -2869,9 +2869,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)
@@ -3020,89 +3020,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[] = {"lxc-usernsexec", "-m", map1, "-m", map2, "--", "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("lxc-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;
 }
 
index 445867d22849b86069016ebb74f81fcee53a2f6f..71399b9205bf85b059e6adabe0b7f12de2bca998 100644 (file)
@@ -350,8 +350,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
  */
@@ -362,7 +360,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
index fca0da2fe60d1a724aa3f35c79ce17d292265d39..9aea6145e0f6802fcfe1bf6b1423aad160fd589d 100644 (file)
@@ -693,49 +693,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[] = {"lxc-usernsexec", "-m", map1, "-m", map2, "--", "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("lxc-usernsexec", args);
-               SYSERROR("Failed executing lxc-usernsexec");
-               exit(1);
-       }
-       return wait_for_pid(pid);
-}
-
 /*
  * do_bdev_create: thin wrapper around bdev_create().  Like bdev_create(),
  * it returns a mounted bdev on success, NULL on error.
@@ -768,15 +725,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;
                }
index e46f3a0ac5c7246cd51c6e1bd63e8c17e5d6fb6c..1cadc0963f772aa7451b50a5479fe0997caff284 100644 (file)
@@ -353,6 +353,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;
 
@@ -784,11 +789,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;