]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
uidmap: fix writing multiple ranges
authorDwight Engen <dwight.engen@oracle.com>
Mon, 11 Mar 2013 20:36:25 +0000 (16:36 -0400)
committerStéphane Graber <stgraber@ubuntu.com>
Tue, 12 Mar 2013 21:06:53 +0000 (17:06 -0400)
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: Dwight Engen <dwight.engen@oracle.com>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
src/lxc/conf.c
src/lxc/conf.h
src/lxc/confile.c

index e2abc72df16e07761549e7de5a976cc5901ef596..9700c7aa2797d1c51dca8fea16d3bede4f5befb4 100644 (file)
@@ -2447,7 +2447,8 @@ int lxc_assign_network(struct lxc_list *network, pid_t pid)
        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];
        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
                perror("open");
                return -EINVAL;
        }
-       ret = fprintf(f, "%d %d %d", ns_start, host_start, range);
+       ret = fwrite(buf, buf_size, 1, f);
        if (ret < 0)
                SYSERROR("writing id mapping");
        closeret = fclose(f);
@@ -2477,13 +2478,34 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
        struct lxc_list *iterator;
        struct id_map *map;
        int ret = 0;
-
-       lxc_list_for_each(iterator, idmap) {
-               map = iterator->elem;
-               ret = add_id_mapping(map->idtype, pid, map->nsid, map->hostid, map->range);
+       char *buf,*pos;
+       enum idtype type;
+
+       /* 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)
                        break;
+               pos = buf;
        }
+
+       free(buf);
        return ret;
 }
 
index 61456ae1871b6a92487c967c47e8cb8a1f4d6fa2..4c25970f309c81d44a6437b56fb938f2a182637e 100644 (file)
@@ -149,17 +149,17 @@ enum idtype {
 
 /*
  * id_map is an id map entry.  Form in confile is:
- * lxc.id_map = U 9800 0 100
- * lxc.id_map = U 9900 1000 100
- * lxc.id_map = G 9800 0 100
- * lxc.id_map = G 9900 1000 100
- * meaning the container can use uids and gids 0-100 and 1000-1100,
- * with uid 0 mapping to uid 9800 on the host, and gid 1000 to
- * gid 9900 on the host.
+ * lxc.id_map = u 0    9800 100
+ * lxc.id_map = u 1000 9900 100
+ * lxc.id_map = g 0    9800 100
+ * lxc.id_map = g 1000 9900 100
+ * meaning the container can use uids and gids 0-99 and 1000-1099,
+ * with [ug]id 0 mapping to [ug]id 9800 on the host, and [ug]id 1000 to
+ * [ug]id 9900 on the host.
  */
 struct id_map {
        enum idtype idtype;
-       int hostid, nsid, range;
+       unsigned long hostid, nsid, range;
 };
 
 /*
index 0f68fe44d547601391f2b2e3abdb710c8c73330f..cd02b2e2c3e4c7067503fc5c9bba6f8a20697624 100644 (file)
@@ -1114,7 +1114,7 @@ static int config_idmap(const char *key, const char *value, struct lxc_conf *lxc
        char *subkey;
        struct lxc_list *idmaplist = NULL;
        struct id_map *idmap = NULL;
-       int hostid, nsid, range;
+       unsigned long hostid, nsid, range;
        char type;
        int ret;
 
@@ -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);
 
-       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)
                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')
                idmap->idtype = ID_TYPE_UID;
        else if (type == 'g')