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)
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;
/* 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;
}
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]);