~serge-hallyn/ubuntu/quantal/lxc/lxc-user-ns

« back to all changes in this revision

Viewing changes to debian/patches/lxc-use-user-namespace.patch

  • Committer: Serge Hallyn
  • Date: 2012-10-29 16:51:57 UTC
  • Revision ID: serge.hallyn@ubuntu.com-20121029165157-xw2nxym7eo0ocxu4
Add user namespaces patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
Description: enable use of user namespaces in containers
 
2
 The rootfs will need to be chowned to the mapped userids, which can
 
3
 be done with the /usr/bin/uidmapshift tool shipped with the nsexec
 
4
 package in ppa:serge-hallyn/userns-natty.
 
5
 The container config supports new entries of the form:
 
6
  lxc.id_map = U 100000 0 10000
 
7
  lxc.id_map = G 100000 0 10000
 
8
 meaning map 'virtual' uids (in the container) 0-10000 to uids
 
9
 100000-110000 on the host, and same for gids.  So long as there are
 
10
 mappings specified in the container config, then CONFIG_NEWUSER will
 
11
 be used when the container is cloned.  This means that container
 
12
 setup is no longer done with root privilege on the host, only root
 
13
 privilege in the container.  Therefore cgroup setup is moved from the
 
14
 init task to the monitor task.
 
15
 .
 
16
 In order to be able to use (or at least further test and develop) this
 
17
 patch, the kernel needs to support use of the following with targeted
 
18
 capabilities only:
 
19
   bind mounts (done)
 
20
   kernel fs mounts (especially sys and proc) (done)
 
21
   devpts mounts (done)
 
22
   pivot_root
 
23
   network device renaming
 
24
 .
 
25
 TODO: when doing setuid(0), need to only do that if 0 is one of the
 
26
 ids we map to.  Similarly, when dropping capabilities, need to only
 
27
 not do that if 0 is one of the ids we map to.
 
28
Author: Serge Hallyn <serge.hallyn@ubuntu.com>
 
29
 
 
30
Index: lxc/src/lxc/conf.h
 
31
===================================================================
 
32
--- lxc.orig/src/lxc/conf.h     2012-10-29 13:20:15.000000000 +0000
 
33
+++ lxc/src/lxc/conf.h  2012-10-29 13:49:28.467894919 +0000
 
34
@@ -133,6 +133,26 @@
 
35
        char *value;
 
36
 };
 
37
 
 
38
+enum idtype {
 
39
+       ID_TYPE_UID,
 
40
+       ID_TYPE_GID
 
41
+};
 
42
+
 
43
+/*
 
44
+ * id_map is an id map entry.  Form in confile is:
 
45
+ * lxc.id_map = U 9800 0 100
 
46
+ * lxc.id_map = U 9900 1000 100
 
47
+ * lxc.id_map = G 9800 0 100
 
48
+ * lxc.id_map = G 9900 1000 100
 
49
+ * meaning the container can use uids and gids 0-100 and 1000-1100,
 
50
+ * with uid 0 mapping to uid 9800 on the host, and gid 1000 to
 
51
+ * gid 9900 on the host.
 
52
+ */
 
53
+struct id_map {
 
54
+       enum idtype idtype;
 
55
+       int hostid, nsid, range;
 
56
+};
 
57
+
 
58
 /*
 
59
  * Defines a structure containing a pty information for
 
60
  * virtualizing a tty
 
61
@@ -214,6 +234,7 @@
 
62
        int personality;
 
63
        struct utsname *utsname;
 
64
        struct lxc_list cgroup;
 
65
+       struct lxc_list id_map;
 
66
        struct lxc_list network;
 
67
        struct lxc_list mount_list;
 
68
        struct lxc_list caps;
 
69
@@ -242,6 +263,7 @@
 
70
 extern int lxc_create_network(struct lxc_handler *handler);
 
71
 extern void lxc_delete_network(struct lxc_list *networks);
 
72
 extern int lxc_assign_network(struct lxc_list *networks, pid_t pid);
 
73
+extern int lxc_map_ids(struct lxc_list *idmap, pid_t pid);
 
74
 extern int lxc_find_gateway_addresses(struct lxc_handler *handler);
 
75
 
 
76
 extern int lxc_create_tty(const char *name, struct lxc_conf *conf);
 
77
@@ -254,6 +276,10 @@
 
78
 extern int lxc_clear_mount_entries(struct lxc_conf *c);
 
79
 extern int lxc_clear_hooks(struct lxc_conf *c, char *key);
 
80
 
 
81
+extern int setup_cgroup(const char *name, struct lxc_list *cgroups);
 
82
+
 
83
+extern int uid_shift_file(char *path, struct lxc_conf *c);
 
84
+
 
85
 /*
 
86
  * Configure the container from inside
 
87
  */
 
