]> git.proxmox.com Git - lxc.git/blob - debian/patches/0004-separate-the-limiting-from-the-namespaced-cgroup-roo.patch
bump version to 3.0.0-3
[lxc.git] / debian / patches / 0004-separate-the-limiting-from-the-namespaced-cgroup-roo.patch
1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
3 Date: Wed, 28 Mar 2018 13:37:28 +0200
4 Subject: [PATCH] separate the limiting from the namespaced cgroup root
5
6 When cgroup namespaces are enabled a privileged container
7 with mixed cgroups has full write access to its own root
8 cgroup effectively allowing it to overwrite values written
9 from the outside or configured via lxc.cgroup.*.
10
11 This patch causes an additional 'ns/' directory to be
12 created in all cgroups if cgroup namespaces and cgfsng are
13 being used in order to combat this.
14
15 Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
16 ---
17 src/lxc/cgroups/cgfsng.c | 88 +++++++++++++++++++++++++++++++++++++++---------
18 src/lxc/cgroups/cgroup.c | 17 +++++-----
19 src/lxc/cgroups/cgroup.h | 23 ++++++++-----
20 src/lxc/commands.c | 85 +++++++++++++++++++++++++++++++++++-----------
21 src/lxc/commands.h | 2 ++
22 src/lxc/criu.c | 4 +--
23 src/lxc/start.c | 28 +++++++++++----
24 7 files changed, 186 insertions(+), 61 deletions(-)
25
26 diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
27 index 10c7ab2c..b48f997f 100644
28 --- a/src/lxc/cgroups/cgfsng.c
29 +++ b/src/lxc/cgroups/cgfsng.c
30 @@ -101,6 +101,7 @@ struct hierarchy {
31 char *mountpoint;
32 char *base_cgroup;
33 char *fullcgpath;
34 + char *innercgpath;
35 int version;
36 };
37
38 @@ -955,6 +956,7 @@ static struct hierarchy *add_hierarchy(char **clist, char *mountpoint,
39 new->mountpoint = mountpoint;
40 new->base_cgroup = base_cgroup;
41 new->fullcgpath = NULL;
42 + new->innercgpath = NULL;
43 new->version = type;
44
45 newentry = append_null_to_list((void ***)&hierarchies);
46 @@ -1587,6 +1589,8 @@ static int cgroup_rmdir(char *container_cgroup)
47
48 free(h->fullcgpath);
49 h->fullcgpath = NULL;
50 + free(h->innercgpath);
51 + h->innercgpath = NULL;
52 }
53
54 return 0;
55 @@ -1597,6 +1601,7 @@ struct generic_userns_exec_data {
56 struct lxc_conf *conf;
57 uid_t origuid; /* target uid in parent namespace */
58 char *path;
59 + bool inner;
60 };
61
62 static int cgroup_rmdir_wrapper(void *data)
63 @@ -1641,6 +1646,7 @@ static void cgfsng_destroy(void *hdata, struct lxc_conf *conf)
64 wrap.origuid = 0;
65 wrap.d = hdata;
66 wrap.conf = conf;
67 + wrap.inner = false;
68
69 if (conf && !lxc_list_empty(&conf->id_map))
70 ret = userns_exec_1(conf, cgroup_rmdir_wrapper, &wrap,
71 @@ -1730,22 +1736,29 @@ on_error:
72 return bret;
73 }
74
75 -static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname)
76 +static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname, bool inner)
77 {
78 int ret;
79
80 - h->fullcgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
81 - if (dir_exists(h->fullcgpath)) {
82 - ERROR("The cgroup \"%s\" already existed", h->fullcgpath);
83 + char *path;
84 + if (inner) {
85 + path = must_make_path(h->fullcgpath, CGROUP_NAMESPACE_SUBDIR, NULL);
86 + h->innercgpath = path;
87 + } else {
88 + path = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
89 + h->fullcgpath = path;
90 + }
91 + if (dir_exists(path)) { // it must not already exist
92 + ERROR("Path \"%s\" already existed.", path);
93 return false;
94 }
95
96 - if (!cg_legacy_handle_cpuset_hierarchy(h, cgname)) {
97 + if (!inner && !cg_legacy_handle_cpuset_hierarchy(h, cgname)) {
98 ERROR("Failed to handle legacy cpuset controller");
99 return false;
100 }
101
102 - ret = mkdir_p(h->fullcgpath, 0755);
103 + ret = mkdir_p(path, 0755);
104 if (ret < 0) {
105 ERROR("Failed to create cgroup \"%s\"", h->fullcgpath);
106 return false;
107 @@ -1766,10 +1779,26 @@ static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)
108 h->fullcgpath = NULL;
109 }
110
111 +static inline bool cgfsng_create_inner(struct cgfsng_handler_data *d)
112 +{
113 + size_t i;
114 + bool ret = true;
115 + char *cgname = must_make_path(d->container_cgroup, CGROUP_NAMESPACE_SUBDIR, NULL);
116 + for (i = 0; hierarchies[i]; i++) {
117 + if (!create_path_for_hierarchy(hierarchies[i], cgname, true)) {
118 + SYSERROR("Failed to create %s namespace subdirectory: %s", hierarchies[i]->fullcgpath, strerror(errno));
119 + ret = false;
120 + break;
121 + }
122 + }
123 + free(cgname);
124 + return ret;
125 +}
126 +
127 /* Try to create the same cgroup in all hierarchies. Start with cgroup_pattern;
128 * next cgroup_pattern-1, -2, ..., -999.
129 */
130 -static inline bool cgfsng_create(void *hdata)
131 +static inline bool cgfsng_create(void *hdata, bool inner)
132 {
133 int i;
134 size_t len;
135 @@ -1781,10 +1810,17 @@ static inline bool cgfsng_create(void *hdata)
136 return false;
137
138 if (d->container_cgroup) {
139 + if (inner)
140 + return cgfsng_create_inner(d);
141 WARN("cgfsng_create called a second time");
142 return false;
143 }
144
145 + if (inner) {
146 + ERROR("cgfsng_create called twice for innner cgroup");
147 + return false;
148 + }
149 +
150 if (d->cgroup_meta.dir)
151 tmp = lxc_string_join("/", (const char *[]){d->cgroup_meta.dir, d->name, NULL}, false);
152 else
153 @@ -1821,7 +1857,7 @@ again:
154 }
155
156 for (i = 0; hierarchies[i]; i++) {
157 - if (!create_path_for_hierarchy(hierarchies[i], container_cgroup)) {
158 + if (!create_path_for_hierarchy(hierarchies[i], container_cgroup, false)) {
159 int j;
160 ERROR("Failed to create cgroup \"%s\"", hierarchies[i]->fullcgpath);
161 free(hierarchies[i]->fullcgpath);
162 @@ -1843,7 +1879,7 @@ out_free:
163 return false;
164 }
165
166 -static bool cgfsng_enter(void *hdata, pid_t pid)
167 +static bool cgfsng_enter(void *hdata, pid_t pid, bool inner)
168 {
169 int i, len;
170 char pidstr[25];
171 @@ -1856,8 +1892,13 @@ static bool cgfsng_enter(void *hdata, pid_t pid)
172 int ret;
173 char *fullpath;
174
175 - fullpath = must_make_path(hierarchies[i]->fullcgpath,
176 - "cgroup.procs", NULL);
177 + if (inner)
178 + fullpath = must_make_path(hierarchies[i]->fullcgpath,
179 + CGROUP_NAMESPACE_SUBDIR,
180 + "cgroup.procs", NULL);
181 + else
182 + fullpath = must_make_path(hierarchies[i]->fullcgpath,
183 + "cgroup.procs", NULL);
184 ret = lxc_write_to_file(fullpath, pidstr, len, false);
185 if (ret != 0) {
186 SYSERROR("Failed to enter cgroup \"%s\"", fullpath);
187 @@ -1933,9 +1974,15 @@ static int chown_cgroup_wrapper(void *data)
188 char *fullpath;
189 char *path = hierarchies[i]->fullcgpath;
190
191 + if (arg->inner)
192 + path = must_make_path(path, CGROUP_NAMESPACE_SUBDIR, NULL);
193 +
194 ret = chowmod(path, destuid, nsgid, 0775);
195 - if (ret < 0)
196 + if (ret < 0) {
197 + if (arg->inner)
198 + free(path);
199 return -1;
200 + }
201
202 /* Failures to chown() these are inconvenient but not
203 * detrimental We leave these owned by the container launcher,
204 @@ -1954,8 +2001,11 @@ static int chown_cgroup_wrapper(void *data)
205 (void)chowmod(fullpath, destuid, 0, 0664);
206 free(fullpath);
207
208 - if (hierarchies[i]->version != CGROUP2_SUPER_MAGIC)
209 + if (hierarchies[i]->version != CGROUP2_SUPER_MAGIC) {
210 + if (arg->inner)
211 + free(path);
212 continue;
213 + }
214
215 fullpath = must_make_path(path, "cgroup.subtree_control", NULL);
216 (void)chowmod(fullpath, destuid, nsgid, 0664);
217 @@ -1964,12 +2014,14 @@ static int chown_cgroup_wrapper(void *data)
218 fullpath = must_make_path(path, "cgroup.threads", NULL);
219 (void)chowmod(fullpath, destuid, nsgid, 0664);
220 free(fullpath);
221 + if (arg->inner)
222 + free(path);
223 }
224
225 return 0;
226 }
227
228 -static bool cgfsng_chown(void *hdata, struct lxc_conf *conf)
229 +static bool cgfsng_chown(void *hdata, struct lxc_conf *conf, bool inner)
230 {
231 struct cgfsng_handler_data *d = hdata;
232 struct generic_userns_exec_data wrap;
233 @@ -1984,6 +2036,7 @@ static bool cgfsng_chown(void *hdata, struct lxc_conf *conf)
234 wrap.path = NULL;
235 wrap.d = d;
236 wrap.conf = conf;
237 + wrap.inner = inner;
238
239 if (userns_exec_1(conf, chown_cgroup_wrapper, &wrap,
240 "chown_cgroup_wrapper") < 0) {
241 @@ -2366,7 +2419,7 @@ static bool cgfsng_unfreeze(void *hdata)
242 return true;
243 }
244
245 -static const char *cgfsng_get_cgroup(void *hdata, const char *controller)
246 +static const char *cgfsng_get_cgroup(void *hdata, const char *controller, bool inner)
247 {
248 struct hierarchy *h;
249
250 @@ -2377,6 +2430,9 @@ static const char *cgfsng_get_cgroup(void *hdata, const char *controller)
251 return NULL;
252 }
253
254 + if (inner && h->innercgpath)
255 + return h->innercgpath + strlen(h->mountpoint);
256 +
257 return h->fullcgpath ? h->fullcgpath + strlen(h->mountpoint) : NULL;
258 }
259
260 @@ -2408,7 +2464,7 @@ static int __cg_unified_attach(const struct hierarchy *h, const char *name,
261 int fret = -1, idx = 0;
262 char *base_path = NULL, *container_cgroup = NULL, *full_path = NULL;
263
264 - container_cgroup = lxc_cmd_get_cgroup_path(name, lxcpath, controller);
265 + container_cgroup = lxc_cmd_get_attach_cgroup_path(name, lxcpath, controller);
266 /* not running */
267 if (!container_cgroup)
268 return 0;
269 diff --git a/src/lxc/cgroups/cgroup.c b/src/lxc/cgroups/cgroup.c
270 index 9e7b26e0..ec45dd39 100644
271 --- a/src/lxc/cgroups/cgroup.c
272 +++ b/src/lxc/cgroups/cgroup.c
273 @@ -73,19 +73,19 @@ void cgroup_destroy(struct lxc_handler *handler)
274 }
275
276 /* Create the container cgroups for all requested controllers. */
277 -bool cgroup_create(struct lxc_handler *handler)
278 +bool cgroup_create(struct lxc_handler *handler, bool inner)
279 {
280 if (ops)
281 - return ops->create(handler->cgroup_data);
282 + return ops->create(handler->cgroup_data, inner);
283
284 return false;
285 }
286
287 /* Enter the container init into its new cgroups for all requested controllers. */
288 -bool cgroup_enter(struct lxc_handler *handler)
289 +bool cgroup_enter(struct lxc_handler *handler, bool inner)
290 {
291 if (ops)
292 - return ops->enter(handler->cgroup_data, handler->pid);
293 + return ops->enter(handler->cgroup_data, handler->pid, inner);
294
295 return false;
296 }
297 @@ -99,10 +99,11 @@ bool cgroup_create_legacy(struct lxc_handler *handler)
298 }
299
300 const char *cgroup_get_cgroup(struct lxc_handler *handler,
301 - const char *subsystem)
302 + const char *subsystem,
303 + bool inner)
304 {
305 if (ops)
306 - return ops->get_cgroup(handler->cgroup_data, subsystem);
307 + return ops->get_cgroup(handler->cgroup_data, subsystem, inner);
308
309 return NULL;
310 }
311 @@ -148,10 +149,10 @@ bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices)
312 return false;
313 }
314
315 -bool cgroup_chown(struct lxc_handler *handler)
316 +bool cgroup_chown(struct lxc_handler *handler, bool inner)
317 {
318 if (ops && ops->chown)
319 - return ops->chown(handler->cgroup_data, handler->conf);
320 + return ops->chown(handler->cgroup_data, handler->conf, inner);
321
322 return true;
323 }
324 diff --git a/src/lxc/cgroups/cgroup.h b/src/lxc/cgroups/cgroup.h
325 index 0f04e8b7..3a63133d 100644
326 --- a/src/lxc/cgroups/cgroup.h
327 +++ b/src/lxc/cgroups/cgroup.h
328 @@ -28,6 +28,12 @@
329 #include <stddef.h>
330 #include <sys/types.h>
331
332 +/* When lxc.cgroup.protect_limits is in effect the container's cgroup namespace
333 + * will be moved into an additional subdirectory "cgns/" inside the cgroup in
334 + * order to prevent it from accessing the outer limiting cgroup.
335 + */
336 +#define CGROUP_NAMESPACE_SUBDIR "cgns"
337 +
338 struct lxc_handler;
339 struct lxc_conf;
340 struct lxc_list;
341 @@ -45,10 +51,10 @@ struct cgroup_ops {
342
343 void *(*init)(struct lxc_handler *handler);
344 void (*destroy)(void *hdata, struct lxc_conf *conf);
345 - bool (*create)(void *hdata);
346 - bool (*enter)(void *hdata, pid_t pid);
347 + bool (*create)(void *hdata, bool inner);
348 + bool (*enter)(void *hdata, pid_t pid, bool inner);
349 bool (*create_legacy)(void *hdata, pid_t pid);
350 - const char *(*get_cgroup)(void *hdata, const char *subsystem);
351 + const char *(*get_cgroup)(void *hdata, const char *subsystem, bool inner);
352 bool (*escape)();
353 int (*num_hierarchies)();
354 bool (*get_hierarchies)(int n, char ***out);
355 @@ -56,7 +62,7 @@ struct cgroup_ops {
356 int (*get)(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
357 bool (*unfreeze)(void *hdata);
358 bool (*setup_limits)(void *hdata, struct lxc_conf *conf, bool with_devices);
359 - bool (*chown)(void *hdata, struct lxc_conf *conf);
360 + bool (*chown)(void *hdata, struct lxc_conf *conf, bool inner);
361 bool (*attach)(const char *name, const char *lxcpath, pid_t pid);
362 bool (*mount_cgroup)(void *hdata, const char *root, int type);
363 int (*nrtasks)(void *hdata);
364 @@ -67,15 +73,16 @@ extern bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid);
365 extern bool cgroup_mount(const char *root, struct lxc_handler *handler, int type);
366 extern void cgroup_destroy(struct lxc_handler *handler);
367 extern bool cgroup_init(struct lxc_handler *handler);
368 -extern bool cgroup_create(struct lxc_handler *handler);
369 +extern bool cgroup_create(struct lxc_handler *handler, bool inner);
370 extern bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices);
371 -extern bool cgroup_chown(struct lxc_handler *handler);
372 -extern bool cgroup_enter(struct lxc_handler *handler);
373 +extern bool cgroup_chown(struct lxc_handler *handler, bool inner);
374 +extern bool cgroup_enter(struct lxc_handler *handler, bool inner);
375 extern void cgroup_cleanup(struct lxc_handler *handler);
376 extern bool cgroup_create_legacy(struct lxc_handler *handler);
377 extern int cgroup_nrtasks(struct lxc_handler *handler);
378 extern const char *cgroup_get_cgroup(struct lxc_handler *handler,
379 - const char *subsystem);
380 + const char *subsystem,
381 + bool inner);
382 extern bool cgroup_escape();
383 extern int cgroup_num_hierarchies();
384 extern bool cgroup_get_hierarchies(int i, char ***out);
385 diff --git a/src/lxc/commands.c b/src/lxc/commands.c
386 index 54e9f75c..df5a9907 100644
387 --- a/src/lxc/commands.c
388 +++ b/src/lxc/commands.c
389 @@ -426,20 +426,8 @@ static int lxc_cmd_get_clone_flags_callback(int fd, struct lxc_cmd_req *req,
390 return lxc_cmd_rsp_send(fd, &rsp);
391 }
392
393 -/*
394 - * lxc_cmd_get_cgroup_path: Calculate a container's cgroup path for a
395 - * particular subsystem. This is the cgroup path relative to the root
396 - * of the cgroup filesystem.
397 - *
398 - * @name : name of container to connect to
399 - * @lxcpath : the lxcpath in which the container is running
400 - * @subsystem : the subsystem being asked about
401 - *
402 - * Returns the path on success, NULL on failure. The caller must free() the
403 - * returned path.
404 - */
405 -char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
406 - const char *subsystem)
407 +char *do_lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
408 + const char *subsystem, bool inner)
409 {
410 int ret, stopped;
411 struct lxc_cmd_rr cmd = {
412 @@ -452,8 +440,18 @@ char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
413
414 cmd.req.data = subsystem;
415 cmd.req.datalen = 0;
416 - if (subsystem)
417 - cmd.req.datalen = strlen(subsystem) + 1;
418 + if (subsystem) {
419 + size_t subsyslen = strlen(subsystem);
420 + if (inner) {
421 + char *data = alloca(subsyslen+2);
422 + memcpy(data, subsystem, subsyslen+1);
423 + data[subsyslen+1] = 1;
424 + cmd.req.datalen = subsyslen+2,
425 + cmd.req.data = data;
426 + } else {
427 + cmd.req.datalen = subsyslen+1;
428 + }
429 + }
430
431 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
432 if (ret < 0)
433 @@ -468,16 +466,63 @@ char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
434 return cmd.rsp.data;
435 }
436
437 +/*
438 + * lxc_cmd_get_cgroup_path: Calculate a container's cgroup path for a
439 + * particular subsystem. This is the cgroup path relative to the root
440 + * of the cgroup filesystem.
441 + *
442 + * @name : name of container to connect to
443 + * @lxcpath : the lxcpath in which the container is running
444 + * @subsystem : the subsystem being asked about
445 + *
446 + * Returns the path on success, NULL on failure. The caller must free() the
447 + * returned path.
448 + */
449 +char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
450 + const char *subsystem)
451 +{
452 + return do_lxc_cmd_get_cgroup_path(name, lxcpath, subsystem, false);
453 +}
454 +
455 +/*
456 + * lxc_cmd_get_attach_cgroup_path: Calculate a container's inner cgroup path
457 + * for a particular subsystem. This is the cgroup path relative to the root
458 + * of the cgroup filesystem.
459 + *
460 + * @name : name of container to connect to
461 + * @lxcpath : the lxcpath in which the container is running
462 + * @subsystem : the subsystem being asked about
463 + *
464 + * Returns the path on success, NULL on failure. The caller must free() the
465 + * returned path.
466 + */
467 +char *lxc_cmd_get_attach_cgroup_path(const char *name, const char *lxcpath,
468 + const char *subsystem)
469 +{
470 + return do_lxc_cmd_get_cgroup_path(name, lxcpath, subsystem, true);
471 +}
472 +
473 static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
474 struct lxc_handler *handler)
475 {
476 const char *path;
477 struct lxc_cmd_rsp rsp;
478
479 - if (req->datalen > 0)
480 - path = cgroup_get_cgroup(handler, req->data);
481 - else
482 - path = cgroup_get_cgroup(handler, NULL);
483 + if (req->datalen > 0) {
484 + const char *subsystem;
485 + size_t subsyslen;
486 + bool inner = false;
487 + subsystem = req->data;
488 + subsyslen = strlen(subsystem);
489 + if (req->datalen == subsyslen+2)
490 + inner = (subsystem[subsyslen+1] == 1);
491 +
492 + path = cgroup_get_cgroup(handler, req->data, inner);
493 + } else {
494 + // FIXME: cgroup separation for cgroup v2 cannot be handled
495 + // like we used to do v1 here... need to figure this out...
496 + path = cgroup_get_cgroup(handler, NULL, false);
497 + }
498 if (!path)
499 return -1;
500
501 diff --git a/src/lxc/commands.h b/src/lxc/commands.h
502 index 816cd748..e16c0d79 100644
503 --- a/src/lxc/commands.h
504 +++ b/src/lxc/commands.h
505 @@ -93,6 +93,8 @@ extern int lxc_cmd_console(const char *name, int *ttynum, int *fd,
506 */
507 extern char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
508 const char *subsystem);
509 +extern char *lxc_cmd_get_attach_cgroup_path(const char *name,
510 + const char *lxcpath, const char *subsystem);
511 extern int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath);
512 extern char *lxc_cmd_get_config_item(const char *name, const char *item, const char *lxcpath);
513 extern char *lxc_cmd_get_name(const char *hashed_sock);
514 diff --git a/src/lxc/criu.c b/src/lxc/criu.c
515 index f60a6e15..7c8a8aee 100644
516 --- a/src/lxc/criu.c
517 +++ b/src/lxc/criu.c
518 @@ -324,7 +324,7 @@ static void exec_criu(struct criu_opts *opts)
519 } else {
520 const char *p;
521
522 - p = cgroup_get_cgroup(opts->handler, controllers[0]);
523 + p = cgroup_get_cgroup(opts->handler, controllers[0], false);
524 if (!p) {
525 ERROR("failed to get cgroup path for %s", controllers[0]);
526 goto err;
527 @@ -958,7 +958,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
528 goto out_fini_handler;
529 }
530
531 - if (!cgroup_create(handler)) {
532 + if (!cgroup_create(handler, false)) {
533 ERROR("failed creating groups");
534 goto out_fini_handler;
535 }
536 diff --git a/src/lxc/start.c b/src/lxc/start.c
537 index f66f50a7..772eacc2 100644
538 --- a/src/lxc/start.c
539 +++ b/src/lxc/start.c
540 @@ -1556,7 +1556,7 @@ static int lxc_spawn(struct lxc_handler *handler)
541
542 cgroups_connected = true;
543
544 - if (!cgroup_create(handler)) {
545 + if (!cgroup_create(handler, false)) {
546 ERROR("Failed creating cgroups");
547 goto out_delete_net;
548 }
549 @@ -1650,10 +1650,10 @@ static int lxc_spawn(struct lxc_handler *handler)
550 goto out_delete_net;
551 }
552
553 - if (!cgroup_enter(handler))
554 + if (!cgroup_enter(handler, false))
555 goto out_delete_net;
556
557 - if (!cgroup_chown(handler))
558 + if (!cgroup_chown(handler, false))
559 goto out_delete_net;
560
561 /* Now we're ready to preserve the network namespace */
562 @@ -1714,16 +1714,30 @@ static int lxc_spawn(struct lxc_handler *handler)
563 }
564 }
565
566 - ret = lxc_sync_barrier_child(handler, LXC_SYNC_CGROUP_UNSHARE);
567 - if (ret < 0)
568 - goto out_delete_net;
569 -
570 if (!cgroup_setup_limits(handler, true)) {
571 ERROR("Failed to setup legacy device cgroup controller limits");
572 goto out_delete_net;
573 }
574 TRACE("Set up legacy device cgroup controller limits");
575
576 + if (cgns_supported()) {
577 + if (!cgroup_create(handler, true)) {
578 + ERROR("failed to create inner cgroup separation layer");
579 + goto out_delete_net;
580 + }
581 + if (!cgroup_enter(handler, true)) {
582 + ERROR("failed to enter inner cgroup separation layer");
583 + goto out_delete_net;
584 + }
585 + if (!cgroup_chown(handler, true)) {
586 + ERROR("failed chown inner cgroup separation layer");
587 + goto out_delete_net;
588 + }
589 + }
590 +
591 + if (lxc_sync_barrier_child(handler, LXC_SYNC_CGROUP_UNSHARE))
592 + goto out_delete_net;
593 +
594 cgroup_disconnect();
595 cgroups_connected = false;
596
597 --
598 2.11.0
599