]> git.proxmox.com Git - lxc.git/blame - debian/patches/0001-separate-the-limiting-from-the-namespaced-cgroup-roo.patch
restore backward cgroup namespace backward compatibility
[lxc.git] / debian / patches / 0001-separate-the-limiting-from-the-namespaced-cgroup-roo.patch
CommitLineData
d7bc4f06 1From 386f5fcf2e31efa2d7a379bf20f4aef5f96bf116 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
4Subject: [PATCH 1/2] separate the limiting from the namespaced cgroup root
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 ++++++--
d7bc4f06 18 src/lxc/cgroups/cgfsng.c | 80 +++++++++++++++++++++++++++------
07288e64
WB
19 src/lxc/cgroups/cgmanager.c | 19 ++++++--
20 src/lxc/cgroups/cgroup.c | 16 +++----
21 src/lxc/cgroups/cgroup.h | 16 +++----
d7bc4f06 22 src/lxc/commands.c | 107 +++++++++++++++++++++++++++++++++++---------
07288e64
WB
23 src/lxc/commands.h | 3 ++
24 src/lxc/criu.c | 4 +-
25 src/lxc/start.c | 21 +++++++--
d7bc4f06 26 9 files changed, 223 insertions(+), 62 deletions(-)
308c8a3e
WB
27
28diff --git a/src/lxc/cgroups/cgfs.c b/src/lxc/cgroups/cgfs.c
07288e64 29index 8499200..b78b78d 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
07288e64 99index 2b772e2..c1cc3ad 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 /*
110@@ -814,6 +815,7 @@ static void add_controller(char **clist, char *mountpoint, char *base_cgroup)
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;
118@@ -1286,6 +1288,8 @@ static void cgfsng_destroy(void *hdata, struct lxc_conf *conf)
119 free(h->fullcgpath);
120 h->fullcgpath = NULL;
121 }
122+ free(h->innercgpath);
123+ h->innercgpath = NULL;
124 }
125 }
126
127@@ -1299,18 +1303,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) {
139+ path = must_make_path(h->fullcgpath, "ns", 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)
07288e64 159@@ -1325,7 +1336,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;
07288e64 169@@ -1335,9 +1347,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) {
07288e64 185@@ -1358,7 +1376,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);
07288e64 194@@ -1378,7 +1396,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;
203+ char *cgname = must_make_path(d->container_cgroup, "ns", NULL);
204+ for (i = 0; hierarchies[i]; i++) {
205+ if (!create_path_for_hierarchy(hierarchies[i], cgname, true)) {
206+ SYSERROR("Failed to create %s/ns: %s", hierarchies[i]->fullcgpath, strerror(errno));
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;
07288e64 220@@ -1388,7 +1423,12 @@ 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)
227+ fullpath = must_make_path(hierarchies[i]->fullcgpath, "ns",
228+ "cgroup.procs", NULL);
229+ else
230+ fullpath = must_make_path(hierarchies[i]->fullcgpath,
231 "cgroup.procs", NULL);
232 if (lxc_write_to_file(fullpath, pidstr, len, false) != 0) {
233 SYSERROR("Failed to enter %s", fullpath);
07288e64 234@@ -1404,6 +1444,7 @@ static bool cgfsng_enter(void *hdata, pid_t pid)
308c8a3e
WB
235 struct chown_data {
236 struct cgfsng_handler_data *d;
237 uid_t origuid; // target uid in parent namespace
238+ bool inner;
239 };
240
241 /*
07288e64 242@@ -1432,13 +1473,20 @@ static int chown_cgroup_wrapper(void *data)
308c8a3e
WB
243 for (i = 0; hierarchies[i]; i++) {
244 char *fullpath, *path = hierarchies[i]->fullcgpath;
245
246+ if (arg->inner)
247+ path = must_make_path(path, "ns", NULL);
248+
249 if (chown(path, destuid, 0) < 0) {
250 SYSERROR("Error chowning %s to %d", path, (int) destuid);
251+ if (arg->inner)
252+ free(path);
253 return -1;
254 }
255
256 if (chmod(path, 0775) < 0) {
257 SYSERROR("Error chmoding %s", path);
258+ if (arg->inner)
259+ free(path);
260 return -1;
261 }
262
07288e64 263@@ -1462,12 +1510,14 @@ static int chown_cgroup_wrapper(void *data)
308c8a3e
WB
264 if (chmod(fullpath, 0664) < 0)
265 WARN("Error chmoding %s: %m", path);
266 free(fullpath);
267+
268+ free(path);
269 }
270
271 return 0;
272 }
273
274-static bool cgfsns_chown(void *hdata, struct lxc_conf *conf)
275+static bool cgfsns_chown(void *hdata, struct lxc_conf *conf, bool inner)
276 {
277 struct cgfsng_handler_data *d = hdata;
278 struct chown_data wrap;
07288e64 279@@ -1480,6 +1530,7 @@ static bool cgfsns_chown(void *hdata, struct lxc_conf *conf)
308c8a3e
WB
280
281 wrap.d = d;
282 wrap.origuid = geteuid();
283+ wrap.inner = inner;
284
285 if (userns_exec_1(conf, chown_cgroup_wrapper, &wrap) < 0) {
286 ERROR("Error requesting cgroup chown in new namespace");
07288e64
WB
287@@ -1774,12 +1825,15 @@ static bool cgfsng_unfreeze(void *hdata)
288 return true;
289 }
290
291-static const char *cgfsng_get_cgroup(void *hdata, const char *subsystem)
292+static const char *cgfsng_get_cgroup(void *hdata, const char *subsystem, bool inner)
293 {
294 struct hierarchy *h = get_hierarchy(subsystem);
295 if (!h)
296 return NULL;
297
298+ if (inner && h->innercgpath)
299+ return h->innercgpath + strlen(h->mountpoint);
300+
301 return h->fullcgpath ? h->fullcgpath + strlen(h->mountpoint) : NULL;
302 }
303
304@@ -1814,7 +1868,7 @@ static bool cgfsng_attach(const char *name, const char *lxcpath, pid_t pid)
305 char *path, *fullpath;
306 struct hierarchy *h = hierarchies[i];
307
308- path = lxc_cmd_get_cgroup_path(name, lxcpath, h->controllers[0]);
309+ path = lxc_cmd_get_attach_cgroup_path(name, lxcpath, h->controllers[0]);
310 if (!path) // not running
311 continue;
312
308c8a3e 313diff --git a/src/lxc/cgroups/cgmanager.c b/src/lxc/cgroups/cgmanager.c
07288e64 314index f2756b0..ac966b6 100644
308c8a3e
WB
315--- a/src/lxc/cgroups/cgmanager.c
316+++ b/src/lxc/cgroups/cgmanager.c
317@@ -609,7 +609,7 @@ static inline void cleanup_cgroups(char *path)
318 cgm_remove_cgroup(slist[i], path);
319 }
320
321-static inline bool cgm_create(void *hdata)
322+static inline bool cgm_create(void *hdata, bool inner)
323 {
324 struct cgm_data *d = hdata;
325 char **slist = subsystems;
326@@ -617,6 +617,9 @@ static inline bool cgm_create(void *hdata)
327 int32_t existed;
328 char result[MAXPATHLEN], *tmp, *cgroup_path;
329
330+ if (inner)
331+ return true;
332+
333 if (!d)
334 return false;
335 // XXX we should send a hint to the cgmanager that when these
336@@ -709,13 +712,16 @@ static bool lxc_cgmanager_enter(pid_t pid, const char *controller,
337 return true;
338 }
339
340-static inline bool cgm_enter(void *hdata, pid_t pid)
341+static inline bool cgm_enter(void *hdata, pid_t pid, bool inner)
342 {
343 struct cgm_data *d = hdata;
344 char **slist = subsystems;
345 bool ret = false;
346 int i;
347
348+ if (inner)
349+ return true;
350+
351 if (!d || !d->cgroup_path)
352 return false;
353
07288e64
WB
354@@ -737,10 +743,12 @@ out:
355 return ret;
356 }
357
358-static const char *cgm_get_cgroup(void *hdata, const char *subsystem)
359+static const char *cgm_get_cgroup(void *hdata, const char *subsystem, bool inner)
360 {
361 struct cgm_data *d = hdata;
362
363+ (void)inner;
364+
365 if (!d || !d->cgroup_path)
366 return NULL;
367 return d->cgroup_path;
368@@ -1541,10 +1549,13 @@ out:
308c8a3e
WB
369 return ret;
370 }
371
372-static bool cgm_chown(void *hdata, struct lxc_conf *conf)
373+static bool cgm_chown(void *hdata, struct lxc_conf *conf, bool inner)
374 {
375 struct cgm_data *d = hdata;
376
377+ if (inner)
378+ return true;
379+
380 if (!d || !d->cgroup_path)
381 return false;
382 if (!cgm_dbus_connect()) {
383diff --git a/src/lxc/cgroups/cgroup.c b/src/lxc/cgroups/cgroup.c
07288e64 384index 78472d4..4d26e72 100644
308c8a3e
WB
385--- a/src/lxc/cgroups/cgroup.c
386+++ b/src/lxc/cgroups/cgroup.c
387@@ -80,10 +80,10 @@ void cgroup_destroy(struct lxc_handler *handler)
388 }
389
390 /* Create the container cgroups for all requested controllers */
391-bool cgroup_create(struct lxc_handler *handler)
392+bool cgroup_create(struct lxc_handler *handler, bool inner)
393 {
394 if (ops)
395- return ops->create(handler->cgroup_data);
396+ return ops->create(handler->cgroup_data, inner);
397 return false;
398 }
399
400@@ -91,10 +91,10 @@ bool cgroup_create(struct lxc_handler *handler)
401 * Enter the container init into its new cgroups for all
402 * requested controllers
403 */
404-bool cgroup_enter(struct lxc_handler *handler)
405+bool cgroup_enter(struct lxc_handler *handler, bool inner)
406 {
407 if (ops)
408- return ops->enter(handler->cgroup_data, handler->pid);
409+ return ops->enter(handler->cgroup_data, handler->pid, inner);
410 return false;
411 }
412
07288e64
WB
413@@ -105,10 +105,10 @@ bool cgroup_create_legacy(struct lxc_handler *handler)
414 return true;
415 }
416
417-const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem)
418+const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem, bool inner)
419 {
420 if (ops)
421- return ops->get_cgroup(handler->cgroup_data, subsystem);
422+ return ops->get_cgroup(handler->cgroup_data, subsystem, inner);
423 return NULL;
424 }
425
308c8a3e
WB
426@@ -150,10 +150,10 @@ bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices)
427 return false;
428 }
429
430-bool cgroup_chown(struct lxc_handler *handler)
431+bool cgroup_chown(struct lxc_handler *handler, bool inner)
432 {
433 if (ops && ops->chown)
434- return ops->chown(handler->cgroup_data, handler->conf);
435+ return ops->chown(handler->cgroup_data, handler->conf, inner);
436 return true;
437 }
438
439diff --git a/src/lxc/cgroups/cgroup.h b/src/lxc/cgroups/cgroup.h
07288e64 440index 11b251e..3b5cad9 100644
308c8a3e
WB
441--- a/src/lxc/cgroups/cgroup.h
442+++ b/src/lxc/cgroups/cgroup.h
07288e64 443@@ -43,10 +43,10 @@ struct cgroup_ops {
308c8a3e
WB
444
445 void *(*init)(const char *name);
446 void (*destroy)(void *hdata, struct lxc_conf *conf);
447- bool (*create)(void *hdata);
448- bool (*enter)(void *hdata, pid_t pid);
449+ bool (*create)(void *hdata, bool inner);
450+ bool (*enter)(void *hdata, pid_t pid, bool inner);
451 bool (*create_legacy)(void *hdata, pid_t pid);
07288e64
WB
452- const char *(*get_cgroup)(void *hdata, const char *subsystem);
453+ const char *(*get_cgroup)(void *hdata, const char *subsystem, bool inner);
308c8a3e 454 bool (*escape)();
07288e64
WB
455 int (*num_hierarchies)();
456 bool (*get_hierarchies)(int n, char ***out);
308c8a3e
WB
457@@ -54,7 +54,7 @@ struct cgroup_ops {
458 int (*get)(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
459 bool (*unfreeze)(void *hdata);
460 bool (*setup_limits)(void *hdata, struct lxc_list *cgroup_conf, bool with_devices);
461- bool (*chown)(void *hdata, struct lxc_conf *conf);
462+ bool (*chown)(void *hdata, struct lxc_conf *conf, bool inner);
463 bool (*attach)(const char *name, const char *lxcpath, pid_t pid);
464 bool (*mount_cgroup)(void *hdata, const char *root, int type);
465 int (*nrtasks)(void *hdata);
07288e64 466@@ -66,14 +66,14 @@ extern bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid);
308c8a3e
WB
467 extern bool cgroup_mount(const char *root, struct lxc_handler *handler, int type);
468 extern void cgroup_destroy(struct lxc_handler *handler);
469 extern bool cgroup_init(struct lxc_handler *handler);
470-extern bool cgroup_create(struct lxc_handler *handler);
471+extern bool cgroup_create(struct lxc_handler *handler, bool inner);
472 extern bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices);
473-extern bool cgroup_chown(struct lxc_handler *handler);
474-extern bool cgroup_enter(struct lxc_handler *handler);
475+extern bool cgroup_chown(struct lxc_handler *handler, bool inner);
476+extern bool cgroup_enter(struct lxc_handler *handler, bool inner);
477 extern void cgroup_cleanup(struct lxc_handler *handler);
478 extern bool cgroup_create_legacy(struct lxc_handler *handler);
479 extern int cgroup_nrtasks(struct lxc_handler *handler);
07288e64
WB
480-extern const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem);
481+extern const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem, bool inner);
482 extern bool cgroup_escape();
483 extern int cgroup_num_hierarchies();
484 extern bool cgroup_get_hierarchies(int i, char ***out);
485diff --git a/src/lxc/commands.c b/src/lxc/commands.c
d7bc4f06 486index b17879b..aeb1e16 100644
07288e64
WB
487--- a/src/lxc/commands.c
488+++ b/src/lxc/commands.c
489@@ -128,15 +128,16 @@ static int fill_sock_name(char *path, int len, const char *name,
490 static const char *lxc_cmd_str(lxc_cmd_t cmd)
491 {
492 static const char * const cmdname[LXC_CMD_MAX] = {
493- [LXC_CMD_CONSOLE] = "console",
494- [LXC_CMD_STOP] = "stop",
495- [LXC_CMD_GET_STATE] = "get_state",
496- [LXC_CMD_GET_INIT_PID] = "get_init_pid",
497- [LXC_CMD_GET_CLONE_FLAGS] = "get_clone_flags",
498- [LXC_CMD_GET_CGROUP] = "get_cgroup",
499- [LXC_CMD_GET_CONFIG_ITEM] = "get_config_item",
500- [LXC_CMD_GET_NAME] = "get_name",
501- [LXC_CMD_GET_LXCPATH] = "get_lxcpath",
502+ [LXC_CMD_CONSOLE] = "console",
503+ [LXC_CMD_STOP] = "stop",
504+ [LXC_CMD_GET_STATE] = "get_state",
505+ [LXC_CMD_GET_INIT_PID] = "get_init_pid",
506+ [LXC_CMD_GET_CLONE_FLAGS] = "get_clone_flags",
507+ [LXC_CMD_GET_CGROUP] = "get_cgroup",
508+ [LXC_CMD_GET_CONFIG_ITEM] = "get_config_item",
509+ [LXC_CMD_GET_NAME] = "get_name",
510+ [LXC_CMD_GET_LXCPATH] = "get_lxcpath",
511+ [LXC_CMD_GET_ATTACH_CGROUP] = "get_attach_cgroup",
512 };
513
514 if (cmd >= LXC_CMD_MAX)
d7bc4f06 515@@ -480,7 +481,72 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
07288e64
WB
516 if (req->datalen < 1)
517 return -1;
518
519- path = cgroup_get_cgroup(handler, req->data);
520+ path = cgroup_get_cgroup(handler, req->data, false);
521+ if (!path)
522+ return -1;
523+ rsp.datalen = strlen(path) + 1,
524+ rsp.data = (char *)path;
525+ rsp.ret = 0;
526+
527+ return lxc_cmd_rsp_send(fd, &rsp);
528+}
529+
530+/*
531+ * lxc_cmd_get_attach_cgroup_path: Calculate a container's inner cgroup path
532+ * for a particular subsystem. This is the cgroup path relative to the root
533+ * of the cgroup filesystem.
534+ *
535+ * @name : name of container to connect to
536+ * @lxcpath : the lxcpath in which the container is running
537+ * @subsystem : the subsystem being asked about
538+ *
539+ * Returns the path on success, NULL on failure. The caller must free() the
540+ * returned path.
541+ */
542+char *lxc_cmd_get_attach_cgroup_path(const char *name, const char *lxcpath,
543+ const char *subsystem)
544+{
545+ int ret, stopped;
546+ struct lxc_cmd_rr cmd = {
547+ .req = {
548+ .cmd = LXC_CMD_GET_ATTACH_CGROUP,
549+ .datalen = strlen(subsystem)+1,
550+ .data = subsystem,
551+ },
552+ };
553+
554+ ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
d7bc4f06
WB
555+ if (!ret) {
556+ cmd.req.cmd = LXC_CMD_GET_CGROUP;
557+ ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
558+ }
07288e64
WB
559+ if (ret < 0)
560+ return NULL;
561+
562+ if (!ret) {
563+ WARN("Container \"%s\" has stopped before sending its state.", name);
564+ return NULL;
565+ }
566+
567+ if (cmd.rsp.ret < 0 || cmd.rsp.datalen < 0) {
568+ ERROR("Command %s failed for container \"%s\": %s.",
569+ lxc_cmd_str(cmd.req.cmd), name, strerror(-cmd.rsp.ret));
570+ return NULL;
571+ }
572+
573+ return cmd.rsp.data;
574+}
575+
576+static int lxc_cmd_get_attach_cgroup_callback(int fd, struct lxc_cmd_req *req,
577+ struct lxc_handler *handler)
578+{
579+ struct lxc_cmd_rsp rsp;
580+ const char *path;
581+
582+ if (req->datalen < 1)
583+ return -1;
584+
585+ path = cgroup_get_cgroup(handler, req->data, true);
586 if (!path)
587 return -1;
588 rsp.datalen = strlen(path) + 1,
d7bc4f06 589@@ -841,16 +907,17 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
07288e64
WB
590 typedef int (*callback)(int, struct lxc_cmd_req *, struct lxc_handler *);
591
592 callback cb[LXC_CMD_MAX] = {
593- [LXC_CMD_CONSOLE] = lxc_cmd_console_callback,
594- [LXC_CMD_CONSOLE_WINCH] = lxc_cmd_console_winch_callback,
595- [LXC_CMD_STOP] = lxc_cmd_stop_callback,
596- [LXC_CMD_GET_STATE] = lxc_cmd_get_state_callback,
597- [LXC_CMD_GET_INIT_PID] = lxc_cmd_get_init_pid_callback,
598- [LXC_CMD_GET_CLONE_FLAGS] = lxc_cmd_get_clone_flags_callback,
599- [LXC_CMD_GET_CGROUP] = lxc_cmd_get_cgroup_callback,
600- [LXC_CMD_GET_CONFIG_ITEM] = lxc_cmd_get_config_item_callback,
601- [LXC_CMD_GET_NAME] = lxc_cmd_get_name_callback,
602- [LXC_CMD_GET_LXCPATH] = lxc_cmd_get_lxcpath_callback,
603+ [LXC_CMD_CONSOLE] = lxc_cmd_console_callback,
604+ [LXC_CMD_CONSOLE_WINCH] = lxc_cmd_console_winch_callback,
605+ [LXC_CMD_STOP] = lxc_cmd_stop_callback,
606+ [LXC_CMD_GET_STATE] = lxc_cmd_get_state_callback,
607+ [LXC_CMD_GET_INIT_PID] = lxc_cmd_get_init_pid_callback,
608+ [LXC_CMD_GET_CLONE_FLAGS] = lxc_cmd_get_clone_flags_callback,
609+ [LXC_CMD_GET_CGROUP] = lxc_cmd_get_cgroup_callback,
610+ [LXC_CMD_GET_CONFIG_ITEM] = lxc_cmd_get_config_item_callback,
611+ [LXC_CMD_GET_NAME] = lxc_cmd_get_name_callback,
612+ [LXC_CMD_GET_LXCPATH] = lxc_cmd_get_lxcpath_callback,
613+ [LXC_CMD_GET_ATTACH_CGROUP] = lxc_cmd_get_attach_cgroup_callback,
614 };
615
616 if (req->cmd >= LXC_CMD_MAX) {
617diff --git a/src/lxc/commands.h b/src/lxc/commands.h
618index 184eefa..bb86e3d 100644
619--- a/src/lxc/commands.h
620+++ b/src/lxc/commands.h
621@@ -43,6 +43,7 @@ typedef enum {
622 LXC_CMD_GET_CONFIG_ITEM,
623 LXC_CMD_GET_NAME,
624 LXC_CMD_GET_LXCPATH,
625+ LXC_CMD_GET_ATTACH_CGROUP,
626 LXC_CMD_MAX,
627 } lxc_cmd_t;
628
629@@ -77,6 +78,8 @@ extern int lxc_cmd_console(const char *name, int *ttynum, int *fd,
630 */
631 extern char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
632 const char *subsystem);
633+extern char *lxc_cmd_get_attach_cgroup_path(const char *name,
634+ const char *lxcpath, const char *subsystem);
635 extern int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath);
636 extern char *lxc_cmd_get_config_item(const char *name, const char *item, const char *lxcpath);
637 extern char *lxc_cmd_get_name(const char *hashed_sock);
308c8a3e 638diff --git a/src/lxc/criu.c b/src/lxc/criu.c
07288e64 639index 125e674..5a9e36b 100644
308c8a3e
WB
640--- a/src/lxc/criu.c
641+++ b/src/lxc/criu.c
07288e64
WB
642@@ -284,7 +284,7 @@ static void exec_criu(struct criu_opts *opts)
643 } else {
644 const char *p;
645
646- p = cgroup_get_cgroup(opts->handler, controllers[0]);
647+ p = cgroup_get_cgroup(opts->handler, controllers[0], false);
648 if (!p) {
649 ERROR("failed to get cgroup path for %s", controllers[0]);
650 goto err;
da73bbc6 651@@ -797,7 +797,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
308c8a3e
WB
652 goto out_fini_handler;
653 }
654
655- if (!cgroup_create(handler)) {
656+ if (!cgroup_create(handler, false)) {
657 ERROR("failed creating groups");
658 goto out_fini_handler;
659 }
660diff --git a/src/lxc/start.c b/src/lxc/start.c
da73bbc6 661index 71206e0..c9d78b7 100644
308c8a3e
WB
662--- a/src/lxc/start.c
663+++ b/src/lxc/start.c
da73bbc6 664@@ -1121,7 +1121,7 @@ static int lxc_spawn(struct lxc_handler *handler)
308c8a3e
WB
665
666 cgroups_connected = true;
667
668- if (!cgroup_create(handler)) {
669+ if (!cgroup_create(handler, false)) {
da73bbc6 670 ERROR("Failed creating cgroups.");
308c8a3e
WB
671 goto out_delete_net;
672 }
da73bbc6 673@@ -1208,10 +1208,10 @@ static int lxc_spawn(struct lxc_handler *handler)
308c8a3e
WB
674 goto out_delete_net;
675 }
676
677- if (!cgroup_enter(handler))
678+ if (!cgroup_enter(handler, false))
679 goto out_delete_net;
680
681- if (!cgroup_chown(handler))
682+ if (!cgroup_chown(handler, false))
683 goto out_delete_net;
684
685 if (failed_before_rename)
da73bbc6 686@@ -1254,6 +1254,21 @@ static int lxc_spawn(struct lxc_handler *handler)
308c8a3e
WB
687 goto out_delete_net;
688 }
689
690+ if (cgns_supported()) {
691+ if (!cgroup_create(handler, true)) {
692+ ERROR("failed to create inner cgroup separation layer");
693+ goto out_delete_net;
694+ }
695+ if (!cgroup_enter(handler, true)) {
696+ ERROR("failed to enter inner cgroup separation layer");
697+ goto out_delete_net;
698+ }
699+ if (!cgroup_chown(handler, true)) {
700+ ERROR("failed chown inner cgroup separation layer");
701+ goto out_delete_net;
702+ }
703+ }
704+
705 cgroup_disconnect();
706 cgroups_connected = false;
707
708--
7092.1.4
710