88
Index: lxc/src/lxc/confile.c
 
89
===================================================================
 
90
--- lxc.orig/src/lxc/confile.c  2012-10-29 13:20:15.000000000 +0000
 
91
+++ lxc/src/lxc/confile.c       2012-10-29 13:21:10.083894919 +0000
 
92
@@ -52,6 +52,7 @@
 
93
 static int config_ttydir(const char *, char *, struct lxc_conf *);
 
94
 static int config_aa_profile(const char *, char *, struct lxc_conf *);
 
95
 static int config_cgroup(const char *, char *, struct lxc_conf *);
 
96
+static int config_idmap(const char *, char *, struct lxc_conf *);
 
97
 static int config_mount(const char *, char *, struct lxc_conf *);
 
98
 static int config_rootfs(const char *, char *, struct lxc_conf *);
 
99
 static int config_rootfs_mount(const char *, char *, struct lxc_conf *);
 
100
@@ -86,8 +87,9 @@
 
101
        { "lxc.pts",                  config_pts                  },
 
102
        { "lxc.tty",                  config_tty                  },
 
103
        { "lxc.devttydir",            config_ttydir               },
 
104
-       { "lxc.aa_profile",            config_aa_profile          },
 
105
+       { "lxc.aa_profile",           config_aa_profile           },
 
106
        { "lxc.cgroup",               config_cgroup               },
 
107
+       { "lxc.id_map",                config_idmap                },
 
108
        { "lxc.mount",                config_mount                },
 
109
        { "lxc.rootfs.mount",         config_rootfs_mount         },
 
110
        { "lxc.rootfs",               config_rootfs               },
 
111
@@ -928,6 +930,65 @@
 
112
        }
 
113
 
 
114
        return -1;
 
115
+}
 
116
+
 
117
+static int config_idmap(const char *key, char *value, struct lxc_conf *lxc_conf)
 
118
+{
 
119
+       char *token = "lxc.id_map";
 
120
+       char *subkey;
 
121
+       struct lxc_list *idmaplist = NULL;
 
122
+       struct id_map *idmap = NULL;
 
123
+       int hostid, nsid, range;
 
124
+       char type;
 
125
+       int ret;
 
126
+
 
127
+       subkey = strstr(key, token);
 
128
+
 
129
+       if (!subkey)
 
130
+               return -1;
 
131
+
 
132
+       if (!strlen(subkey))
 
133
+               return -1;
 
134
+
 
135
+       idmaplist = malloc(sizeof(*idmaplist));
 
136
+       if (!idmaplist)
 
137
+               goto out;
 
138
+
 
139
+       idmap = malloc(sizeof(*idmap));
 
140
+       if (!idmap)
 
141
+               goto out;
 
142
+       memset(idmap, 0, sizeof(*idmap));
 
143
+
 
144
+       idmaplist->elem = idmap;
 
145
+
 
146
+       lxc_list_add_tail(&lxc_conf->id_map, idmaplist);
 
147
+
 
148
+       ret = sscanf(value, "%c %d %d %d", &type, &hostid, &nsid, &range);
 
149
+       INFO("read %d elements", ret);
 
150
+       if (ret != 4)
 
151
+               goto out;
 
152
+       INFO("type %c hostid %d nsid %d range %d", type, hostid, nsid, range);
 
153
+       if (type == 'U')
 
154
+               idmap->idtype = ID_TYPE_UID;
 
155
+       else if (type == 'G')
 
156
+               idmap->idtype = ID_TYPE_GID;
 
157
+       else 
 
158
+               goto out;
 
159
+       idmap->hostid = hostid;
 
160
+       idmap->nsid = nsid;
 
161
+       idmap->range = range;
 
162
+
 
163
+       return 0;
 
164
+
 
165
+out:
 
166
+       if (idmaplist)
 
167
+               free(idmaplist);
 
168
+
 
169
+       if (idmap) {
 
170
+               free(idmap);
 
171
+       }
 
172
+
 
173
+       return -1;
 
174
 }
 
175
 
 
176
 static int config_fstab(const char *key, char *value, struct lxc_conf *lxc_conf)
 
177
Index: lxc/src/lxc/start.c
 
178
===================================================================
 
179
--- lxc.orig/src/lxc/start.c    2012-10-29 13:20:15.000000000 +0000
 
180
+++ lxc/src/lxc/start.c 2012-10-29 13:21:10.087894919 +0000
 
181
@@ -580,6 +580,22 @@
 
182
        if (lxc_sync_barrier_parent(handler, LXC_SYNC_CONFIGURE))
 
