Commit 251d0d2a by Dwight Engen Committed by Stéphane Graber

uidmap: fix writing multiple ranges

The kernel requires a single atomic write for setting the /proc idmap files. We were calling write(2) more than once when multiple ranges were configured so instead build a buffer to pass in one write(2) call. Change id types to unsigned long to handle large id mappings gracefully. Fix max id in example comment. Signed-off-by: 's avatarDwight Engen <dwight.engen@oracle.com> Acked-by: 's avatarSerge E. Hallyn <serge.hallyn@ubuntu.com>
parent a84b9932
...@@ -2447,7 +2447,8 @@ int lxc_assign_network(struct lxc_list *network, pid_t pid) ...@@ -2447,7 +2447,8 @@ int lxc_assign_network(struct lxc_list *network, pid_t pid)
return 0; return 0;
} }
static int add_id_mapping(enum idtype idtype, pid_t pid, uid_t ns_start, uid_t host_start, int range) static int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
size_t buf_size)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
int ret, closeret; int ret, closeret;
...@@ -2463,7 +2464,7 @@ static int add_id_mapping(enum idtype idtype, pid_t pid, uid_t ns_start, uid_t h ...@@ -2463,7 +2464,7 @@ static int add_id_mapping(enum idtype idtype, pid_t pid, uid_t ns_start, uid_t h
perror("open"); perror("open");
return -EINVAL; return -EINVAL;
} }
ret = fprintf(f, "%d %d %d", ns_start, host_start, range); ret = fwrite(buf, buf_size, 1, f);
if (ret < 0) if (ret < 0)
SYSERROR("writing id mapping"); SYSERROR("writing id mapping");
closeret = fclose(f); closeret = fclose(f);
...@@ -2477,13 +2478,34 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid) ...@@ -2477,13 +2478,34 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
struct lxc_list *iterator; struct lxc_list *iterator;
struct id_map *map; struct id_map *map;
int ret = 0; int ret = 0;
char *buf,*pos;
lxc_list_for_each(iterator, idmap) { enum idtype type;
map = iterator->elem;
ret = add_id_mapping(map->idtype, pid, map->nsid, map->hostid, map->range); /* The kernel only takes <= 4k for writes to /proc/<nr>/[ug]id_map */
buf = pos = malloc(4096);
if (!buf)
return -ENOMEM;
for(type = ID_TYPE_UID; type <= ID_TYPE_GID; type++) {
int left,fill;
lxc_list_for_each(iterator, idmap) {
map = iterator->elem;
if (map->idtype == type) {
left = 4096 - (pos - buf);
fill = snprintf(pos, left, "%lu %lu %lu\n",
map->nsid, map->hostid, map->range);
if (fill <= 0 || fill >= left)
SYSERROR("snprintf failed, too many mappings");
pos += fill;
}
}
ret = write_id_mapping(type, pid, buf, pos-buf);
if (ret) if (ret)
break; break;
pos = buf;
} }
free(buf);
return ret; return ret;
} }
......
...@@ -149,17 +149,17 @@ enum idtype { ...@@ -149,17 +149,17 @@ enum idtype {
/* /*
* id_map is an id map entry. Form in confile is: * id_map is an id map entry. Form in confile is:
* lxc.id_map = U 9800 0 100 * lxc.id_map = u 0 9800 100
* lxc.id_map = U 9900 1000 100 * lxc.id_map = u 1000 9900 100
* lxc.id_map = G 9800 0 100 * lxc.id_map = g 0 9800 100
* lxc.id_map = G 9900 1000 100 * lxc.id_map = g 1000 9900 100
* meaning the container can use uids and gids 0-100 and 1000-1100, * meaning the container can use uids and gids 0-99 and 1000-1099,
* with uid 0 mapping to uid 9800 on the host, and gid 1000 to * with [ug]id 0 mapping to [ug]id 9800 on the host, and [ug]id 1000 to
* gid 9900 on the host. * [ug]id 9900 on the host.
*/ */
struct id_map { struct id_map {
enum idtype idtype; enum idtype idtype;
int hostid, nsid, range; unsigned long hostid, nsid, range;
}; };
/* /*
......
...@@ -1114,7 +1114,7 @@ static int config_idmap(const char *key, const char *value, struct lxc_conf *lxc ...@@ -1114,7 +1114,7 @@ static int config_idmap(const char *key, const char *value, struct lxc_conf *lxc
char *subkey; char *subkey;
struct lxc_list *idmaplist = NULL; struct lxc_list *idmaplist = NULL;
struct id_map *idmap = NULL; struct id_map *idmap = NULL;
int hostid, nsid, range; unsigned long hostid, nsid, range;
char type; char type;
int ret; int ret;
...@@ -1139,10 +1139,10 @@ static int config_idmap(const char *key, const char *value, struct lxc_conf *lxc ...@@ -1139,10 +1139,10 @@ static int config_idmap(const char *key, const char *value, struct lxc_conf *lxc
lxc_list_add_tail(&lxc_conf->id_map, idmaplist); lxc_list_add_tail(&lxc_conf->id_map, idmaplist);
ret = sscanf(value, "%c %d %d %d", &type, &nsid, &hostid, &range); ret = sscanf(value, "%c %lu %lu %lu", &type, &nsid, &hostid, &range);
if (ret != 4) if (ret != 4)
goto out; goto out;
INFO("read uid map: type %c nsid %d hostid %d range %d", type, nsid, hostid, range); INFO("read uid map: type %c nsid %lu hostid %lu range %lu", type, nsid, hostid, range);
if (type == 'u') if (type == 'u')
idmap->idtype = ID_TYPE_UID; idmap->idtype = ID_TYPE_UID;
else if (type == 'g') else if (type == 'g')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment