]> git.proxmox.com Git - lxc.git/blame - debian/patches/0004-separate-the-limiting-from-the-namespaced-cgroup-roo.patch
merge lxc-console improvements from stable branch
[lxc.git] / debian / patches / 0004-separate-the-limiting-from-the-namespaced-cgroup-roo.patch
CommitLineData
bc7e56ac 1From 6ebdc24c00b4dee75aebef3136469a5297e1d9ee Mon Sep 17 00:00:00 2001
308c8a3e
WB
2From: Wolfgang Bumiller <w.bumiller@proxmox.com>
3Date: Tue, 15 Nov 2016 09:20:24 +0100
c44ec9ce 4Subject: [PATCH 04/13] separate the limiting from the namespaced cgroup root
308c8a3e
WB
5
6When cgroup namespaces are enabled a privileged container
7with mixed cgroups has full write access to its own root
8cgroup effectively allowing it to overwrite values written
9from the outside or configured via lxc.cgroup.*.
10
11This patch causes an additional 'ns/' directory to be
12created in all cgroups if cgroup namespaces and cgfsng are
13being used in order to combat this.
14
15Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
16---
f39a178a
WB
17 src/lxc/cgroups/cgfs.c | 19 ++++++++---
18 src/lxc/cgroups/cgfsng.c | 79 +++++++++++++++++++++++++++++++++++++--------
19 src/lxc/cgroups/cgmanager.c | 19 ++++++++---
20 src/lxc/cgroups/cgroup.c | 17 +++++-----
21 src/lxc/cgroups/cgroup.h | 22 ++++++++-----
22 src/lxc/commands.c | 76 ++++++++++++++++++++++++++++++++++---------
23 src/lxc/commands.h | 2 ++
24 src/lxc/criu.c | 4 +--
bc7e56ac
WB
25 src/lxc/start.c | 27 ++++++++++++----
26 9 files changed, 204 insertions(+), 61 deletions(-)
308c8a3e
WB
27
28diff --git a/src/lxc/cgroups/cgfs.c b/src/lxc/cgroups/cgfs.c
f39a178a 29index bcbd6613..573ccb25 100644
308c8a3e
WB
30--- a/src/lxc/cgroups/cgfs.c
31+++ b/src/lxc/cgroups/cgfs.c
f39a178a 32@@ -2387,12 +2387,15 @@ static void cgfs_destroy(void *hdata, struct lxc_conf *conf)
308c8a3e
WB
33 free(d);
34 }
35
36-static inline bool cgfs_create(void *hdata)
37+static inline bool cgfs_create(void *hdata, bool inner)
38 {
39 struct cgfs_data *d = hdata;
40 struct cgroup_process_info *i;
41 struct cgroup_meta_data *md;
42
43+ if (inner)
44+ return true;
45+
46 if (!d)
47 return false;
48 md = d->meta;
f39a178a 49@@ -2403,12 +2406,15 @@ static inline bool cgfs_create(void *hdata)
308c8a3e
WB
50 return true;
51 }
52
53-static inline bool cgfs_enter(void *hdata, pid_t pid)
54+static inline bool cgfs_enter(void *hdata, pid_t pid, bool inner)
55 {
56 struct cgfs_data *d = hdata;
57 struct cgroup_process_info *i;
58 int ret;
59
60+ if (inner)
61+ return true;
62+
63 if (!d)
64 return false;
65 i = d->info;
f39a178a 66@@ -2432,10 +2438,12 @@ static inline bool cgfs_create_legacy(void *hdata, pid_t pid)
07288e64
WB
67 return true;
68 }
69
70-static const char *cgfs_get_cgroup(void *hdata, const char *subsystem)
71+static const char *cgfs_get_cgroup(void *hdata, const char *subsystem, bool inner)
72 {
73 struct cgfs_data *d = hdata;
74
75+ (void)inner;
76+
77 if (!d)
78 return NULL;
79 return lxc_cgroup_get_hierarchy_path_data(subsystem, d);
f39a178a 80@@ -2651,13 +2659,16 @@ static bool do_cgfs_chown(char *cgroup_path, struct lxc_conf *conf)
308c8a3e
WB
81 return true;
82 }
83
84-static bool cgfs_chown(void *hdata, struct lxc_conf *conf)
85+static bool cgfs_chown(void *hdata, struct lxc_conf *conf, bool inner)
86 {
87 struct cgfs_data *d = hdata;
88 struct cgroup_process_info *info_ptr;
89 char *cgpath;
90 bool r = true;
91
92+ if (inner)
93+ return true;
94+
95 if (!d)
96 return false;
97
98diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
bc7e56ac 99index 897336f0..81c589e0 100644
308c8a3e
WB
100--- a/src/lxc/cgroups/cgfsng.c
101+++ b/src/lxc/cgroups/cgfsng.c
f39a178a 102@@ -77,6 +77,7 @@ struct hierarchy {
07288e64
WB
103 char *mountpoint;
104 char *base_cgroup;
105 char *fullcgpath;
106+ char *innercgpath;
f39a178a 107 bool is_cgroup_v2;
07288e64
WB
108 };
109
f39a178a 110@@ -813,6 +814,7 @@ static void add_controller(char **clist, char *mountpoint, char *base_cgroup)
07288e64
WB
111 new->mountpoint = mountpoint;
112 new->base_cgroup = base_cgroup;
113 new->fullcgpath = NULL;
f39a178a 114+ new->innercgpath = NULL;
07288e64 115
f39a178a
WB
116 /* record if this is the cgroup v2 hierarchy */
117 if (!strcmp(base_cgroup, "cgroup2"))
bc7e56ac 118@@ -1302,6 +1304,8 @@ static void cgfsng_destroy(void *hdata, struct lxc_conf *conf)
07288e64
WB
119 free(h->fullcgpath);
120 h->fullcgpath = NULL;
121 }
122+ free(h->innercgpath);
123+ h->innercgpath = NULL;
124 }
125 }
126
bc7e56ac 127@@ -1319,18 +1323,25 @@ struct cgroup_ops *cgfsng_ops_init(void)
308c8a3e
WB
128 return &cgfsng_ops;
129 }
130
131-static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname)
132+static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname, bool inner)
133 {
134- h->fullcgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
f39a178a 135- if (dir_exists(h->fullcgpath)) { /* it must not already exist */
da73bbc6 136- ERROR("Path \"%s\" already existed.", h->fullcgpath);
308c8a3e
WB
137+ char *path;
138+ if (inner) {
02a2999d 139+ path = must_make_path(h->fullcgpath, CGROUP_NAMESPACE_SUBDIR, NULL);
07288e64 140+ h->innercgpath = path;
308c8a3e
WB
141+ } else {
142+ path = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
143+ h->fullcgpath = path;
07288e64
WB
144+ }
145+ if (dir_exists(path)) { // it must not already exist
146+ ERROR("Path \"%s\" already existed.", path);
147 return false;
148 }
149- if (!handle_cpuset_hierarchy(h, cgname)) {
150+ if (!inner && !handle_cpuset_hierarchy(h, cgname)) {
151 ERROR("Failed to handle cgroupfs v1 cpuset controller.");
152 return false;
da73bbc6
WB
153 }
154- return mkdir_p(h->fullcgpath, 0755) == 0;
308c8a3e
WB
155+ return mkdir_p(path, 0755) == 0;
156 }
157
158 static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)
bc7e56ac 159@@ -1341,11 +1352,27 @@ static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)
f39a178a
WB
160 h->fullcgpath = NULL;
161 }
162
163+static inline bool cgfsng_create_inner(struct cgfsng_handler_data *d)
164+{
165+ size_t i;
166+ bool ret = true;
167+ char *cgname = must_make_path(d->container_cgroup, CGROUP_NAMESPACE_SUBDIR, NULL);
168+ for (i = 0; hierarchies[i]; i++) {
169+ if (!create_path_for_hierarchy(hierarchies[i], cgname, true)) {
170+ SYSERROR("Failed to create %s namespace subdirectory: %s", hierarchies[i]->fullcgpath, strerror(errno));
171+ ret = false;
172+ break;
173+ }
174+ }
175+ free(cgname);
176+ return ret;
177+}
178+
179 /*
308c8a3e
WB
180 * Try to create the same cgroup in all hierarchies.
181 * Start with cgroup_pattern; next cgroup_pattern-1, -2, ..., -999
182 */
183-static inline bool cgfsng_create(void *hdata)
308c8a3e
WB
184+static inline bool cgfsng_create(void *hdata, bool inner)
185 {
f39a178a
WB
186 int i;
187 size_t len;
bc7e56ac 188@@ -1357,9 +1384,15 @@ static inline bool cgfsng_create(void *hdata)
308c8a3e 189 return false;
f39a178a 190
308c8a3e
WB
191 if (d->container_cgroup) {
192+ if (inner)
193+ return cgfsng_create_inner(d);
194 WARN("cgfsng_create called a second time");
195 return false;
196 }
197+ if (inner) {
198+ ERROR("cgfsng_create called twice for innner cgroup");
199+ return false;
200+ }
201
f39a178a
WB
202 if (d->cgroup_meta.dir)
203 tmp = lxc_string_join("/", (const char *[]){d->cgroup_meta.dir, d->name, NULL}, false);
bc7e56ac 204@@ -1395,7 +1428,7 @@ again:
f39a178a
WB
205 }
206 }
308c8a3e
WB
207 for (i = 0; hierarchies[i]; i++) {
208- if (!create_path_for_hierarchy(hierarchies[i], cgname)) {
209+ if (!create_path_for_hierarchy(hierarchies[i], cgname, false)) {
210 int j;
f39a178a 211 ERROR("Failed to create \"%s\"", hierarchies[i]->fullcgpath);
308c8a3e 212 free(hierarchies[i]->fullcgpath);
bc7e56ac 213@@ -1415,7 +1448,7 @@ out_free:
308c8a3e
WB
214 return false;
215 }
216
217-static bool cgfsng_enter(void *hdata, pid_t pid)
308c8a3e
WB
218+static bool cgfsng_enter(void *hdata, pid_t pid, bool inner)
219 {
220 char pidstr[25];
221 int i, len;
bc7e56ac 222@@ -1425,7 +1458,13 @@ static bool cgfsng_enter(void *hdata, pid_t pid)
308c8a3e
WB
223 return false;
224
225 for (i = 0; hierarchies[i]; i++) {
226- char *fullpath = must_make_path(hierarchies[i]->fullcgpath,
227+ char *fullpath;
228+ if (inner)
02a2999d
WB
229+ fullpath = must_make_path(hierarchies[i]->fullcgpath,
230+ CGROUP_NAMESPACE_SUBDIR,
308c8a3e
WB
231+ "cgroup.procs", NULL);
232+ else
233+ fullpath = must_make_path(hierarchies[i]->fullcgpath,
234 "cgroup.procs", NULL);
235 if (lxc_write_to_file(fullpath, pidstr, len, false) != 0) {
236 SYSERROR("Failed to enter %s", fullpath);
bc7e56ac 237@@ -1441,6 +1480,7 @@ static bool cgfsng_enter(void *hdata, pid_t pid)
308c8a3e
WB
238 struct chown_data {
239 struct cgfsng_handler_data *d;
f39a178a 240 uid_t origuid; /* target uid in parent namespace */
308c8a3e
WB
241+ bool inner;
242 };
243
244 /*
bc7e56ac 245@@ -1469,13 +1509,20 @@ static int chown_cgroup_wrapper(void *data)
308c8a3e
WB
246 for (i = 0; hierarchies[i]; i++) {
247 char *fullpath, *path = hierarchies[i]->fullcgpath;
248
249+ if (arg->inner)
02a2999d 250+ path = must_make_path(path, CGROUP_NAMESPACE_SUBDIR, NULL);
308c8a3e
WB
251+
252 if (chown(path, destuid, 0) < 0) {
253 SYSERROR("Error chowning %s to %d", path, (int) destuid);
254+ if (arg->inner)
255+ free(path);
256 return -1;
257 }
258
259 if (chmod(path, 0775) < 0) {
260 SYSERROR("Error chmoding %s", path);
261+ if (arg->inner)
262+ free(path);
263 return -1;
264 }
265
bc7e56ac 266@@ -1501,12 +1548,14 @@ static int chown_cgroup_wrapper(void *data)
308c8a3e 267 if (chmod(fullpath, 0664) < 0)
f39a178a 268 WARN("Error chmoding %s: %s", path, strerror(errno));
308c8a3e 269 free(fullpath);
f39a178a
WB
270+ if (arg->inner)
271+ free(path);
308c8a3e
WB
272 }
273
274 return 0;
275 }
276
277-static bool cgfsns_chown(void *hdata, struct lxc_conf *conf)
278+static bool cgfsns_chown(void *hdata, struct lxc_conf *conf, bool inner)
279 {
280 struct cgfsng_handler_data *d = hdata;
281 struct chown_data wrap;
bc7e56ac 282@@ -1519,6 +1568,7 @@ static bool cgfsns_chown(void *hdata, struct lxc_conf *conf)
308c8a3e
WB
283
284 wrap.d = d;
285 wrap.origuid = geteuid();
286+ wrap.inner = inner;
287
f39a178a
WB
288 if (userns_exec_1(conf, chown_cgroup_wrapper, &wrap,
289 "chown_cgroup_wrapper") < 0) {
bc7e56ac 290@@ -1815,12 +1865,15 @@ static bool cgfsng_unfreeze(void *hdata)
07288e64
WB
291 return true;
292 }
293
294-static const char *cgfsng_get_cgroup(void *hdata, const char *subsystem)
295+static const char *cgfsng_get_cgroup(void *hdata, const char *subsystem, bool inner)
296 {
297 struct hierarchy *h = get_hierarchy(subsystem);
298 if (!h)
299 return NULL;
300
301+ if (inner && h->innercgpath)
302+ return h->innercgpath + strlen(h->mountpoint);
303+
304 return h->fullcgpath ? h->fullcgpath + strlen(h->mountpoint) : NULL;
305 }
306
bc7e56ac 307@@ -1848,7 +1901,7 @@ static bool cgfsng_attach(const char *name, const char *lxcpath, pid_t pid)
07288e64
WB
308 char *path, *fullpath;
309 struct hierarchy *h = hierarchies[i];
310
311- path = lxc_cmd_get_cgroup_path(name, lxcpath, h->controllers[0]);
312+ path = lxc_cmd_get_attach_cgroup_path(name, lxcpath, h->controllers[0]);
f39a178a 313 if (!path) /* not running */
07288e64
WB
314 continue;
315
308c8a3e 316diff --git a/src/lxc/cgroups/cgmanager.c b/src/lxc/cgroups/cgmanager.c
f39a178a 317index 054eb171..04ae3a16 100644
308c8a3e
WB
318--- a/src/lxc/cgroups/cgmanager.c
319+++ b/src/lxc/cgroups/cgmanager.c
f39a178a 320@@ -610,7 +610,7 @@ static inline void cleanup_cgroups(char *path)
308c8a3e
WB
321 cgm_remove_cgroup(slist[i], path);
322 }
323
324-static inline bool cgm_create(void *hdata)
325+static inline bool cgm_create(void *hdata, bool inner)
326 {
327 struct cgm_data *d = hdata;
328 char **slist = subsystems;
f39a178a 329@@ -618,6 +618,9 @@ static inline bool cgm_create(void *hdata)
308c8a3e
WB
330 int32_t existed;
331 char result[MAXPATHLEN], *tmp, *cgroup_path;
332
333+ if (inner)
334+ return true;
335+
336 if (!d)
337 return false;
f39a178a
WB
338
339@@ -710,13 +713,16 @@ static bool lxc_cgmanager_enter(pid_t pid, const char *controller,
308c8a3e
WB
340 return true;
341 }
342
343-static inline bool cgm_enter(void *hdata, pid_t pid)
344+static inline bool cgm_enter(void *hdata, pid_t pid, bool inner)
345 {
346 struct cgm_data *d = hdata;
347 char **slist = subsystems;
348 bool ret = false;
349 int i;
350
351+ if (inner)
352+ return true;
353+
354 if (!d || !d->cgroup_path)
355 return false;
356
f39a178a 357@@ -738,10 +744,12 @@ out:
07288e64
WB
358 return ret;
359 }
360
361-static const char *cgm_get_cgroup(void *hdata, const char *subsystem)
362+static const char *cgm_get_cgroup(void *hdata, const char *subsystem, bool inner)
363 {
364 struct cgm_data *d = hdata;
365
366+ (void)inner;
367+
368 if (!d || !d->cgroup_path)
369 return NULL;
370 return d->cgroup_path;
f39a178a 371@@ -1542,10 +1550,13 @@ out:
308c8a3e
WB
372 return ret;
373 }
374
375-static bool cgm_chown(void *hdata, struct lxc_conf *conf)
376+static bool cgm_chown(void *hdata, struct lxc_conf *conf, bool inner)
377 {
378 struct cgm_data *d = hdata;
379
380+ if (inner)
381+ return true;
382+
383 if (!d || !d->cgroup_path)
384 return false;
385 if (!cgm_dbus_connect()) {
386diff --git a/src/lxc/cgroups/cgroup.c b/src/lxc/cgroups/cgroup.c
f39a178a 387index 674e3090..6f0d2fe8 100644
308c8a3e
WB
388--- a/src/lxc/cgroups/cgroup.c
389+++ b/src/lxc/cgroups/cgroup.c
f39a178a 390@@ -80,19 +80,19 @@ void cgroup_destroy(struct lxc_handler *handler)
308c8a3e
WB
391 }
392
f39a178a 393 /* Create the container cgroups for all requested controllers. */
308c8a3e
WB
394-bool cgroup_create(struct lxc_handler *handler)
395+bool cgroup_create(struct lxc_handler *handler, bool inner)
396 {
397 if (ops)
398- return ops->create(handler->cgroup_data);
399+ return ops->create(handler->cgroup_data, inner);
f39a178a 400
308c8a3e
WB
401 return false;
402 }
403
f39a178a 404 /* Enter the container init into its new cgroups for all requested controllers. */
308c8a3e
WB
405-bool cgroup_enter(struct lxc_handler *handler)
406+bool cgroup_enter(struct lxc_handler *handler, bool inner)
407 {
408 if (ops)
409- return ops->enter(handler->cgroup_data, handler->pid);
410+ return ops->enter(handler->cgroup_data, handler->pid, inner);
f39a178a 411
308c8a3e
WB
412 return false;
413 }
f39a178a 414@@ -106,10 +106,11 @@ bool cgroup_create_legacy(struct lxc_handler *handler)
07288e64
WB
415 }
416
f39a178a
WB
417 const char *cgroup_get_cgroup(struct lxc_handler *handler,
418- const char *subsystem)
419+ const char *subsystem,
420+ bool inner)
07288e64
WB
421 {
422 if (ops)
423- return ops->get_cgroup(handler->cgroup_data, subsystem);
424+ return ops->get_cgroup(handler->cgroup_data, subsystem, inner);
f39a178a 425
07288e64
WB
426 return NULL;
427 }
f39a178a 428@@ -155,10 +156,10 @@ bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices)
308c8a3e
WB
429 return false;
430 }
431
432-bool cgroup_chown(struct lxc_handler *handler)
433+bool cgroup_chown(struct lxc_handler *handler, bool inner)
434 {
435 if (ops && ops->chown)
436- return ops->chown(handler->cgroup_data, handler->conf);
437+ return ops->chown(handler->cgroup_data, handler->conf, inner);
f39a178a 438
308c8a3e
WB
439 return true;
440 }
308c8a3e 441diff --git a/src/lxc/cgroups/cgroup.h b/src/lxc/cgroups/cgroup.h
f39a178a 442index f17a6abe..f05fda4e 100644
308c8a3e
WB
443--- a/src/lxc/cgroups/cgroup.h
444+++ b/src/lxc/cgroups/cgroup.h
02a2999d
WB
445@@ -28,6 +28,12 @@
446 #include <stddef.h>
447 #include <sys/types.h>
448
449+/* When lxc.cgroup.protect_limits is in effect the container's cgroup namespace
450+ * will be moved into an additional subdirectory "cgns/" inside the cgroup in
451+ * order to prevent it from accessing the outer limiting cgroup.
452+ */
453+#define CGROUP_NAMESPACE_SUBDIR "cgns"
454+
455 struct lxc_handler;
456 struct lxc_conf;
457 struct lxc_list;
458@@ -43,10 +49,10 @@ struct cgroup_ops {
308c8a3e 459
f39a178a 460 void *(*init)(struct lxc_handler *handler);
308c8a3e
WB
461 void (*destroy)(void *hdata, struct lxc_conf *conf);
462- bool (*create)(void *hdata);
463- bool (*enter)(void *hdata, pid_t pid);
464+ bool (*create)(void *hdata, bool inner);
465+ bool (*enter)(void *hdata, pid_t pid, bool inner);
466 bool (*create_legacy)(void *hdata, pid_t pid);
07288e64
WB
467- const char *(*get_cgroup)(void *hdata, const char *subsystem);
468+ const char *(*get_cgroup)(void *hdata, const char *subsystem, bool inner);
308c8a3e 469 bool (*escape)();
07288e64
WB
470 int (*num_hierarchies)();
471 bool (*get_hierarchies)(int n, char ***out);
02a2999d 472@@ -54,7 +60,7 @@ struct cgroup_ops {
308c8a3e
WB
473 int (*get)(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
474 bool (*unfreeze)(void *hdata);
475 bool (*setup_limits)(void *hdata, struct lxc_list *cgroup_conf, bool with_devices);
476- bool (*chown)(void *hdata, struct lxc_conf *conf);
477+ bool (*chown)(void *hdata, struct lxc_conf *conf, bool inner);
478 bool (*attach)(const char *name, const char *lxcpath, pid_t pid);
479 bool (*mount_cgroup)(void *hdata, const char *root, int type);
480 int (*nrtasks)(void *hdata);
02a2999d 481@@ -66,14 +72,14 @@ extern bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid);
308c8a3e
WB
482 extern bool cgroup_mount(const char *root, struct lxc_handler *handler, int type);
483 extern void cgroup_destroy(struct lxc_handler *handler);
484 extern bool cgroup_init(struct lxc_handler *handler);
485-extern bool cgroup_create(struct lxc_handler *handler);
486+extern bool cgroup_create(struct lxc_handler *handler, bool inner);
487 extern bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices);
488-extern bool cgroup_chown(struct lxc_handler *handler);
489-extern bool cgroup_enter(struct lxc_handler *handler);
490+extern bool cgroup_chown(struct lxc_handler *handler, bool inner);
491+extern bool cgroup_enter(struct lxc_handler *handler, bool inner);
492 extern void cgroup_cleanup(struct lxc_handler *handler);
493 extern bool cgroup_create_legacy(struct lxc_handler *handler);
494 extern int cgroup_nrtasks(struct lxc_handler *handler);
07288e64
WB
495-extern const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem);
496+extern const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem, bool inner);
497 extern bool cgroup_escape();
498 extern int cgroup_num_hierarchies();
499 extern bool cgroup_get_hierarchies(int i, char ***out);
500diff --git a/src/lxc/commands.c b/src/lxc/commands.c
f39a178a 501index 68fbd387..ccdbeeba 100644
07288e64
WB
502--- a/src/lxc/commands.c
503+++ b/src/lxc/commands.c
f39a178a 504@@ -410,30 +410,29 @@ static int lxc_cmd_get_clone_flags_callback(int fd, struct lxc_cmd_req *req,
02a2999d
WB
505 return lxc_cmd_rsp_send(fd, &rsp);
506 }
07288e64 507
02a2999d
WB
508-/*
509- * lxc_cmd_get_cgroup_path: Calculate a container's cgroup path for a
510- * particular subsystem. This is the cgroup path relative to the root
511- * of the cgroup filesystem.
512- *
513- * @name : name of container to connect to
514- * @lxcpath : the lxcpath in which the container is running
515- * @subsystem : the subsystem being asked about
516- *
517- * Returns the path on success, NULL on failure. The caller must free() the
518- * returned path.
519- */
520-char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
521- const char *subsystem)
522+static char *do_lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
f39a178a
WB
523+ const char *subsystem,
524+ bool inner)
02a2999d
WB
525 {
526 int ret, stopped;
527+ size_t subsyslen = strlen(subsystem);
07288e64 528+
02a2999d
WB
529 struct lxc_cmd_rr cmd = {
530 .req = {
531 .cmd = LXC_CMD_GET_CGROUP,
532- .datalen = strlen(subsystem)+1,
533+ .datalen = subsyslen+1,
534 .data = subsystem,
535 },
536 };
537
538+ if (inner) {
539+ char *data = alloca(subsyslen+2);
540+ memcpy(data, subsystem, subsyslen+1);
541+ data[subsyslen+1] = 1;
542+ cmd.req.datalen = subsyslen+2,
543+ cmd.req.data = data;
544+ }
07288e64 545+
02a2999d 546 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
f39a178a
WB
547 if (ret < 0) {
548 TRACE("command %s failed for container \"%s\": %s.",
549@@ -458,16 +457,61 @@ char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
02a2999d
WB
550 return cmd.rsp.data;
551 }
552
07288e64 553+/*
02a2999d
WB
554+ * lxc_cmd_get_cgroup_path: Calculate a container's cgroup path for a
555+ * particular subsystem. This is the cgroup path relative to the root
07288e64
WB
556+ * of the cgroup filesystem.
557+ *
558+ * @name : name of container to connect to
559+ * @lxcpath : the lxcpath in which the container is running
560+ * @subsystem : the subsystem being asked about
561+ *
562+ * Returns the path on success, NULL on failure. The caller must free() the
563+ * returned path.
564+ */
02a2999d 565+char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
07288e64
WB
566+ const char *subsystem)
567+{
02a2999d 568+ return do_lxc_cmd_get_cgroup_path(name, lxcpath, subsystem, false);
07288e64 569+}
f39a178a
WB
570+
571+/*
572+ * lxc_cmd_get_attach_cgroup_path: Calculate a container's inner cgroup path
573+ * for a particular subsystem. This is the cgroup path relative to the root
574+ * of the cgroup filesystem.
575+ *
576+ * @name : name of container to connect to
577+ * @lxcpath : the lxcpath in which the container is running
578+ * @subsystem : the subsystem being asked about
579+ *
580+ * Returns the path on success, NULL on failure. The caller must free() the
581+ * returned path.
582+ */
583+char *lxc_cmd_get_attach_cgroup_path(const char *name, const char *lxcpath,
584+ const char *subsystem)
585+{
586+ return do_lxc_cmd_get_cgroup_path(name, lxcpath, subsystem, true);
587+}
588+
07288e64 589+
02a2999d
WB
590 static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
591 struct lxc_handler *handler)
592 {
593 struct lxc_cmd_rsp rsp;
594 const char *path;
595+ const char *subsystem;
596+ size_t subsyslen;
597+ bool inner = false;
598
599 if (req->datalen < 1)
600 return -1;
601
602- path = cgroup_get_cgroup(handler, req->data);
603+ subsystem = req->data;
604+ subsyslen = strlen(subsystem);
605+ if (req->datalen == subsyslen+2)
606+ inner = (subsystem[subsyslen+1] == 1);
07288e64 607+
02a2999d 608+ path = cgroup_get_cgroup(handler, req->data, inner);
07288e64
WB
609 if (!path)
610 return -1;
611 rsp.datalen = strlen(path) + 1,
07288e64 612diff --git a/src/lxc/commands.h b/src/lxc/commands.h
f39a178a 613index 28428c77..9557dcaa 100644
07288e64
WB
614--- a/src/lxc/commands.h
615+++ b/src/lxc/commands.h
f39a178a 616@@ -82,6 +82,8 @@ extern int lxc_cmd_console(const char *name, int *ttynum, int *fd,
07288e64
WB
617 */
618 extern char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
619 const char *subsystem);
620+extern char *lxc_cmd_get_attach_cgroup_path(const char *name,
621+ const char *lxcpath, const char *subsystem);
622 extern int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath);
623 extern char *lxc_cmd_get_config_item(const char *name, const char *item, const char *lxcpath);
624 extern char *lxc_cmd_get_name(const char *hashed_sock);
308c8a3e 625diff --git a/src/lxc/criu.c b/src/lxc/criu.c
bc7e56ac 626index 96688edc..539ae8bd 100644
308c8a3e
WB
627--- a/src/lxc/criu.c
628+++ b/src/lxc/criu.c
f39a178a 629@@ -324,7 +324,7 @@ static void exec_criu(struct criu_opts *opts)
07288e64
WB
630 } else {
631 const char *p;
632
633- p = cgroup_get_cgroup(opts->handler, controllers[0]);
634+ p = cgroup_get_cgroup(opts->handler, controllers[0], false);
635 if (!p) {
636 ERROR("failed to get cgroup path for %s", controllers[0]);
637 goto err;
f39a178a 638@@ -857,7 +857,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
308c8a3e
WB
639 goto out_fini_handler;
640 }
641
642- if (!cgroup_create(handler)) {
643+ if (!cgroup_create(handler, false)) {
644 ERROR("failed creating groups");
645 goto out_fini_handler;
646 }
647diff --git a/src/lxc/start.c b/src/lxc/start.c
bc7e56ac 648index a6a40c72..920f3c23 100644
308c8a3e
WB
649--- a/src/lxc/start.c
650+++ b/src/lxc/start.c
bc7e56ac 651@@ -1217,7 +1217,7 @@ static int lxc_spawn(struct lxc_handler *handler)
308c8a3e
WB
652
653 cgroups_connected = true;
654
655- if (!cgroup_create(handler)) {
656+ if (!cgroup_create(handler, false)) {
da73bbc6 657 ERROR("Failed creating cgroups.");
308c8a3e
WB
658 goto out_delete_net;
659 }
bc7e56ac 660@@ -1292,10 +1292,10 @@ static int lxc_spawn(struct lxc_handler *handler)
308c8a3e
WB
661 goto out_delete_net;
662 }
663
664- if (!cgroup_enter(handler))
665+ if (!cgroup_enter(handler, false))
666 goto out_delete_net;
667
668- if (!cgroup_chown(handler))
669+ if (!cgroup_chown(handler, false))
670 goto out_delete_net;
671
bc7e56ac
WB
672 handler->netnsfd = lxc_preserve_ns(handler->pid, "net");
673@@ -1338,15 +1338,30 @@ static int lxc_spawn(struct lxc_handler *handler)
674 goto out_delete_net;
675 }
676
677- if (lxc_sync_barrier_child(handler, LXC_SYNC_CGROUP_UNSHARE))
678- goto out_delete_net;
679-
680 if (!cgroup_setup_limits(handler, true)) {
681 ERROR("Failed to setup the devices cgroup for container \"%s\".", name);
682 goto out_delete_net;
308c8a3e 683 }
f39a178a 684 TRACE("Set up cgroup device limits");
308c8a3e
WB
685
686+ if (cgns_supported()) {
687+ if (!cgroup_create(handler, true)) {
688+ ERROR("failed to create inner cgroup separation layer");
689+ goto out_delete_net;
690+ }
691+ if (!cgroup_enter(handler, true)) {
692+ ERROR("failed to enter inner cgroup separation layer");
693+ goto out_delete_net;
694+ }
695+ if (!cgroup_chown(handler, true)) {
696+ ERROR("failed chown inner cgroup separation layer");
697+ goto out_delete_net;
698+ }
699+ }
bc7e56ac
WB
700+
701+ if (lxc_sync_barrier_child(handler, LXC_SYNC_CGROUP_UNSHARE))
702+ goto out_delete_net;
308c8a3e
WB
703+
704 cgroup_disconnect();
705 cgroups_connected = false;
706
707--
7395ab25 7082.11.0
308c8a3e 709