183
                return -1;
 
184
 
 
185
+    /*
 
186
+     * if we are in a new user namespace, become root there to have
 
187
+     * privilege over our namespace
 
188
+     */
 
189
+    if (!lxc_list_empty(&handler->conf->id_map)) {
 
190
+        NOTICE("switching to gid/uid 0");
 
191
+        if (setgid(0)) {
 
192
+            SYSERROR("setgid");
 
193
+            exit(1);
 
194
+        }
 
195
+        if (setuid(0)) {
 
196
+            SYSERROR("setuid");
 
197
+            exit(1);
 
198
+        }
 
199
+    }
 
200
+
 
201
        if (handler->conf->need_utmp_watch) {
 
202
                if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0)) {
 
203
                        SYSERROR("failed to remove CAP_SYS_BOOT capability");
 
204
@@ -628,6 +644,10 @@
 
205
                return -1;
 
206
 
 
207
        clone_flags = CLONE_NEWUTS|CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWNS;
 
208
+    if (!lxc_list_empty(&handler->conf->id_map)) {
 
209
+        INFO("Cloning a new user namespace");
 
210
+        clone_flags |= CLONE_NEWUSER;
 
211
+    }
 
212
        if (!lxc_list_empty(&handler->conf->network)) {
 
213
 
 
214
                clone_flags |= CLONE_NEWNET;
 
215
@@ -678,6 +698,11 @@
 
216
        if (lxc_cgroup_create(name, handler->pid))
 
217
                goto out_delete_net;
 
218
 
 
219
+       if (setup_cgroup(name, &handler->conf->cgroup)) {
 
220
+               ERROR("failed to setup the cgroups for '%s'", name);
 
221
+               goto out_delete_net;
 
222
+       }
 
223
+
 
224
        if (failed_before_rename)
 
225
                goto out_delete_net;
 
226
 
 
227
@@ -689,6 +714,11 @@
 
228
                }
 
229
        }
 
230
 
 
231
+       if (lxc_map_ids(&handler->conf->id_map, handler->pid)) {
 
232
+               ERROR("failed to set up id mapping");
 
233
+               goto out_delete_net;
 
234
+       }
 
235
+
 
236
        /* Tell the child to continue its initialization and wait for
 
237
         * it to exec or return an error
 
238
         */
 
239
Index: lxc/src/lxc/conf.c
 
240
===================================================================
 
241
--- lxc.orig/src/lxc/conf.c     2012-10-29 13:20:15.000000000 +0000
 
242
+++ lxc/src/lxc/conf.c  2012-10-29 14:35:32.124880664 +0000
 
243
@@ -1079,7 +1079,7 @@
 
244
        return 0;
 
245
 }
 
246
 
 
247
-static int setup_cgroup(const char *name, struct lxc_list *cgroups)
 
248
+int setup_cgroup(const char *name, struct lxc_list *cgroups)
 
249
 {
 
250
        struct lxc_list *iterator;
 
251
        struct lxc_cgroup *cg;
 
252
@@ -1738,6 +1738,7 @@
 
253
        lxc_list_init(&new->network);
 
254
        lxc_list_init(&new->mount_list);
 
255
        lxc_list_init(&new->caps);
 
256
+       lxc_list_init(&new->id_map);
 
257
        new->aa_profile = NULL;
 
258
        for (i=0; i<NUM_LXC_HOOKS; i++)
 
259
                lxc_list_init(&new->hooks[i]);
 
260
@@ -2037,6 +2038,44 @@
 
261
        return 0;
 
262
 }
 
263
 
 
264
+int add_id_mapping(enum idtype idtype, pid_t pid, uid_t host_start, uid_t ns_start, int range)
 
265
+{
 
266
+        char path[PATH_MAX];
 
267
+        int ret;
 
268
+        FILE *f;
 
269
+
 
270
+        ret = snprintf(path, PATH_MAX, "/proc/%d/%cid_map", pid, idtype == ID_TYPE_UID ? 'u' : 'g');
 
271
+        if (ret < 0 || ret >= PATH_MAX) {
 
272
+                fprintf(stderr, "%s: path name too long", __func__);
 
273
+                return -E2BIG;
 
274
+        }
 
275
+        f = fopen(path, "w");
 
276
+        if (!f) {
 
277
+                perror("open");
 
278
+                return -EINVAL;
 
279
+        }
 
280
+        ret = fprintf(f, "%d %d %d", ns_start, host_start, range);
 
281
+        if (ret < 0)
 
282
+                perror("write");
 
283
+        fclose(f);
 
284
+        return ret < 0 ? ret : 0;
 
285
+}
 
286
+
 
