]> git.proxmox.com Git - lxc.git/blame - debian/patches/0005-separate-the-limiting-from-the-namespaced-cgroup-roo.patch
bump version to 2.0.8-1
[lxc.git] / debian / patches / 0005-separate-the-limiting-from-the-namespaced-cgroup-roo.patch
CommitLineData
7395ab25 1From 5ceb26ec765edb81aba25b9db4fc5ede0d7a0375 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
7395ab25 4Subject: [PATCH 5/8] 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---
07288e64 17 src/lxc/cgroups/cgfs.c | 19 ++++++--
02a2999d 18 src/lxc/cgroups/cgfsng.c | 81 +++++++++++++++++++++++++++-----
07288e64
WB
19 src/lxc/cgroups/cgmanager.c | 19 ++++++--
20 src/lxc/cgroups/cgroup.c | 16 +++----
02a2999d
WB
21 src/lxc/cgroups/cgroup.h | 22 +++++----
22 src/lxc/commands.c | 112 ++++++++++++++++++++++++++++++--------------
23 src/lxc/commands.h | 2 +
07288e64
WB
24 src/lxc/criu.c | 4 +-
25 src/lxc/start.c | 21 +++++++--
02a2999d 26 9 files changed, 219 insertions(+), 77 deletions(-)
308c8a3e
WB
27
28diff --git a/src/lxc/cgroups/cgfs.c b/src/lxc/cgroups/cgfs.c
7395ab25 29index 3bfa5239..f305a561 100644
308c8a3e
WB
30--- a/src/lxc/cgroups/cgfs.c
31+++ b/src/lxc/cgroups/cgfs.c
32@@ -2383,12 +2383,15 @@ static void cgfs_destroy(void *hdata, struct lxc_conf *conf)
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;
49@@ -2399,12 +2402,15 @@ static inline bool cgfs_create(void *hdata)
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;
07288e64
WB
66@@ -2428,10 +2434,12 @@ static inline bool cgfs_create_legacy(void *hdata, pid_t pid)
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);
80@@ -2646,13 +2654,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
7395ab25 99index ebd548b9..b26e1b27 100644
308c8a3e
WB
100--- a/src/lxc/cgroups/cgfsng.c
101+++ b/src/lxc/cgroups/cgfsng.c
07288e64
WB
102@@ -72,6 +72,7 @@ struct hierarchy {
103 char *mountpoint;
104 char *base_cgroup;
105 char *fullcgpath;
106+ char *innercgpath;
107 };
108
109 /*
7395ab25 110@@ -820,6 +821,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;
114+ new->innercgpath = false;
115
116 newentry = append_null_to_list((void ***)&hierarchies);
117 hierarchies[newentry] = new;
7395ab25 118@@ -1304,6 +1306,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
7395ab25 127@@ -1321,18 +1325,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);
da73bbc6
WB
135- if (dir_exists(h->fullcgpath)) { // it must not already exist
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)
7395ab25 159@@ -1347,7 +1358,8 @@ static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)
308c8a3e
WB
160 * Try to create the same cgroup in all hierarchies.
161 * Start with cgroup_pattern; next cgroup_pattern-1, -2, ..., -999
162 */
163-static inline bool cgfsng_create(void *hdata)
164+static inline bool cgfsng_create_inner(struct cgfsng_handler_data*);
165+static inline bool cgfsng_create(void *hdata, bool inner)
166 {
167 struct cgfsng_handler_data *d = hdata;
168 char *tmp, *cgname, *offset;
7395ab25 169@@ -1357,9 +1369,15 @@ static inline bool cgfsng_create(void *hdata)
308c8a3e
WB
170 if (!d)
171 return false;
172 if (d->container_cgroup) {
173+ if (inner)
174+ return cgfsng_create_inner(d);
175 WARN("cgfsng_create called a second time");
176 return false;
177 }
178+ if (inner) {
179+ ERROR("cgfsng_create called twice for innner cgroup");
180+ return false;
181+ }
182
183 tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
184 if (!tmp) {
7395ab25 185@@ -1380,7 +1398,7 @@ again:
308c8a3e
WB
186 if (idx)
187 snprintf(offset, 5, "-%d", idx);
188 for (i = 0; hierarchies[i]; i++) {
189- if (!create_path_for_hierarchy(hierarchies[i], cgname)) {
190+ if (!create_path_for_hierarchy(hierarchies[i], cgname, false)) {
191 int j;
192 SYSERROR("Failed to create %s: %s", hierarchies[i]->fullcgpath, strerror(errno));
193 free(hierarchies[i]->fullcgpath);
7395ab25 194@@ -1400,7 +1418,24 @@ out_free:
308c8a3e
WB
195 return false;
196 }
197
198-static bool cgfsng_enter(void *hdata, pid_t pid)
199+static inline bool cgfsng_create_inner(struct cgfsng_handler_data *d)
200+{
201+ size_t i;
202+ bool ret = true;
02a2999d 203+ char *cgname = must_make_path(d->container_cgroup, CGROUP_NAMESPACE_SUBDIR, NULL);
308c8a3e
WB
204+ for (i = 0; hierarchies[i]; i++) {
205+ if (!create_path_for_hierarchy(hierarchies[i], cgname, true)) {
02a2999d 206+ SYSERROR("Failed to create %s namespace subdirectory: %s", hierarchies[i]->fullcgpath, strerror(errno));
308c8a3e
WB
207+ ret = false;
208+ break;
209+ }
210+ }
211+ free(cgname);
212+ return ret;
213+}
214+
215+
216+static bool cgfsng_enter(void *hdata, pid_t pid, bool inner)
217 {
218 char pidstr[25];
219 int i, len;
7395ab25 220@@ -1410,7 +1445,13 @@ static bool cgfsng_enter(void *hdata, pid_t pid)
308c8a3e
WB
221 return false;
222
223 for (i = 0; hierarchies[i]; i++) {
224- char *fullpath = must_make_path(hierarchies[i]->fullcgpath,
225+ char *fullpath;
226+ if (inner)
02a2999d
WB
227+ fullpath = must_make_path(hierarchies[i]->fullcgpath,
228+ CGROUP_NAMESPACE_SUBDIR,
308c8a3e
WB
229+ "cgroup.procs", NULL);
230+ else
231+ fullpath = must_make_path(hierarchies[i]->fullcgpath,
232 "cgroup.procs", NULL);
233 if (lxc_write_to_file(fullpath, pidstr, len, false) != 0) {
234 SYSERROR("Failed to enter %s", fullpath);
7395ab25 235@@ -1426,6 +1467,7 @@ static bool cgfsng_enter(void *hdata, pid_t pid)
308c8a3e
WB
236 struct chown_data {
237 struct cgfsng_handler_data *d;
238 uid_t origuid; // target uid in parent namespace
239+ bool inner;
240 };
241
242 /*
7395ab25 243@@ -1454,13 +1496,20 @@ static int chown_cgroup_wrapper(void *data)
308c8a3e
WB
244 for (i = 0; hierarchies[i]; i++) {
245 char *fullpath, *path = hierarchies[i]->fullcgpath;
246
247+ if (arg->inner)
02a2999d 248+ path = must_make_path(path, CGROUP_NAMESPACE_SUBDIR, NULL);
308c8a3e
WB
249+
250 if (chown(path, destuid, 0) < 0) {
251 SYSERROR("Error chowning %s to %d", path, (int) destuid);
252+ if (arg->inner)
253+ free(path);
254 return -1;
255 }
256
257 if (chmod(path, 0775) < 0) {
258 SYSERROR("Error chmoding %s", path);
259+ if (arg->inner)
260+ free(path);
261 return -1;
262 }
263
7395ab25 264@@ -1484,12 +1533,14 @@ static int chown_cgroup_wrapper(void *data)
308c8a3e
WB
265 if (chmod(fullpath, 0664) < 0)
266 WARN("Error chmoding %s: %m", path);
267 free(fullpath);
268+
269+ free(path);
270 }
271
272 return 0;
273 }
274
275-static bool cgfsns_chown(void *hdata, struct lxc_conf *conf)
276+static bool cgfsns_chown(void *hdata, struct lxc_conf *conf, bool inner)
277 {
278 struct cgfsng_handler_data *d = hdata;
279 struct chown_data wrap;
7395ab25 280@@ -1502,6 +1553,7 @@ static bool cgfsns_chown(void *hdata, struct lxc_conf *conf)
308c8a3e
WB
281
282 wrap.d = d;
283 wrap.origuid = geteuid();
284+ wrap.inner = inner;
285
286 if (userns_exec_1(conf, chown_cgroup_wrapper, &wrap) < 0) {
287 ERROR("Error requesting cgroup chown in new namespace");
7395ab25 288@@ -1796,12 +1848,15 @@ static bool cgfsng_unfreeze(void *hdata)
07288e64
WB
289 return true;
290 }
291
292-static const char *cgfsng_get_cgroup(void *hdata, const char *subsystem)
293+static const char *cgfsng_get_cgroup(void *hdata, const char *subsystem, bool inner)
294 {
295 struct hierarchy *h = get_hierarchy(subsystem);
296 if (!h)
297 return NULL;
298
299+ if (inner && h->innercgpath)
300+ return h->innercgpath + strlen(h->mountpoint);
301+
302 return h->fullcgpath ? h->fullcgpath + strlen(h->mountpoint) : NULL;
303 }
304
7395ab25 305@@ -1836,7 +1891,7 @@ static bool cgfsng_attach(const char *name, const char *lxcpath, pid_t pid)
07288e64
WB
306 char *path, *fullpath;
307 struct hierarchy *h = hierarchies[i];
308
309- path = lxc_cmd_get_cgroup_path(name, lxcpath, h->controllers[0]);
310+ path = lxc_cmd_get_attach_cgroup_path(name, lxcpath, h->controllers[0]);
311 if (!path) // not running
312 continue;
313
308c8a3e 314diff --git a/src/lxc/cgroups/cgmanager.c b/src/lxc/cgroups/cgmanager.c
7395ab25 315index f2756b07..ac966b6f 100644
308c8a3e
WB
316--- a/src/lxc/cgroups/cgmanager.c
317+++ b/src/lxc/cgroups/cgmanager.c
318@@ -609,7 +609,7 @@ static inline void cleanup_cgroups(char *path)
319 cgm_remove_cgroup(slist[i], path);
320 }
321
322-static inline bool cgm_create(void *hdata)
323+static inline bool cgm_create(void *hdata, bool inner)
324 {
325 struct cgm_data *d = hdata;
326 char **slist = subsystems;
327@@ -617,6 +617,9 @@ static inline bool cgm_create(void *hdata)
328 int32_t existed;
329 char result[MAXPATHLEN], *tmp, *cgroup_path;
330
331+ if (inner)
332+ return true;
333+
334 if (!d)
335 return false;
336 // XXX we should send a hint to the cgmanager that when these
337@@ -709,13 +712,16 @@ static bool lxc_cgmanager_enter(pid_t pid, const char *controller,
338 return true;
339 }
340
341-static inline bool cgm_enter(void *hdata, pid_t pid)
342+static inline bool cgm_enter(void *hdata, pid_t pid, bool inner)
343 {
344 struct cgm_data *d = hdata;
345 char **slist = subsystems;
346 bool ret = false;
347 int i;
348
349+ if (inner)
350+ return true;
351+
352 if (!d || !d->cgroup_path)
353 return false;
354
07288e64
WB
355@@ -737,10 +743,12 @@ out:
356 return ret;
357 }
358
359-static const char *cgm_get_cgroup(void *hdata, const char *subsystem)
360+static const char *cgm_get_cgroup(void *hdata, const char *subsystem, bool inner)
361 {
362 struct cgm_data *d = hdata;
363
364+ (void)inner;
365+
366 if (!d || !d->cgroup_path)
367 return NULL;
368 return d->cgroup_path;
369@@ -1541,10 +1549,13 @@ out:
308c8a3e
WB
370 return ret;
371 }
372
373-static bool cgm_chown(void *hdata, struct lxc_conf *conf)
374+static bool cgm_chown(void *hdata, struct lxc_conf *conf, bool inner)
375 {
376 struct cgm_data *d = hdata;
377
378+ if (inner)
379+ return true;
380+
381 if (!d || !d->cgroup_path)
382 return false;
383 if (!cgm_dbus_connect()) {
384diff --git a/src/lxc/cgroups/cgroup.c b/src/lxc/cgroups/cgroup.c
7395ab25 385index 78472d4f..4d26e720 100644
308c8a3e
WB
386--- a/src/lxc/cgroups/cgroup.c
387+++ b/src/lxc/cgroups/cgroup.c
388@@ -80,10 +80,10 @@ void cgroup_destroy(struct lxc_handler *handler)
389 }
390
391 /* Create the container cgroups for all requested controllers */
392-bool cgroup_create(struct lxc_handler *handler)
393+bool cgroup_create(struct lxc_handler *handler, bool inner)
394 {
395 if (ops)
396- return ops->create(handler->cgroup_data);
397+ return ops->create(handler->cgroup_data, inner);
398 return false;
399 }
400
401@@ -91,10 +91,10 @@ bool cgroup_create(struct lxc_handler *handler)
402 * Enter the container init into its new cgroups for all
403 * requested controllers
404 */
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);
411 return false;
412 }
413
07288e64
WB
414@@ -105,10 +105,10 @@ bool cgroup_create_legacy(struct lxc_handler *handler)
415 return true;
416 }
417
418-const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem)
419+const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem, bool inner)
420 {
421 if (ops)
422- return ops->get_cgroup(handler->cgroup_data, subsystem);
423+ return ops->get_cgroup(handler->cgroup_data, subsystem, inner);
424 return NULL;
425 }
426
308c8a3e
WB
427@@ -150,10 +150,10 @@ bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices)
428 return false;
429 }
430
431-bool cgroup_chown(struct lxc_handler *handler)
432+bool cgroup_chown(struct lxc_handler *handler, bool inner)
433 {
434 if (ops && ops->chown)
435- return ops->chown(handler->cgroup_data, handler->conf);
436+ return ops->chown(handler->cgroup_data, handler->conf, inner);
437 return true;
438 }
439
440diff --git a/src/lxc/cgroups/cgroup.h b/src/lxc/cgroups/cgroup.h
7395ab25 441index 11b251e6..f36c6f02 100644
308c8a3e
WB
442--- a/src/lxc/cgroups/cgroup.h
443+++ b/src/lxc/cgroups/cgroup.h
02a2999d
WB
444@@ -28,6 +28,12 @@
445 #include <stddef.h>
446 #include <sys/types.h>
447
448+/* When lxc.cgroup.protect_limits is in effect the container's cgroup namespace
449+ * will be moved into an additional subdirectory "cgns/" inside the cgroup in
450+ * order to prevent it from accessing the outer limiting cgroup.
451+ */
452+#define CGROUP_NAMESPACE_SUBDIR "cgns"
453+
454 struct lxc_handler;
455 struct lxc_conf;
456 struct lxc_list;
457@@ -43,10 +49,10 @@ struct cgroup_ops {
308c8a3e
WB
458
459 void *(*init)(const char *name);
460 void (*destroy)(void *hdata, struct lxc_conf *conf);
461- bool (*create)(void *hdata);
462- bool (*enter)(void *hdata, pid_t pid);
463+ bool (*create)(void *hdata, bool inner);
464+ bool (*enter)(void *hdata, pid_t pid, bool inner);
465 bool (*create_legacy)(void *hdata, pid_t pid);
07288e64
WB
466- const char *(*get_cgroup)(void *hdata, const char *subsystem);
467+ const char *(*get_cgroup)(void *hdata, const char *subsystem, bool inner);
308c8a3e 468 bool (*escape)();
07288e64
WB
469 int (*num_hierarchies)();
470 bool (*get_hierarchies)(int n, char ***out);
02a2999d 471@@ -54,7 +60,7 @@ struct cgroup_ops {
308c8a3e
WB
472 int (*get)(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
473 bool (*unfreeze)(void *hdata);
474 bool (*setup_limits)(void *hdata, struct lxc_list *cgroup_conf, bool with_devices);
475- bool (*chown)(void *hdata, struct lxc_conf *conf);
476+ bool (*chown)(void *hdata, struct lxc_conf *conf, bool inner);
477 bool (*attach)(const char *name, const char *lxcpath, pid_t pid);
478 bool (*mount_cgroup)(void *hdata, const char *root, int type);
479 int (*nrtasks)(void *hdata);
02a2999d 480@@ -66,14 +72,14 @@ extern bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid);
308c8a3e
WB
481 extern bool cgroup_mount(const char *root, struct lxc_handler *handler, int type);
482 extern void cgroup_destroy(struct lxc_handler *handler);
483 extern bool cgroup_init(struct lxc_handler *handler);
484-extern bool cgroup_create(struct lxc_handler *handler);
485+extern bool cgroup_create(struct lxc_handler *handler, bool inner);
486 extern bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices);
487-extern bool cgroup_chown(struct lxc_handler *handler);
488-extern bool cgroup_enter(struct lxc_handler *handler);
489+extern bool cgroup_chown(struct lxc_handler *handler, bool inner);
490+extern bool cgroup_enter(struct lxc_handler *handler, bool inner);
491 extern void cgroup_cleanup(struct lxc_handler *handler);
492 extern bool cgroup_create_legacy(struct lxc_handler *handler);
493 extern int cgroup_nrtasks(struct lxc_handler *handler);
07288e64
WB
494-extern const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem);
495+extern const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem, bool inner);
496 extern bool cgroup_escape();
497 extern int cgroup_num_hierarchies();
498 extern bool cgroup_get_hierarchies(int i, char ***out);
499diff --git a/src/lxc/commands.c b/src/lxc/commands.c
7395ab25 500index 27c8c084..0eb2741f 100644
07288e64
WB
501--- a/src/lxc/commands.c
502+++ b/src/lxc/commands.c
7395ab25 503@@ -133,15 +133,15 @@ static int fill_sock_name(char *path, int len, const char *lxcname,
07288e64
WB
504 static const char *lxc_cmd_str(lxc_cmd_t cmd)
505 {
506 static const char * const cmdname[LXC_CMD_MAX] = {
507- [LXC_CMD_CONSOLE] = "console",
508- [LXC_CMD_STOP] = "stop",
509- [LXC_CMD_GET_STATE] = "get_state",
510- [LXC_CMD_GET_INIT_PID] = "get_init_pid",
511- [LXC_CMD_GET_CLONE_FLAGS] = "get_clone_flags",
512- [LXC_CMD_GET_CGROUP] = "get_cgroup",
513- [LXC_CMD_GET_CONFIG_ITEM] = "get_config_item",
514- [LXC_CMD_GET_NAME] = "get_name",
515- [LXC_CMD_GET_LXCPATH] = "get_lxcpath",
516+ [LXC_CMD_CONSOLE] = "console",
517+ [LXC_CMD_STOP] = "stop",
518+ [LXC_CMD_GET_STATE] = "get_state",
519+ [LXC_CMD_GET_INIT_PID] = "get_init_pid",
520+ [LXC_CMD_GET_CLONE_FLAGS] = "get_clone_flags",
521+ [LXC_CMD_GET_CGROUP] = "get_cgroup",
522+ [LXC_CMD_GET_CONFIG_ITEM] = "get_config_item",
523+ [LXC_CMD_GET_NAME] = "get_name",
524+ [LXC_CMD_GET_LXCPATH] = "get_lxcpath",
07288e64
WB
525 };
526
527 if (cmd >= LXC_CMD_MAX)
7395ab25 528@@ -437,30 +437,28 @@ static int lxc_cmd_get_clone_flags_callback(int fd, struct lxc_cmd_req *req,
02a2999d
WB
529 return lxc_cmd_rsp_send(fd, &rsp);
530 }
07288e64 531
02a2999d
WB
532-/*
533- * lxc_cmd_get_cgroup_path: Calculate a container's cgroup path for a
534- * particular subsystem. This is the cgroup path relative to the root
535- * of the cgroup filesystem.
536- *
537- * @name : name of container to connect to
538- * @lxcpath : the lxcpath in which the container is running
539- * @subsystem : the subsystem being asked about
540- *
541- * Returns the path on success, NULL on failure. The caller must free() the
542- * returned path.
543- */
544-char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
545- const char *subsystem)
546+static char *do_lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
547+ const char *subsystem, bool inner)
548 {
549 int ret, stopped;
550+ size_t subsyslen = strlen(subsystem);
07288e64 551+
02a2999d
WB
552 struct lxc_cmd_rr cmd = {
553 .req = {
554 .cmd = LXC_CMD_GET_CGROUP,
555- .datalen = strlen(subsystem)+1,
556+ .datalen = subsyslen+1,
557 .data = subsystem,
558 },
559 };
560
561+ if (inner) {
562+ char *data = alloca(subsyslen+2);
563+ memcpy(data, subsystem, subsyslen+1);
564+ data[subsyslen+1] = 1;
565+ cmd.req.datalen = subsyslen+2,
566+ cmd.req.data = data;
567+ }
07288e64 568+
02a2999d
WB
569 ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
570 if (ret < 0)
571 return NULL;
7395ab25 572@@ -479,16 +477,42 @@ char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
02a2999d
WB
573 return cmd.rsp.data;
574 }
575
07288e64 576+/*
02a2999d
WB
577+ * lxc_cmd_get_cgroup_path: Calculate a container's cgroup path for a
578+ * particular subsystem. This is the cgroup path relative to the root
07288e64
WB
579+ * of the cgroup filesystem.
580+ *
581+ * @name : name of container to connect to
582+ * @lxcpath : the lxcpath in which the container is running
583+ * @subsystem : the subsystem being asked about
584+ *
585+ * Returns the path on success, NULL on failure. The caller must free() the
586+ * returned path.
587+ */
02a2999d 588+char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
07288e64
WB
589+ const char *subsystem)
590+{
02a2999d 591+ return do_lxc_cmd_get_cgroup_path(name, lxcpath, subsystem, false);
07288e64
WB
592+}
593+
02a2999d
WB
594 static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
595 struct lxc_handler *handler)
596 {
597 struct lxc_cmd_rsp rsp;
598 const char *path;
599+ const char *subsystem;
600+ size_t subsyslen;
601+ bool inner = false;
602
603 if (req->datalen < 1)
604 return -1;
605
606- path = cgroup_get_cgroup(handler, req->data);
607+ subsystem = req->data;
608+ subsyslen = strlen(subsystem);
609+ if (req->datalen == subsyslen+2)
610+ inner = (subsystem[subsyslen+1] == 1);
07288e64 611+
02a2999d 612+ path = cgroup_get_cgroup(handler, req->data, inner);
07288e64
WB
613 if (!path)
614 return -1;
615 rsp.datalen = strlen(path) + 1,
7395ab25 616@@ -499,6 +523,24 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
02a2999d
WB
617 }
618
619 /*
620+ * lxc_cmd_get_attach_cgroup_path: Calculate a container's inner cgroup path
621+ * for a particular subsystem. This is the cgroup path relative to the root
622+ * of the cgroup filesystem.
623+ *
624+ * @name : name of container to connect to
625+ * @lxcpath : the lxcpath in which the container is running
626+ * @subsystem : the subsystem being asked about
627+ *
628+ * Returns the path on success, NULL on failure. The caller must free() the
629+ * returned path.
630+ */
631+char *lxc_cmd_get_attach_cgroup_path(const char *name, const char *lxcpath,
632+ const char *subsystem)
633+{
634+ return do_lxc_cmd_get_cgroup_path(name, lxcpath, subsystem, true);
635+}
636+
637+/*
638 * lxc_cmd_get_config_item: Get config item the running container
639 *
640 * @name : name of container to connect to
7395ab25 641@@ -849,16 +891,16 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
07288e64
WB
642 typedef int (*callback)(int, struct lxc_cmd_req *, struct lxc_handler *);
643
644 callback cb[LXC_CMD_MAX] = {
645- [LXC_CMD_CONSOLE] = lxc_cmd_console_callback,
646- [LXC_CMD_CONSOLE_WINCH] = lxc_cmd_console_winch_callback,
647- [LXC_CMD_STOP] = lxc_cmd_stop_callback,
648- [LXC_CMD_GET_STATE] = lxc_cmd_get_state_callback,
649- [LXC_CMD_GET_INIT_PID] = lxc_cmd_get_init_pid_callback,
650- [LXC_CMD_GET_CLONE_FLAGS] = lxc_cmd_get_clone_flags_callback,
651- [LXC_CMD_GET_CGROUP] = lxc_cmd_get_cgroup_callback,
652- [LXC_CMD_GET_CONFIG_ITEM] = lxc_cmd_get_config_item_callback,
653- [LXC_CMD_GET_NAME] = lxc_cmd_get_name_callback,
654- [LXC_CMD_GET_LXCPATH] = lxc_cmd_get_lxcpath_callback,
655+ [LXC_CMD_CONSOLE] = lxc_cmd_console_callback,
656+ [LXC_CMD_CONSOLE_WINCH] = lxc_cmd_console_winch_callback,
657+ [LXC_CMD_STOP] = lxc_cmd_stop_callback,
658+ [LXC_CMD_GET_STATE] = lxc_cmd_get_state_callback,
659+ [LXC_CMD_GET_INIT_PID] = lxc_cmd_get_init_pid_callback,
660+ [LXC_CMD_GET_CLONE_FLAGS] = lxc_cmd_get_clone_flags_callback,
661+ [LXC_CMD_GET_CGROUP] = lxc_cmd_get_cgroup_callback,
662+ [LXC_CMD_GET_CONFIG_ITEM] = lxc_cmd_get_config_item_callback,
663+ [LXC_CMD_GET_NAME] = lxc_cmd_get_name_callback,
664+ [LXC_CMD_GET_LXCPATH] = lxc_cmd_get_lxcpath_callback,
07288e64
WB
665 };
666
667 if (req->cmd >= LXC_CMD_MAX) {
668diff --git a/src/lxc/commands.h b/src/lxc/commands.h
7395ab25 669index 184eefa0..6430b334 100644
07288e64
WB
670--- a/src/lxc/commands.h
671+++ b/src/lxc/commands.h
02a2999d 672@@ -77,6 +77,8 @@ extern int lxc_cmd_console(const char *name, int *ttynum, int *fd,
07288e64
WB
673 */
674 extern char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
675 const char *subsystem);
676+extern char *lxc_cmd_get_attach_cgroup_path(const char *name,
677+ const char *lxcpath, const char *subsystem);
678 extern int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath);
679 extern char *lxc_cmd_get_config_item(const char *name, const char *item, const char *lxcpath);
680 extern char *lxc_cmd_get_name(const char *hashed_sock);
308c8a3e 681diff --git a/src/lxc/criu.c b/src/lxc/criu.c
7395ab25 682index d757bef6..64512193 100644
308c8a3e
WB
683--- a/src/lxc/criu.c
684+++ b/src/lxc/criu.c
ade16ee6 685@@ -283,7 +283,7 @@ static void exec_criu(struct criu_opts *opts)
07288e64
WB
686 } else {
687 const char *p;
688
689- p = cgroup_get_cgroup(opts->handler, controllers[0]);
690+ p = cgroup_get_cgroup(opts->handler, controllers[0], false);
691 if (!p) {
692 ERROR("failed to get cgroup path for %s", controllers[0]);
693 goto err;
7395ab25 694@@ -805,7 +805,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
308c8a3e
WB
695 goto out_fini_handler;
696 }
697
698- if (!cgroup_create(handler)) {
699+ if (!cgroup_create(handler, false)) {
700 ERROR("failed creating groups");
701 goto out_fini_handler;
702 }
703diff --git a/src/lxc/start.c b/src/lxc/start.c
7395ab25 704index bca7f8eb..2d7df0e7 100644
308c8a3e
WB
705--- a/src/lxc/start.c
706+++ b/src/lxc/start.c
7395ab25 707@@ -1115,7 +1115,7 @@ static int lxc_spawn(struct lxc_handler *handler)
308c8a3e
WB
708
709 cgroups_connected = true;
710
711- if (!cgroup_create(handler)) {
712+ if (!cgroup_create(handler, false)) {
da73bbc6 713 ERROR("Failed creating cgroups.");
308c8a3e
WB
714 goto out_delete_net;
715 }
7395ab25 716@@ -1202,10 +1202,10 @@ static int lxc_spawn(struct lxc_handler *handler)
308c8a3e
WB
717 goto out_delete_net;
718 }
719
720- if (!cgroup_enter(handler))
721+ if (!cgroup_enter(handler, false))
722 goto out_delete_net;
723
724- if (!cgroup_chown(handler))
725+ if (!cgroup_chown(handler, false))
726 goto out_delete_net;
727
728 if (failed_before_rename)
7395ab25 729@@ -1248,6 +1248,21 @@ static int lxc_spawn(struct lxc_handler *handler)
308c8a3e
WB
730 goto out_delete_net;
731 }
732
733+ if (cgns_supported()) {
734+ if (!cgroup_create(handler, true)) {
735+ ERROR("failed to create inner cgroup separation layer");
736+ goto out_delete_net;
737+ }
738+ if (!cgroup_enter(handler, true)) {
739+ ERROR("failed to enter inner cgroup separation layer");
740+ goto out_delete_net;
741+ }
742+ if (!cgroup_chown(handler, true)) {
743+ ERROR("failed chown inner cgroup separation layer");
744+ goto out_delete_net;
745+ }
746+ }
747+
748 cgroup_disconnect();
749 cgroups_connected = false;
750
751--
7395ab25 7522.11.0
308c8a3e 753