]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
conf: rework userns_exec_1()
authorChristian Brauner <christian.brauner@ubuntu.com>
Thu, 4 Jan 2018 14:01:06 +0000 (15:01 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Fri, 19 Jan 2018 13:31:08 +0000 (14:31 +0100)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/conf.c

index 3b63ad3fad0e06e64baef7686f5bf60eb06c1855..ddfd84aa263157f4be80ce18f5fad8df6700ff79 100644 (file)
@@ -1278,6 +1278,15 @@ static struct id_map *find_mapped_nsid_entry(struct lxc_conf *conf, unsigned id,
        struct id_map *map;
        struct id_map *retmap = NULL;
 
+       /* Shortcut for container's root mappings. */
+       if (id == 0) {
+               if (idtype == ID_TYPE_UID)
+                       return conf->root_nsuid_map;
+
+               if (idtype == ID_TYPE_GID)
+                       return conf->root_nsgid_map;
+       }
+
        lxc_list_for_each(it, &conf->id_map) {
                map = it->elem;
                if (map->idtype != idtype)
@@ -3615,86 +3624,46 @@ static struct id_map *mapped_hostid_add(struct lxc_conf *conf, uid_t id, enum id
        return entry;
 }
 
-/* Run a function in a new user namespace.
- * The caller's euid/egid will be mapped if it is not already.
- * Afaict, userns_exec_1() is only used to operate based on privileges for the
- * user's own {g,u}id on the host and for the container root's unmapped {g,u}id.
- * This means we require only to establish a mapping from:
- * - the container root {g,u}id as seen from the host > user's host {g,u}id
- * - the container root -> some sub{g,u}id
- * The former we add, if the user did not specifiy a mapping. The latter we
- * retrieve from the ontainer's configured {g,u}id mappings as it must have been
- * there to start the container in the first place.
- */
-int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
-                 const char *fn_name)
+struct lxc_list *get_minimal_idmap(struct lxc_conf *conf)
 {
-       pid_t pid;
        uid_t euid, egid;
-       struct userns_fn_data d;
-       int p[2];
-       struct lxc_list *it;
-       struct id_map *map;
-       char c = '1';
-       int ret = -1, status = -1;
        uid_t nsuid = (conf->root_nsuid_map != NULL) ? 0 : conf->init_uid;
        gid_t nsgid = (conf->root_nsgid_map != NULL) ? 0 : conf->init_gid;
        struct lxc_list *idmap = NULL, *tmplist = NULL;
        struct id_map *container_root_uid = NULL, *container_root_gid = NULL,
                      *host_uid_map = NULL, *host_gid_map = NULL;
 
-       ret = pipe(p);
-       if (ret < 0) {
-               SYSERROR("opening pipe");
-               return -1;
-       }
-       d.fn = fn;
-       d.fn_name = fn_name;
-       d.arg = data;
-       d.p[0] = p[0];
-       d.p[1] = p[1];
-
-       /* Clone child in new user namespace. */
-       pid = lxc_clone(run_userns_fn, &d, CLONE_NEWUSER);
-       if (pid < 0) {
-               ERROR("failed to clone child process in new user namespace");
-               goto on_error;
-       }
-
-       close(p[0]);
-       p[0] = -1;
-
        /* Find container root mappings. */
-       euid = geteuid();
        container_root_uid = mapped_nsid_add(conf, nsuid, ID_TYPE_UID);
        if (!container_root_uid) {
-               DEBUG("Failed to find mapping for container root uid %d", 0);
+               DEBUG("Failed to find mapping for namespace uid %d", 0);
                goto on_error;
        }
-       if (euid >= container_root_uid->hostid && euid < container_root_uid->hostid + container_root_uid->range)
+       euid = geteuid();
+       if (euid >= container_root_uid->hostid &&
+           euid < (container_root_uid->hostid + container_root_uid->range))
                host_uid_map = container_root_uid;
 
-       egid = getegid();
        container_root_gid = mapped_nsid_add(conf, nsgid, ID_TYPE_GID);
        if (!container_root_gid) {
-               DEBUG("Failed to find mapping for container root gid %d", 0);
+               DEBUG("Failed to find mapping for namespace gid %d", 0);
                goto on_error;
        }
-       if (egid >= container_root_gid->hostid && egid < container_root_gid->hostid + container_root_gid->range)
+       egid = getegid();
+       if (egid >= container_root_gid->hostid &&
+           egid < (container_root_gid->hostid + container_root_gid->range))
                host_gid_map = container_root_gid;
 
        /* Check whether the {g,u}id of the user has a mapping. */
        if (!host_uid_map)
                host_uid_map = mapped_hostid_add(conf, euid, ID_TYPE_UID);
-
-       if (!host_gid_map)
-               host_gid_map = mapped_hostid_add(conf, egid, ID_TYPE_GID);
-
        if (!host_uid_map) {
                DEBUG("Failed to find mapping for uid %d", euid);
                goto on_error;
        }
 
+       if (!host_gid_map)
+               host_gid_map = mapped_hostid_add(conf, egid, ID_TYPE_GID);
        if (!host_gid_map) {
                DEBUG("Failed to find mapping for gid %d", egid);
                goto on_error;
@@ -3750,29 +3719,95 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
        /* idmap will now keep track of that memory. */
        host_gid_map = NULL;
 
+       TRACE("Allocated minimal idmapping");
+       return idmap;
+
+on_error:
+       if (idmap)
+               lxc_free_idmap(idmap);
+       if (container_root_uid)
+               free(container_root_uid);
+       if (container_root_gid)
+               free(container_root_gid);
+       if (host_uid_map && (host_uid_map != container_root_uid))
+               free(host_uid_map);
+       if (host_gid_map && (host_gid_map != container_root_gid))
+               free(host_gid_map);
+
+       return NULL;
+}
+
+/* Run a function in a new user namespace.
+ * The caller's euid/egid will be mapped if it is not already.
+ * Afaict, userns_exec_1() is only used to operate based on privileges for the
+ * user's own {g,u}id on the host and for the container root's unmapped {g,u}id.
+ * This means we require only to establish a mapping from:
+ * - the container root {g,u}id as seen from the host > user's host {g,u}id
+ * - the container root -> some sub{g,u}id
+ * The former we add, if the user did not specifiy a mapping. The latter we
+ * retrieve from the ontainer's configured {g,u}id mappings as it must have been
+ * there to start the container in the first place.
+ */
+int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
+                 const char *fn_name)
+{
+       pid_t pid;
+       struct userns_fn_data d;
+       int p[2];
+       char c = '1';
+       int ret = -1, status = -1;
+       struct lxc_list *idmap;
+
+       idmap = get_minimal_idmap(conf);
+       if (!idmap)
+               return -1;
+
+       ret = pipe(p);
+       if (ret < 0) {
+               SYSERROR("Failed to create pipe");
+               return -1;
+       }
+       d.fn = fn;
+       d.fn_name = fn_name;
+       d.arg = data;
+       d.p[0] = p[0];
+       d.p[1] = p[1];
+
+       /* Clone child in new user namespace. */
+       pid = lxc_raw_clone_cb(run_userns_fn, &d, CLONE_NEWUSER);
+       if (pid < 0) {
+               ERROR("failed to clone child process in new user namespace");
+               goto on_error;
+       }
+
+       close(p[0]);
+       p[0] = -1;
+
        if (lxc_log_get_level() == LXC_LOG_LEVEL_TRACE ||
            conf->loglevel == LXC_LOG_LEVEL_TRACE) {
+               struct lxc_list *it;
+               struct id_map *map;
+
                lxc_list_for_each(it, idmap) {
                        map = it->elem;
-                       TRACE("establishing %cid mapping for \"%d\" in new "
+                       TRACE("Establishing %cid mapping for \"%d\" in new "
                              "user namespace: nsuid %lu - hostid %lu - range "
-                             "%lu",
-                             (map->idtype == ID_TYPE_UID) ? 'u' : 'g', pid,
-                             map->nsid, map->hostid, map->range);
+                             "%lu", (map->idtype == ID_TYPE_UID) ? 'u' : 'g',
+                             pid, map->nsid, map->hostid, map->range);
                }
        }
 
        /* Set up {g,u}id mapping for user namespace of child process. */
        ret = lxc_map_ids(idmap, pid);
        if (ret < 0) {
-               ERROR("error setting up {g,u}id mappings for child process "
+               ERROR("Error setting up {g,u}id mappings for child process "
                      "\"%d\"", pid);
                goto on_error;
        }
 
        /* Tell child to proceed. */
        if (write(p[1], &c, 1) != 1) {
-               SYSERROR("failed telling child process \"%d\" to proceed", pid);
+               SYSERROR("Failed telling child process \"%d\" to proceed", pid);
                goto on_error;
        }
 
@@ -3781,17 +3816,6 @@ on_error:
        if (pid > 0)
                status = wait_for_pid(pid);
 
-       if (idmap)
-               lxc_free_idmap(idmap);
-       if (container_root_uid)
-               free(container_root_uid);
-       if (container_root_gid)
-               free(container_root_gid);
-       if (host_uid_map && (host_uid_map != container_root_uid))
-               free(host_uid_map);
-       if (host_gid_map && (host_gid_map != container_root_gid))
-               free(host_gid_map);
-
        if (p[0] != -1)
                close(p[0]);
        close(p[1]);