287
+int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
 
288
+{
 
289
+       struct lxc_list *iterator;
 
290
+       struct id_map *map;
 
291
+       int ret;
 
292
+
 
293
+       lxc_list_for_each(iterator, idmap) {
 
294
+               map = iterator->elem;
 
295
+               ret = add_id_mapping(map->idtype, pid, map->hostid, map->nsid, map->range);
 
296
+               if (ret)
 
297
+                       break;
 
298
+       }
 
299
+       return ret;
 
300
+}
 
301
+
 
302
 int lxc_find_gateway_addresses(struct lxc_handler *handler)
 
303
 {
 
304
        struct lxc_list *network = &handler->conf->network;
 
305
@@ -2218,10 +2257,6 @@
 
306
                return -1;
 
307
        }
 
308
 
 
309
-       if (setup_cgroup(name, &lxc_conf->cgroup)) {
 
310
-               ERROR("failed to setup the cgroups for '%s'", name);
 
311
-               return -1;
 
312
-       }
 
313
        if (run_lxc_hooks(name, "mount", lxc_conf)) {
 
314
                ERROR("failed to run mount hooks for container '%s'.", name);
 
315
                return -1;
 
316
@@ -2274,9 +2309,11 @@
 
317
                return -1;
 
318
        }
 
319
 
 
320
-       if (setup_caps(&lxc_conf->caps)) {
 
321
-               ERROR("failed to drop capabilities");
 
322
-               return -1;
 
323
+       if (lxc_list_empty(&lxc_conf->id_map)) {
 
324
+               if (setup_caps(&lxc_conf->caps)) {
 
325
+                       ERROR("failed to drop capabilities");
 
326
+                       return -1;
 
327
+               }
 
328
        }
 
329
 
 
330
        NOTICE("'%s' is setup.", name);
 
331
@@ -2533,3 +2570,54 @@
 
332
        lxc_clear_mount_entries(conf);
 
333
        free(conf);
 
334
 }
 
335
+
 
336
+/*
 
337
+ * given a host uid, return the ns uid if it is mapped.
 
338
+ * if it is not mapped, return the original host id.
 
339
+ */
 
340
+static int shiftid(struct lxc_conf *c, int uid, enum idtype w)
 
341
+{
 
342
+       struct lxc_list *iterator;
 
343
+       struct id_map *map;
 
344
+       int low, high;
 
345
+
 
346
+       lxc_list_for_each(iterator, &c->id_map) {
 
347
+               map = iterator->elem;
 
348
+               if (map->idtype != w)
 
349
+                       continue;
 
350
+
 
351
+               low = map->hostid;
 
352
+               high = map->hostid + map->range;
 
353
+               if (uid < low || uid >= high)
 
354
+                       continue;
 
355
+
 
356
+               return uid - low + map->nsid;
 
357
+       }
 
358
+
 
359
+       return uid;
 
360
+}
 
361
+
 
362
+/*
 
363
+ * Take a pathname for a file created on the host, and map the uid and gid
 
364
+ * into the container if needed.  (Used for ttys)
 
365
+ */
 
366
+int uid_shift_file(char *path, struct lxc_conf *c)
 
367
+{
 
368
+       struct stat statbuf;
 
369
+       int newuid, newgid;
 
370
+
 
371
+       if (stat(path, &statbuf)) {
 
372
+               SYSERROR("stat(%s)", path);
 
373
+               return -1;
 
374
+       }
 
375
+
 
376
+       newuid = shiftid(c, statbuf.st_uid, ID_TYPE_UID);
 
377
+       newgid = shiftid(c, statbuf.st_gid, ID_TYPE_GID);
 
378
+       if (newuid != statbuf.st_uid || newgid != statbuf.st_gid) {
 
379
+               if (chown(path, newuid, newgid)) {
 
380
+                       SYSERROR("chown(%s)", path);
 
381
+                       return -1;
 
382
+               }
 
383
+       }
 
384
+       return 0;
 
385
+}
 
386
Index: lxc/src/lxc/console.c
 
387
===================================================================
 
388
--- lxc.orig/src/lxc/console.c  2012-10-29 13:20:15.967318000 +0000
 
389
+++ lxc/src/lxc/console.c       2012-10-29 13:54:52.055894919 +0000
 
390
@@ -195,6 +195,9 @@
 
391
                goto err;
 
392
        }
 
393
 
 
394
+       if (uid_shift_file(console->path, conf))
 
395
+               goto err;
 
396
+
 
397
        fd = lxc_unpriv(open(console->path, O_CLOEXEC | O_RDWR | O_CREAT |
 
398
                             O_APPEND, 0600));
 
399
        if (fd < 0) {