]>
Commit | Line | Data |
---|---|---|
7395ab25 | 1 | From 5ceb26ec765edb81aba25b9db4fc5ede0d7a0375 Mon Sep 17 00:00:00 2001 |
308c8a3e WB |
2 | From: Wolfgang Bumiller <w.bumiller@proxmox.com> |
3 | Date: Tue, 15 Nov 2016 09:20:24 +0100 | |
7395ab25 | 4 | Subject: [PATCH 5/8] separate the limiting from the namespaced cgroup root |
308c8a3e WB |
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 | --- | |
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 | |
28 | diff --git a/src/lxc/cgroups/cgfs.c b/src/lxc/cgroups/cgfs.c | |
7395ab25 | 29 | index 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 | ||
98 | diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c | |
7395ab25 | 99 | index 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 | 314 | diff --git a/src/lxc/cgroups/cgmanager.c b/src/lxc/cgroups/cgmanager.c |
7395ab25 | 315 | index 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()) { | |
384 | diff --git a/src/lxc/cgroups/cgroup.c b/src/lxc/cgroups/cgroup.c | |
7395ab25 | 385 | index 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 | ||
440 | diff --git a/src/lxc/cgroups/cgroup.h b/src/lxc/cgroups/cgroup.h | |
7395ab25 | 441 | index 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); | |
499 | diff --git a/src/lxc/commands.c b/src/lxc/commands.c | |
7395ab25 | 500 | index 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) { | |
668 | diff --git a/src/lxc/commands.h b/src/lxc/commands.h | |
7395ab25 | 669 | index 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 | 681 | diff --git a/src/lxc/criu.c b/src/lxc/criu.c |
7395ab25 | 682 | index 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 | } | |
703 | diff --git a/src/lxc/start.c b/src/lxc/start.c | |
7395ab25 | 704 | index 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 | 752 | 2.11.0 |
308c8a3e | 753 |