]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/cgroups/cgfsng.c
Merge pull request #2186 from brauner/2018-02-22/make_confile_reading_thread_safe
[mirror_lxc.git] / src / lxc / cgroups / cgfsng.c
1 /*
2 * lxc: linux Container library
3 *
4 * Copyright © 2016 Canonical Ltd.
5 *
6 * Authors:
7 * Serge Hallyn <serge.hallyn@ubuntu.com>
8 * Christian Brauner <christian.brauner@ubuntu.com>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 /*
26 * cgfs-ng.c: this is a new, simplified implementation of a filesystem
27 * cgroup backend. The original cgfs.c was designed to be as flexible
28 * as possible. It would try to find cgroup filesystems no matter where
29 * or how you had them mounted, and deduce the most usable mount for
30 * each controller.
31 *
32 * This new implementation assumes that cgroup filesystems are mounted
33 * under /sys/fs/cgroup/clist where clist is either the controller, or
34 * a comman-separated list of controllers.
35 */
36
37 #include "config.h"
38
39 #include <ctype.h>
40 #include <dirent.h>
41 #include <errno.h>
42 #include <grp.h>
43 #include <stdint.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <linux/kdev_t.h>
49 #include <linux/types.h>
50 #include <sys/types.h>
51
52 #include "caps.h"
53 #include "cgroup.h"
54 #include "cgroup_utils.h"
55 #include "commands.h"
56 #include "conf.h"
57 #include "log.h"
58 #include "storage/storage.h"
59 #include "utils.h"
60
61 lxc_log_define(lxc_cgfsng, lxc);
62
63 static struct cgroup_ops cgfsng_ops;
64
65 /* A descriptor for a mounted hierarchy
66 *
67 * @controllers
68 * - legacy hierarchy
69 * Either NULL, or a null-terminated list of all the co-mounted controllers.
70 * - unified hierarchy
71 * Either NULL, or a null-terminated list of all enabled controllers.
72 *
73 * @mountpoint
74 * - The mountpoint we will use.
75 * - legacy hierarchy
76 * It will be either /sys/fs/cgroup/controller or
77 * /sys/fs/cgroup/controllerlist.
78 * - unified hierarchy
79 * It will either be /sys/fs/cgroup or /sys/fs/cgroup/<mountpoint-name>
80 * depending on whether this is a hybrid cgroup layout (mix of legacy and
81 * unified hierarchies) or a pure unified cgroup layout.
82 *
83 * @base_cgroup
84 * - The cgroup under which the container cgroup path
85 * is created. This will be either the caller's cgroup (if not root), or
86 * init's cgroup (if root).
87 *
88 * @fullcgpath
89 * - The full path to the containers cgroup.
90 *
91 * @version
92 * - legacy hierarchy
93 * If the hierarchy is a legacy hierarchy this will be set to
94 * CGROUP_SUPER_MAGIC.
95 * - unified hierarchy
96 * If the hierarchy is a legacy hierarchy this will be set to
97 * CGROUP2_SUPER_MAGIC.
98 */
99 struct hierarchy {
100 char **controllers;
101 char *mountpoint;
102 char *base_cgroup;
103 char *fullcgpath;
104 int version;
105 };
106
107 /* The cgroup data which is attached to the lxc_handler.
108 *
109 * @cgroup_pattern
110 * - A copy of lxc.cgroup.pattern.
111 *
112 * @container_cgroup
113 * - If not null, the cgroup which was created for the container. For each
114 * hierarchy, it is created under the @hierarchy->base_cgroup directory.
115 * Relative to the base_cgroup it is the same for all hierarchies.
116 *
117 * @name
118 * - The name of the container.
119 *
120 * @cgroup_meta
121 * - A copy of the container's cgroup information. This overrides
122 * @cgroup_pattern.
123 *
124 * @cgroup_layout
125 * - What cgroup layout the container is running with.
126 * - CGROUP_LAYOUT_UNKNOWN
127 * The cgroup layout could not be determined. This should be treated as an
128 * error condition.
129 * - CGROUP_LAYOUT_LEGACY
130 * The container is running with all controllers mounted into legacy cgroup
131 * hierarchies.
132 * - CGROUP_LAYOUT_HYBRID
133 * The container is running with at least one controller mounted into a
134 * legacy cgroup hierarchy and a mountpoint for the unified hierarchy. The
135 * unified hierarchy can be empty (no controllers enabled) or non-empty
136 * (controllers enabled).
137 * - CGROUP_LAYOUT_UNIFIED
138 * The container is running on a pure unified cgroup hierarchy. The unified
139 * hierarchy can be empty (no controllers enabled) or non-empty (controllers
140 * enabled).
141 */
142 struct cgfsng_handler_data {
143 char *cgroup_pattern;
144 char *container_cgroup; /* cgroup we created for the container */
145 char *name; /* container name */
146 /* per-container cgroup information */
147 struct lxc_cgroup cgroup_meta;
148 cgroup_layout_t cgroup_layout;
149 };
150
151 /* @hierarchies
152 * - A NULL-terminated array of struct hierarchy, one per legacy hierarchy. No
153 * duplicates. First sufficient, writeable mounted hierarchy wins.
154 */
155 struct hierarchy **hierarchies;
156 /* Pointer to the unified hierarchy in the null terminated list @hierarchies.
157 * This is merely a convenience for hybrid cgroup layouts to easily retrieve the
158 * unified hierarchy without iterating throught @hierarchies.
159 */
160 struct hierarchy *unified;
161 /*
162 * @cgroup_layout
163 * - What cgroup layout the container is running with.
164 * - CGROUP_LAYOUT_UNKNOWN
165 * The cgroup layout could not be determined. This should be treated as an
166 * error condition.
167 * - CGROUP_LAYOUT_LEGACY
168 * The container is running with all controllers mounted into legacy cgroup
169 * hierarchies.
170 * - CGROUP_LAYOUT_HYBRID
171 * The container is running with at least one controller mounted into a
172 * legacy cgroup hierarchy and a mountpoint for the unified hierarchy. The
173 * unified hierarchy can be empty (no controllers enabled) or non-empty
174 * (controllers enabled).
175 * - CGROUP_LAYOUT_UNIFIED
176 * The container is running on a pure unified cgroup hierarchy. The unified
177 * hierarchy can be empty (no controllers enabled) or non-empty (controllers
178 * enabled).
179 */
180 cgroup_layout_t cgroup_layout;
181 /* What controllers is the container supposed to use. */
182 char *cgroup_use;
183
184 /* @lxc_cgfsng_debug
185 * - Whether to print debug info to stdout for the cgfsng driver.
186 */
187 static bool lxc_cgfsng_debug;
188
189 #define CGFSNG_DEBUG(format, ...) \
190 do { \
191 if (lxc_cgfsng_debug) \
192 printf("cgfsng: " format, ##__VA_ARGS__); \
193 } while (0)
194
195 static void free_string_list(char **clist)
196 {
197 int i;
198
199 if (!clist)
200 return;
201
202 for (i = 0; clist[i]; i++)
203 free(clist[i]);
204
205 free(clist);
206 }
207
208 /* Allocate a pointer, do not fail. */
209 static void *must_alloc(size_t sz)
210 {
211 return must_realloc(NULL, sz);
212 }
213
214 /* Given a pointer to a null-terminated array of pointers, realloc to add one
215 * entry, and point the new entry to NULL. Do not fail. Return the index to the
216 * second-to-last entry - that is, the one which is now available for use
217 * (keeping the list null-terminated).
218 */
219 static int append_null_to_list(void ***list)
220 {
221 int newentry = 0;
222
223 if (*list)
224 for (; (*list)[newentry]; newentry++)
225 ;
226
227 *list = must_realloc(*list, (newentry + 2) * sizeof(void **));
228 (*list)[newentry + 1] = NULL;
229 return newentry;
230 }
231
232 /* Given a null-terminated array of strings, check whether @entry is one of the
233 * strings.
234 */
235 static bool string_in_list(char **list, const char *entry)
236 {
237 int i;
238
239 if (!list)
240 return false;
241
242 for (i = 0; list[i]; i++)
243 if (strcmp(list[i], entry) == 0)
244 return true;
245
246 return false;
247 }
248
249 /* Return a copy of @entry prepending "name=", i.e. turn "systemd" into
250 * "name=systemd". Do not fail.
251 */
252 static char *cg_legacy_must_prefix_named(char *entry)
253 {
254 size_t len;
255 char *prefixed;
256
257 len = strlen(entry);
258 prefixed = must_alloc(len + 6);
259
260 memcpy(prefixed, "name=", sizeof("name=") - 1);
261 memcpy(prefixed + sizeof("name=") - 1, entry, len);
262 prefixed[len + 5] = '\0';
263 return prefixed;
264 }
265
266 /* Append an entry to the clist. Do not fail. @clist must be NULL the first time
267 * we are called.
268 *
269 * We also handle named subsystems here. Any controller which is not a kernel
270 * subsystem, we prefix "name=". Any which is both a kernel and named subsystem,
271 * we refuse to use because we're not sure which we have here.
272 * (TODO: We could work around this in some cases by just remounting to be
273 * unambiguous, or by comparing mountpoint contents with current cgroup.)
274 *
275 * The last entry will always be NULL.
276 */
277 static void must_append_controller(char **klist, char **nlist, char ***clist,
278 char *entry)
279 {
280 int newentry;
281 char *copy;
282
283 if (string_in_list(klist, entry) && string_in_list(nlist, entry)) {
284 ERROR("Refusing to use ambiguous controller \"%s\"", entry);
285 ERROR("It is both a named and kernel subsystem");
286 return;
287 }
288
289 newentry = append_null_to_list((void ***)clist);
290
291 if (strncmp(entry, "name=", 5) == 0)
292 copy = must_copy_string(entry);
293 else if (string_in_list(klist, entry))
294 copy = must_copy_string(entry);
295 else
296 copy = cg_legacy_must_prefix_named(entry);
297
298 (*clist)[newentry] = copy;
299 }
300
301 static void free_handler_data(struct cgfsng_handler_data *d)
302 {
303 free(d->cgroup_pattern);
304 free(d->container_cgroup);
305 free(d->name);
306 if (d->cgroup_meta.dir)
307 free(d->cgroup_meta.dir);
308 if (d->cgroup_meta.controllers)
309 free(d->cgroup_meta.controllers);
310 free(d);
311 }
312
313 /* Given a handler's cgroup data, return the struct hierarchy for the controller
314 * @c, or NULL if there is none.
315 */
316 struct hierarchy *get_hierarchy(const char *c)
317 {
318 int i;
319
320 if (!hierarchies)
321 return NULL;
322
323 for (i = 0; hierarchies[i]; i++) {
324 if (!c) {
325 /* This is the empty unified hierarchy. */
326 if (hierarchies[i]->controllers &&
327 !hierarchies[i]->controllers[0])
328 return hierarchies[i];
329
330 continue;
331 }
332
333 if (string_in_list(hierarchies[i]->controllers, c))
334 return hierarchies[i];
335 }
336
337 return NULL;
338 }
339
340 #define BATCH_SIZE 50
341 static void batch_realloc(char **mem, size_t oldlen, size_t newlen)
342 {
343 int newbatches = (newlen / BATCH_SIZE) + 1;
344 int oldbatches = (oldlen / BATCH_SIZE) + 1;
345
346 if (!*mem || newbatches > oldbatches) {
347 *mem = must_realloc(*mem, newbatches * BATCH_SIZE);
348 }
349 }
350
351 static void append_line(char **dest, size_t oldlen, char *new, size_t newlen)
352 {
353 size_t full = oldlen + newlen;
354
355 batch_realloc(dest, oldlen, full + 1);
356
357 memcpy(*dest + oldlen, new, newlen + 1);
358 }
359
360 /* Slurp in a whole file */
361 static char *read_file(const char *fnam)
362 {
363 FILE *f;
364 char *line = NULL, *buf = NULL;
365 size_t len = 0, fulllen = 0;
366 int linelen;
367
368 f = fopen(fnam, "r");
369 if (!f)
370 return NULL;
371 while ((linelen = getline(&line, &len, f)) != -1) {
372 append_line(&buf, fulllen, line, linelen);
373 fulllen += linelen;
374 }
375 fclose(f);
376 free(line);
377 return buf;
378 }
379
380 /* Taken over modified from the kernel sources. */
381 #define NBITS 32 /* bits in uint32_t */
382 #define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d))
383 #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, NBITS)
384
385 static void set_bit(unsigned bit, uint32_t *bitarr)
386 {
387 bitarr[bit / NBITS] |= (1 << (bit % NBITS));
388 }
389
390 static void clear_bit(unsigned bit, uint32_t *bitarr)
391 {
392 bitarr[bit / NBITS] &= ~(1 << (bit % NBITS));
393 }
394
395 static bool is_set(unsigned bit, uint32_t *bitarr)
396 {
397 return (bitarr[bit / NBITS] & (1 << (bit % NBITS))) != 0;
398 }
399
400 /* Create cpumask from cpulist aka turn:
401 *
402 * 0,2-3
403 *
404 * into bit array
405 *
406 * 1 0 1 1
407 */
408 static uint32_t *lxc_cpumask(char *buf, size_t nbits)
409 {
410 char *token;
411 size_t arrlen;
412 uint32_t *bitarr;
413 char *saveptr = NULL;
414
415 arrlen = BITS_TO_LONGS(nbits);
416 bitarr = calloc(arrlen, sizeof(uint32_t));
417 if (!bitarr)
418 return NULL;
419
420 for (; (token = strtok_r(buf, ",", &saveptr)); buf = NULL) {
421 errno = 0;
422 unsigned end, start;
423 char *range;
424
425 start = strtoul(token, NULL, 0);
426 end = start;
427 range = strchr(token, '-');
428 if (range)
429 end = strtoul(range + 1, NULL, 0);
430
431 if (!(start <= end)) {
432 free(bitarr);
433 return NULL;
434 }
435
436 if (end >= nbits) {
437 free(bitarr);
438 return NULL;
439 }
440
441 while (start <= end)
442 set_bit(start++, bitarr);
443 }
444
445 return bitarr;
446 }
447
448 /* Turn cpumask into simple, comma-separated cpulist. */
449 static char *lxc_cpumask_to_cpulist(uint32_t *bitarr, size_t nbits)
450 {
451 int ret;
452 size_t i;
453 char **cpulist = NULL;
454 char numstr[LXC_NUMSTRLEN64] = {0};
455
456 for (i = 0; i <= nbits; i++) {
457 if (!is_set(i, bitarr))
458 continue;
459
460 ret = snprintf(numstr, LXC_NUMSTRLEN64, "%zu", i);
461 if (ret < 0 || (size_t)ret >= LXC_NUMSTRLEN64) {
462 lxc_free_array((void **)cpulist, free);
463 return NULL;
464 }
465
466 ret = lxc_append_string(&cpulist, numstr);
467 if (ret < 0) {
468 lxc_free_array((void **)cpulist, free);
469 return NULL;
470 }
471 }
472
473 if (!cpulist)
474 return NULL;
475
476 return lxc_string_join(",", (const char **)cpulist, false);
477 }
478
479 static ssize_t get_max_cpus(char *cpulist)
480 {
481 char *c1, *c2;
482 char *maxcpus = cpulist;
483 size_t cpus = 0;
484
485 c1 = strrchr(maxcpus, ',');
486 if (c1)
487 c1++;
488
489 c2 = strrchr(maxcpus, '-');
490 if (c2)
491 c2++;
492
493 if (!c1 && !c2)
494 c1 = maxcpus;
495 else if (c1 > c2)
496 c2 = c1;
497 else if (c1 < c2)
498 c1 = c2;
499 else if (!c1 && c2)
500 c1 = c2;
501
502 errno = 0;
503 cpus = strtoul(c1, NULL, 0);
504 if (errno != 0)
505 return -1;
506
507 return cpus;
508 }
509
510 #define __ISOL_CPUS "/sys/devices/system/cpu/isolated"
511 static bool cg_legacy_filter_and_set_cpus(char *path, bool am_initialized)
512 {
513 int ret;
514 ssize_t i;
515 char *lastslash, *fpath, oldv;
516 ssize_t maxisol = 0, maxposs = 0;
517 char *cpulist = NULL, *isolcpus = NULL, *posscpus = NULL;
518 uint32_t *isolmask = NULL, *possmask = NULL;
519 bool bret = false, flipped_bit = false;
520
521 lastslash = strrchr(path, '/');
522 if (!lastslash) {
523 ERROR("Failed to detect \"/\" in \"%s\"", path);
524 return bret;
525 }
526 oldv = *lastslash;
527 *lastslash = '\0';
528 fpath = must_make_path(path, "cpuset.cpus", NULL);
529 posscpus = read_file(fpath);
530 if (!posscpus) {
531 SYSERROR("Failed to read file \"%s\"", fpath);
532 goto on_error;
533 }
534
535 /* Get maximum number of cpus found in possible cpuset. */
536 maxposs = get_max_cpus(posscpus);
537 if (maxposs < 0)
538 goto on_error;
539
540 if (!file_exists(__ISOL_CPUS)) {
541 /* This system doesn't expose isolated cpus. */
542 DEBUG("The path \""__ISOL_CPUS"\" to read isolated cpus from does not exist");
543 cpulist = posscpus;
544 /* No isolated cpus but we weren't already initialized by
545 * someone. We should simply copy the parents cpuset.cpus
546 * values.
547 */
548 if (!am_initialized) {
549 DEBUG("Copying cpu settings of parent cgroup");
550 goto copy_parent;
551 }
552 /* No isolated cpus but we were already initialized by someone.
553 * Nothing more to do for us.
554 */
555 goto on_success;
556 }
557
558 isolcpus = read_file(__ISOL_CPUS);
559 if (!isolcpus) {
560 SYSERROR("Failed to read file \""__ISOL_CPUS"\"");
561 goto on_error;
562 }
563 if (!isdigit(isolcpus[0])) {
564 TRACE("No isolated cpus detected");
565 cpulist = posscpus;
566 /* No isolated cpus but we weren't already initialized by
567 * someone. We should simply copy the parents cpuset.cpus
568 * values.
569 */
570 if (!am_initialized) {
571 DEBUG("Copying cpu settings of parent cgroup");
572 goto copy_parent;
573 }
574 /* No isolated cpus but we were already initialized by someone.
575 * Nothing more to do for us.
576 */
577 goto on_success;
578 }
579
580 /* Get maximum number of cpus found in isolated cpuset. */
581 maxisol = get_max_cpus(isolcpus);
582 if (maxisol < 0)
583 goto on_error;
584
585 if (maxposs < maxisol)
586 maxposs = maxisol;
587 maxposs++;
588
589 possmask = lxc_cpumask(posscpus, maxposs);
590 if (!possmask) {
591 ERROR("Failed to create cpumask for possible cpus");
592 goto on_error;
593 }
594
595 isolmask = lxc_cpumask(isolcpus, maxposs);
596 if (!isolmask) {
597 ERROR("Failed to create cpumask for isolated cpus");
598 goto on_error;
599 }
600
601 for (i = 0; i <= maxposs; i++) {
602 if (!is_set(i, isolmask) || !is_set(i, possmask))
603 continue;
604
605 flipped_bit = true;
606 clear_bit(i, possmask);
607 }
608
609 if (!flipped_bit) {
610 DEBUG("No isolated cpus present in cpuset");
611 goto on_success;
612 }
613 DEBUG("Removed isolated cpus from cpuset");
614
615 cpulist = lxc_cpumask_to_cpulist(possmask, maxposs);
616 if (!cpulist) {
617 ERROR("Failed to create cpu list");
618 goto on_error;
619 }
620
621 copy_parent:
622 *lastslash = oldv;
623 free(fpath);
624 fpath = must_make_path(path, "cpuset.cpus", NULL);
625 ret = lxc_write_to_file(fpath, cpulist, strlen(cpulist), false);
626 if (ret < 0) {
627 SYSERROR("Failed to write cpu list to \"%s\"", fpath);
628 goto on_error;
629 }
630
631 on_success:
632 bret = true;
633
634 on_error:
635 free(fpath);
636
637 free(isolcpus);
638 free(isolmask);
639
640 if (posscpus != cpulist)
641 free(posscpus);
642 free(possmask);
643
644 free(cpulist);
645 return bret;
646 }
647
648 /* Copy contents of parent(@path)/@file to @path/@file */
649 static bool copy_parent_file(char *path, char *file)
650 {
651 int ret;
652 char *fpath, *lastslash, oldv;
653 int len = 0;
654 char *value = NULL;
655
656 lastslash = strrchr(path, '/');
657 if (!lastslash) {
658 ERROR("Failed to detect \"/\" in \"%s\"", path);
659 return false;
660 }
661 oldv = *lastslash;
662 *lastslash = '\0';
663 fpath = must_make_path(path, file, NULL);
664 len = lxc_read_from_file(fpath, NULL, 0);
665 if (len <= 0)
666 goto on_error;
667
668 value = must_alloc(len + 1);
669 ret = lxc_read_from_file(fpath, value, len);
670 if (ret != len)
671 goto on_error;
672 free(fpath);
673
674 *lastslash = oldv;
675 fpath = must_make_path(path, file, NULL);
676 ret = lxc_write_to_file(fpath, value, len, false);
677 if (ret < 0)
678 SYSERROR("Failed to write \"%s\" to file \"%s\"", value, fpath);
679 free(fpath);
680 free(value);
681 return ret >= 0;
682
683 on_error:
684 SYSERROR("Failed to read file \"%s\"", fpath);
685 free(fpath);
686 free(value);
687 return false;
688 }
689
690 /* Initialize the cpuset hierarchy in first directory of @gname and set
691 * cgroup.clone_children so that children inherit settings. Since the
692 * h->base_path is populated by init or ourselves, we know it is already
693 * initialized.
694 */
695 static bool cg_legacy_handle_cpuset_hierarchy(struct hierarchy *h, char *cgname)
696 {
697 int ret;
698 char v;
699 char *cgpath, *clonechildrenpath, *slash;
700
701 if (!string_in_list(h->controllers, "cpuset"))
702 return true;
703
704 if (*cgname == '/')
705 cgname++;
706 slash = strchr(cgname, '/');
707 if (slash)
708 *slash = '\0';
709
710 cgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
711 if (slash)
712 *slash = '/';
713
714 ret = mkdir(cgpath, 0755);
715 if (ret < 0) {
716 if (errno != EEXIST) {
717 SYSERROR("Failed to create directory \"%s\"", cgpath);
718 free(cgpath);
719 return false;
720 }
721 }
722
723 clonechildrenpath =
724 must_make_path(cgpath, "cgroup.clone_children", NULL);
725 /* unified hierarchy doesn't have clone_children */
726 if (!file_exists(clonechildrenpath)) {
727 free(clonechildrenpath);
728 free(cgpath);
729 return true;
730 }
731
732 ret = lxc_read_from_file(clonechildrenpath, &v, 1);
733 if (ret < 0) {
734 SYSERROR("Failed to read file \"%s\"", clonechildrenpath);
735 free(clonechildrenpath);
736 free(cgpath);
737 return false;
738 }
739
740 /* Make sure any isolated cpus are removed from cpuset.cpus. */
741 if (!cg_legacy_filter_and_set_cpus(cgpath, v == '1')) {
742 SYSERROR("Failed to remove isolated cpus");
743 free(clonechildrenpath);
744 free(cgpath);
745 return false;
746 }
747
748 /* Already set for us by someone else. */
749 if (v == '1') {
750 DEBUG("\"cgroup.clone_children\" was already set to \"1\"");
751 free(clonechildrenpath);
752 free(cgpath);
753 return true;
754 }
755
756 /* copy parent's settings */
757 if (!copy_parent_file(cgpath, "cpuset.mems")) {
758 SYSERROR("Failed to copy \"cpuset.mems\" settings");
759 free(cgpath);
760 free(clonechildrenpath);
761 return false;
762 }
763 free(cgpath);
764
765 ret = lxc_write_to_file(clonechildrenpath, "1", 1, false);
766 if (ret < 0) {
767 /* Set clone_children so children inherit our settings */
768 SYSERROR("Failed to write 1 to \"%s\"", clonechildrenpath);
769 free(clonechildrenpath);
770 return false;
771 }
772 free(clonechildrenpath);
773 return true;
774 }
775
776 /* Given two null-terminated lists of strings, return true if any string is in
777 * both.
778 */
779 static bool controller_lists_intersect(char **l1, char **l2)
780 {
781 int i;
782
783 if (!l1 || !l2)
784 return false;
785
786 for (i = 0; l1[i]; i++) {
787 if (string_in_list(l2, l1[i]))
788 return true;
789 }
790
791 return false;
792 }
793
794 /* For a null-terminated list of controllers @clist, return true if any of those
795 * controllers is already listed the null-terminated list of hierarchies @hlist.
796 * Realistically, if one is present, all must be present.
797 */
798 static bool controller_list_is_dup(struct hierarchy **hlist, char **clist)
799 {
800 int i;
801
802 if (!hlist)
803 return false;
804
805 for (i = 0; hlist[i]; i++)
806 if (controller_lists_intersect(hlist[i]->controllers, clist))
807 return true;
808
809 return false;
810 }
811
812 /* Return true if the controller @entry is found in the null-terminated list of
813 * hierarchies @hlist.
814 */
815 static bool controller_found(struct hierarchy **hlist, char *entry)
816 {
817 int i;
818
819 if (!hlist)
820 return false;
821
822 for (i = 0; hlist[i]; i++)
823 if (string_in_list(hlist[i]->controllers, entry))
824 return true;
825
826 return false;
827 }
828
829 /* Return true if all of the controllers which we require have been found. The
830 * required list is freezer and anything in lxc.cgroup.use.
831 */
832 static bool all_controllers_found(void)
833 {
834 char *p;
835 char *saveptr = NULL;
836 struct hierarchy **hlist = hierarchies;
837
838 if (!controller_found(hlist, "freezer")) {
839 CGFSNG_DEBUG("No freezer controller mountpoint found\n");
840 return false;
841 }
842
843 if (!cgroup_use)
844 return true;
845
846 for (p = strtok_r(cgroup_use, ",", &saveptr); p;
847 p = strtok_r(NULL, ",", &saveptr)) {
848 if (!controller_found(hlist, p)) {
849 CGFSNG_DEBUG("No %s controller mountpoint found\n", p);
850 return false;
851 }
852 }
853
854 return true;
855 }
856
857 /* Get the controllers from a mountinfo line There are other ways we could get
858 * this info. For lxcfs, field 3 is /cgroup/controller-list. For cgroupfs, we
859 * could parse the mount options. But we simply assume that the mountpoint must
860 * be /sys/fs/cgroup/controller-list
861 */
862 static char **cg_hybrid_get_controllers(char **klist, char **nlist, char *line,
863 int type)
864 {
865 /* The fourth field is /sys/fs/cgroup/comma-delimited-controller-list
866 * for legacy hierarchies.
867 */
868 int i;
869 char *dup, *p2, *tok;
870 char *p = line, *saveptr = NULL, *sep = ",";
871 char **aret = NULL;
872
873 for (i = 0; i < 4; i++) {
874 p = strchr(p, ' ');
875 if (!p)
876 return NULL;
877 p++;
878 }
879
880 /* Note, if we change how mountinfo works, then our caller will need to
881 * verify /sys/fs/cgroup/ in this field.
882 */
883 if (strncmp(p, "/sys/fs/cgroup/", 15) != 0) {
884 CGFSNG_DEBUG("Found hierarchy not under /sys/fs/cgroup: \"%s\"\n", p);
885 return NULL;
886 }
887
888 p += 15;
889 p2 = strchr(p, ' ');
890 if (!p2) {
891 CGFSNG_DEBUG("Corrupt mountinfo\n");
892 return NULL;
893 }
894 *p2 = '\0';
895
896 if (type == CGROUP_SUPER_MAGIC) {
897 /* strdup() here for v1 hierarchies. Otherwise strtok_r() will
898 * destroy mountpoints such as "/sys/fs/cgroup/cpu,cpuacct".
899 */
900 dup = strdup(p);
901 if (!dup)
902 return NULL;
903
904 for (tok = strtok_r(dup, sep, &saveptr); tok;
905 tok = strtok_r(NULL, sep, &saveptr))
906 must_append_controller(klist, nlist, &aret, tok);
907
908 free(dup);
909 }
910 *p2 = ' ';
911
912 return aret;
913 }
914
915 static char **cg_unified_make_empty_controller(void)
916 {
917 int newentry;
918 char **aret = NULL;
919
920 newentry = append_null_to_list((void ***)&aret);
921 aret[newentry] = NULL;
922 return aret;
923 }
924
925 static char **cg_unified_get_controllers(const char *file)
926 {
927 char *buf, *tok;
928 char *saveptr = NULL, *sep = " \t\n";
929 char **aret = NULL;
930
931 buf = read_file(file);
932 if (!buf)
933 return NULL;
934
935 for (tok = strtok_r(buf, sep, &saveptr); tok;
936 tok = strtok_r(NULL, sep, &saveptr)) {
937 int newentry;
938 char *copy;
939
940 newentry = append_null_to_list((void ***)&aret);
941 copy = must_copy_string(tok);
942 aret[newentry] = copy;
943 }
944
945 free(buf);
946 return aret;
947 }
948
949 static struct hierarchy *add_hierarchy(char **clist, char *mountpoint,
950 char *base_cgroup, int type)
951 {
952 struct hierarchy *new;
953 int newentry;
954
955 new = must_alloc(sizeof(*new));
956 new->controllers = clist;
957 new->mountpoint = mountpoint;
958 new->base_cgroup = base_cgroup;
959 new->fullcgpath = NULL;
960 new->version = type;
961
962 newentry = append_null_to_list((void ***)&hierarchies);
963 hierarchies[newentry] = new;
964 return new;
965 }
966
967 /* Get a copy of the mountpoint from @line, which is a line from
968 * /proc/self/mountinfo.
969 */
970 static char *cg_hybrid_get_mountpoint(char *line)
971 {
972 int i;
973 size_t len;
974 char *p2;
975 char *p = line, *sret = NULL;
976
977 for (i = 0; i < 4; i++) {
978 p = strchr(p, ' ');
979 if (!p)
980 return NULL;
981 p++;
982 }
983
984 if (strncmp(p, "/sys/fs/cgroup/", 15) != 0)
985 return NULL;
986
987 p2 = strchr(p + 15, ' ');
988 if (!p2)
989 return NULL;
990 *p2 = '\0';
991
992 len = strlen(p);
993 sret = must_alloc(len + 1);
994 memcpy(sret, p, len);
995 sret[len] = '\0';
996 return sret;
997 }
998
999 /* Given a multi-line string, return a null-terminated copy of the current line. */
1000 static char *copy_to_eol(char *p)
1001 {
1002 char *p2 = strchr(p, '\n'), *sret;
1003 size_t len;
1004
1005 if (!p2)
1006 return NULL;
1007
1008 len = p2 - p;
1009 sret = must_alloc(len + 1);
1010 memcpy(sret, p, len);
1011 sret[len] = '\0';
1012 return sret;
1013 }
1014
1015 /* cgline: pointer to character after the first ':' in a line in a \n-terminated
1016 * /proc/self/cgroup file. Check whether controller c is present.
1017 */
1018 static bool controller_in_clist(char *cgline, char *c)
1019 {
1020 char *tok, *saveptr = NULL, *eol, *tmp;
1021 size_t len;
1022
1023 eol = strchr(cgline, ':');
1024 if (!eol)
1025 return false;
1026
1027 len = eol - cgline;
1028 tmp = alloca(len + 1);
1029 memcpy(tmp, cgline, len);
1030 tmp[len] = '\0';
1031
1032 for (tok = strtok_r(tmp, ",", &saveptr); tok;
1033 tok = strtok_r(NULL, ",", &saveptr)) {
1034 if (strcmp(tok, c) == 0)
1035 return true;
1036 }
1037
1038 return false;
1039 }
1040
1041 /* @basecginfo is a copy of /proc/$$/cgroup. Return the current cgroup for
1042 * @controller.
1043 */
1044 static char *cg_hybrid_get_current_cgroup(char *basecginfo, char *controller,
1045 int type)
1046 {
1047 char *p = basecginfo;
1048
1049 for (;;) {
1050 bool is_cgv2_base_cgroup = false;
1051
1052 /* cgroup v2 entry in "/proc/<pid>/cgroup": "0::/some/path" */
1053 if ((type == CGROUP2_SUPER_MAGIC) && (*p == '0'))
1054 is_cgv2_base_cgroup = true;
1055
1056 p = strchr(p, ':');
1057 if (!p)
1058 return NULL;
1059 p++;
1060
1061 if (is_cgv2_base_cgroup || (controller && controller_in_clist(p, controller))) {
1062 p = strchr(p, ':');
1063 if (!p)
1064 return NULL;
1065 p++;
1066 return copy_to_eol(p);
1067 }
1068
1069 p = strchr(p, '\n');
1070 if (!p)
1071 return NULL;
1072 p++;
1073 }
1074 }
1075
1076 static void must_append_string(char ***list, char *entry)
1077 {
1078 int newentry;
1079 char *copy;
1080
1081 newentry = append_null_to_list((void ***)list);
1082 copy = must_copy_string(entry);
1083 (*list)[newentry] = copy;
1084 }
1085
1086 static int get_existing_subsystems(char ***klist, char ***nlist)
1087 {
1088 FILE *f;
1089 char *line = NULL;
1090 size_t len = 0;
1091
1092 f = fopen("/proc/self/cgroup", "r");
1093 if (!f)
1094 return -1;
1095
1096 while (getline(&line, &len, f) != -1) {
1097 char *p, *p2, *tok, *saveptr = NULL;
1098 p = strchr(line, ':');
1099 if (!p)
1100 continue;
1101 p++;
1102 p2 = strchr(p, ':');
1103 if (!p2)
1104 continue;
1105 *p2 = '\0';
1106
1107 /* If the kernel has cgroup v2 support, then /proc/self/cgroup
1108 * contains an entry of the form:
1109 *
1110 * 0::/some/path
1111 *
1112 * In this case we use "cgroup2" as controller name.
1113 */
1114 if ((p2 - p) == 0) {
1115 must_append_string(klist, "cgroup2");
1116 continue;
1117 }
1118
1119 for (tok = strtok_r(p, ",", &saveptr); tok;
1120 tok = strtok_r(NULL, ",", &saveptr)) {
1121 if (strncmp(tok, "name=", 5) == 0)
1122 must_append_string(nlist, tok);
1123 else
1124 must_append_string(klist, tok);
1125 }
1126 }
1127
1128 free(line);
1129 fclose(f);
1130 return 0;
1131 }
1132
1133 static void trim(char *s)
1134 {
1135 size_t len;
1136
1137 len = strlen(s);
1138 while ((len > 1) && (s[len - 1] == '\n'))
1139 s[--len] = '\0';
1140 }
1141
1142 static void lxc_cgfsng_print_handler_data(const struct cgfsng_handler_data *d)
1143 {
1144 printf("Cgroup information:\n");
1145 printf(" container name: %s\n", d->name ? d->name : "(null)");
1146 printf(" lxc.cgroup.use: %s\n", cgroup_use ? cgroup_use : "(null)");
1147 printf(" lxc.cgroup.pattern: %s\n",
1148 d->cgroup_pattern ? d->cgroup_pattern : "(null)");
1149 printf(" lxc.cgroup.dir: %s\n",
1150 d->cgroup_meta.dir ? d->cgroup_meta.dir : "(null)");
1151 printf(" cgroup: %s\n",
1152 d->container_cgroup ? d->container_cgroup : "(null)");
1153 }
1154
1155 static void lxc_cgfsng_print_hierarchies()
1156 {
1157 int i;
1158 struct hierarchy **it;
1159
1160 if (!hierarchies) {
1161 printf(" No hierarchies found\n");
1162 return;
1163 }
1164
1165 printf(" Hierarchies:\n");
1166 for (i = 0, it = hierarchies; it && *it; it++, i++) {
1167 int j;
1168 char **cit;
1169
1170 printf(" %d: base_cgroup: %s\n", i, (*it)->base_cgroup ? (*it)->base_cgroup : "(null)");
1171 printf(" mountpoint: %s\n", (*it)->mountpoint ? (*it)->mountpoint : "(null)");
1172 printf(" controllers:\n");
1173 for (j = 0, cit = (*it)->controllers; cit && *cit; cit++, j++)
1174 printf(" %d: %s\n", j, *cit);
1175 }
1176 }
1177
1178 static void lxc_cgfsng_print_basecg_debuginfo(char *basecginfo, char **klist,
1179 char **nlist)
1180 {
1181 int k;
1182 char **it;
1183
1184 printf("basecginfo is:\n");
1185 printf("%s\n", basecginfo);
1186
1187 for (k = 0, it = klist; it && *it; it++, k++)
1188 printf("kernel subsystem %d: %s\n", k, *it);
1189
1190 for (k = 0, it = nlist; it && *it; it++, k++)
1191 printf("named subsystem %d: %s\n", k, *it);
1192 }
1193
1194 static void lxc_cgfsng_print_debuginfo(const struct cgfsng_handler_data *d)
1195 {
1196 lxc_cgfsng_print_handler_data(d);
1197 lxc_cgfsng_print_hierarchies();
1198 }
1199
1200 /* At startup, parse_hierarchies finds all the info we need about cgroup
1201 * mountpoints and current cgroups, and stores it in @d.
1202 */
1203 static bool cg_hybrid_init(void)
1204 {
1205 int ret;
1206 char *basecginfo;
1207 bool will_escape;
1208 FILE *f;
1209 size_t len = 0;
1210 char *line = NULL;
1211 char **klist = NULL, **nlist = NULL;
1212
1213 /* Root spawned containers escape the current cgroup, so use init's
1214 * cgroups as our base in that case.
1215 */
1216 will_escape = (geteuid() == 0);
1217 if (will_escape)
1218 basecginfo = read_file("/proc/1/cgroup");
1219 else
1220 basecginfo = read_file("/proc/self/cgroup");
1221 if (!basecginfo)
1222 return false;
1223
1224 ret = get_existing_subsystems(&klist, &nlist);
1225 if (ret < 0) {
1226 CGFSNG_DEBUG("Failed to retrieve available legacy cgroup controllers\n");
1227 free(basecginfo);
1228 return false;
1229 }
1230
1231 f = fopen("/proc/self/mountinfo", "r");
1232 if (!f) {
1233 CGFSNG_DEBUG("Failed to open \"/proc/self/mountinfo\"\n");
1234 free(basecginfo);
1235 return false;
1236 }
1237
1238 if (lxc_cgfsng_debug)
1239 lxc_cgfsng_print_basecg_debuginfo(basecginfo, klist, nlist);
1240
1241 while (getline(&line, &len, f) != -1) {
1242 int type;
1243 bool writeable;
1244 struct hierarchy *new;
1245 char *base_cgroup = NULL, *mountpoint = NULL;
1246 char **controller_list = NULL;
1247
1248 type = get_cgroup_version(line);
1249 if (type == 0)
1250 continue;
1251
1252 if (type == CGROUP2_SUPER_MAGIC && unified)
1253 continue;
1254
1255 if (cgroup_layout == CGROUP_LAYOUT_UNKNOWN) {
1256 if (type == CGROUP2_SUPER_MAGIC)
1257 cgroup_layout = CGROUP_LAYOUT_UNIFIED;
1258 else if (type == CGROUP_SUPER_MAGIC)
1259 cgroup_layout = CGROUP_LAYOUT_LEGACY;
1260 } else if (cgroup_layout == CGROUP_LAYOUT_UNIFIED) {
1261 if (type == CGROUP_SUPER_MAGIC)
1262 cgroup_layout = CGROUP_LAYOUT_HYBRID;
1263 } else if (cgroup_layout == CGROUP_LAYOUT_LEGACY) {
1264 if (type == CGROUP2_SUPER_MAGIC)
1265 cgroup_layout = CGROUP_LAYOUT_HYBRID;
1266 }
1267
1268 controller_list = cg_hybrid_get_controllers(klist, nlist, line, type);
1269 if (!controller_list && type == CGROUP_SUPER_MAGIC)
1270 continue;
1271
1272 if (type == CGROUP_SUPER_MAGIC)
1273 if (controller_list_is_dup(hierarchies, controller_list))
1274 goto next;
1275
1276 mountpoint = cg_hybrid_get_mountpoint(line);
1277 if (!mountpoint) {
1278 CGFSNG_DEBUG("Failed parsing mountpoint from \"%s\"\n", line);
1279 goto next;
1280 }
1281
1282 if (type == CGROUP_SUPER_MAGIC)
1283 base_cgroup = cg_hybrid_get_current_cgroup(basecginfo, controller_list[0], CGROUP_SUPER_MAGIC);
1284 else
1285 base_cgroup = cg_hybrid_get_current_cgroup(basecginfo, NULL, CGROUP2_SUPER_MAGIC);
1286 if (!base_cgroup) {
1287 CGFSNG_DEBUG("Failed to find current cgroup\n");
1288 goto next;
1289 }
1290
1291 trim(base_cgroup);
1292 prune_init_scope(base_cgroup);
1293 if (type == CGROUP2_SUPER_MAGIC)
1294 writeable = test_writeable_v2(mountpoint, base_cgroup);
1295 else
1296 writeable = test_writeable_v1(mountpoint, base_cgroup);
1297 if (!writeable)
1298 goto next;
1299
1300 if (type == CGROUP2_SUPER_MAGIC) {
1301 char *cgv2_ctrl_path;
1302
1303 cgv2_ctrl_path = must_make_path(mountpoint, base_cgroup,
1304 "cgroup.controllers",
1305 NULL);
1306
1307 controller_list = cg_unified_get_controllers(cgv2_ctrl_path);
1308 free(cgv2_ctrl_path);
1309 if (!controller_list) {
1310 controller_list = cg_unified_make_empty_controller();
1311 CGFSNG_DEBUG("No controllers are enabled for "
1312 "delegation in the unified hierarchy\n");
1313 }
1314 }
1315
1316 new = add_hierarchy(controller_list, mountpoint, base_cgroup, type);
1317 if (type == CGROUP2_SUPER_MAGIC && !unified)
1318 unified = new;
1319
1320 continue;
1321
1322 next:
1323 free_string_list(controller_list);
1324 free(mountpoint);
1325 free(base_cgroup);
1326 }
1327
1328 free_string_list(klist);
1329 free_string_list(nlist);
1330
1331 free(basecginfo);
1332
1333 fclose(f);
1334 free(line);
1335
1336 if (lxc_cgfsng_debug) {
1337 printf("Writable cgroup hierarchies:\n");
1338 lxc_cgfsng_print_hierarchies();
1339 }
1340
1341 /* verify that all controllers in cgroup.use and all crucial
1342 * controllers are accounted for
1343 */
1344 if (!all_controllers_found())
1345 return false;
1346
1347 return true;
1348 }
1349
1350 static int cg_is_pure_unified(void)
1351 {
1352
1353 int ret;
1354 struct statfs fs;
1355
1356 ret = statfs("/sys/fs/cgroup", &fs);
1357 if (ret < 0)
1358 return -ENOMEDIUM;
1359
1360 if (is_fs_type(&fs, CGROUP2_SUPER_MAGIC))
1361 return CGROUP2_SUPER_MAGIC;
1362
1363 return 0;
1364 }
1365
1366 /* Get current cgroup from /proc/self/cgroup for the cgroupfs v2 hierarchy. */
1367 static char *cg_unified_get_current_cgroup(void)
1368 {
1369 char *basecginfo, *base_cgroup;
1370 bool will_escape;
1371 char *copy = NULL;
1372
1373 will_escape = (geteuid() == 0);
1374 if (will_escape)
1375 basecginfo = read_file("/proc/1/cgroup");
1376 else
1377 basecginfo = read_file("/proc/self/cgroup");
1378 if (!basecginfo)
1379 return NULL;
1380
1381 base_cgroup = strstr(basecginfo, "0::/");
1382 if (!base_cgroup)
1383 goto cleanup_on_err;
1384
1385 base_cgroup = base_cgroup + 3;
1386 copy = copy_to_eol(base_cgroup);
1387 if (!copy)
1388 goto cleanup_on_err;
1389
1390 cleanup_on_err:
1391 free(basecginfo);
1392 if (copy)
1393 trim(copy);
1394
1395 return copy;
1396 }
1397
1398 static int cg_unified_init(void)
1399 {
1400 int ret;
1401 char *mountpoint, *subtree_path;
1402 char **delegatable;
1403 char *base_cgroup = NULL;
1404
1405 ret = cg_is_pure_unified();
1406 if (ret == -ENOMEDIUM)
1407 return -ENOMEDIUM;
1408
1409 if (ret != CGROUP2_SUPER_MAGIC)
1410 return 0;
1411
1412 base_cgroup = cg_unified_get_current_cgroup();
1413 if (!base_cgroup)
1414 return -EINVAL;
1415 prune_init_scope(base_cgroup);
1416
1417 /* We assume that we have already been given controllers to delegate
1418 * further down the hierarchy. If not it is up to the user to delegate
1419 * them to us.
1420 */
1421 mountpoint = must_copy_string("/sys/fs/cgroup");
1422 subtree_path = must_make_path(mountpoint, base_cgroup,
1423 "cgroup.subtree_control", NULL);
1424 delegatable = cg_unified_get_controllers(subtree_path);
1425 free(subtree_path);
1426 if (!delegatable)
1427 delegatable = cg_unified_make_empty_controller();
1428 if (!delegatable[0])
1429 CGFSNG_DEBUG("No controllers are enabled for delegation\n");
1430
1431 /* TODO: If the user requested specific controllers via lxc.cgroup.use
1432 * we should verify here. The reason I'm not doing it right is that I'm
1433 * not convinced that lxc.cgroup.use will be the future since it is a
1434 * global property. I much rather have an option that lets you request
1435 * controllers per container.
1436 */
1437
1438 add_hierarchy(delegatable, mountpoint, base_cgroup, CGROUP2_SUPER_MAGIC);
1439 unified = hierarchies[0];
1440
1441 cgroup_layout = CGROUP_LAYOUT_UNIFIED;
1442 return CGROUP2_SUPER_MAGIC;
1443 }
1444
1445 static bool cg_init(void)
1446 {
1447 int ret;
1448 const char *tmp;
1449
1450 errno = 0;
1451 tmp = lxc_global_config_value("lxc.cgroup.use");
1452 if (!cgroup_use && errno != 0) { /* lxc.cgroup.use can be NULL */
1453 CGFSNG_DEBUG("Failed to retrieve list of cgroups to use\n");
1454 return false;
1455 }
1456 cgroup_use = must_copy_string(tmp);
1457
1458 ret = cg_unified_init();
1459 if (ret < 0)
1460 return false;
1461
1462 if (ret == CGROUP2_SUPER_MAGIC)
1463 return true;
1464
1465 return cg_hybrid_init();
1466 }
1467
1468 static void *cgfsng_init(struct lxc_handler *handler)
1469 {
1470 const char *cgroup_pattern;
1471 struct cgfsng_handler_data *d;
1472
1473 d = must_alloc(sizeof(*d));
1474 memset(d, 0, sizeof(*d));
1475
1476 /* copy container name */
1477 d->name = must_copy_string(handler->name);
1478
1479 /* copy per-container cgroup information */
1480 d->cgroup_meta.dir = NULL;
1481 d->cgroup_meta.controllers = NULL;
1482 if (handler->conf) {
1483 d->cgroup_meta.dir = must_copy_string(handler->conf->cgroup_meta.dir);
1484 d->cgroup_meta.controllers = must_copy_string(handler->conf->cgroup_meta.controllers);
1485 }
1486
1487 /* copy system-wide cgroup information */
1488 cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
1489 if (!cgroup_pattern) {
1490 /* lxc.cgroup.pattern is only NULL on error. */
1491 ERROR("Failed to retrieve cgroup pattern");
1492 goto out_free;
1493 }
1494 d->cgroup_pattern = must_copy_string(cgroup_pattern);
1495
1496 d->cgroup_layout = cgroup_layout;
1497 if (d->cgroup_layout == CGROUP_LAYOUT_LEGACY)
1498 TRACE("Running with legacy cgroup layout");
1499 else if (d->cgroup_layout == CGROUP_LAYOUT_HYBRID)
1500 TRACE("Running with hybrid cgroup layout");
1501 else if (d->cgroup_layout == CGROUP_LAYOUT_UNIFIED)
1502 TRACE("Running with unified cgroup layout");
1503 else
1504 WARN("Running with unknown cgroup layout");
1505
1506 if (lxc_cgfsng_debug)
1507 lxc_cgfsng_print_debuginfo(d);
1508
1509 return d;
1510
1511 out_free:
1512 free_handler_data(d);
1513 return NULL;
1514 }
1515
1516 static int recursive_destroy(char *dirname)
1517 {
1518 int ret;
1519 struct dirent *direntp;
1520 DIR *dir;
1521 int r = 0;
1522
1523 dir = opendir(dirname);
1524 if (!dir)
1525 return -1;
1526
1527 while ((direntp = readdir(dir))) {
1528 char *pathname;
1529 struct stat mystat;
1530
1531 if (!strcmp(direntp->d_name, ".") ||
1532 !strcmp(direntp->d_name, ".."))
1533 continue;
1534
1535 pathname = must_make_path(dirname, direntp->d_name, NULL);
1536
1537 ret = lstat(pathname, &mystat);
1538 if (ret < 0) {
1539 if (!r)
1540 WARN("Failed to stat \"%s\"", pathname);
1541 r = -1;
1542 goto next;
1543 }
1544
1545 if (!S_ISDIR(mystat.st_mode))
1546 goto next;
1547
1548 ret = recursive_destroy(pathname);
1549 if (ret < 0)
1550 r = -1;
1551 next:
1552 free(pathname);
1553 }
1554
1555 ret = rmdir(dirname);
1556 if (ret < 0) {
1557 if (!r)
1558 WARN("%s - Failed to delete \"%s\"", strerror(errno), dirname);
1559 r = -1;
1560 }
1561
1562 ret = closedir(dir);
1563 if (ret < 0) {
1564 if (!r)
1565 WARN("%s - Failed to delete \"%s\"", strerror(errno), dirname);
1566 r = -1;
1567 }
1568
1569 return r;
1570 }
1571
1572 static int cgroup_rmdir(char *container_cgroup)
1573 {
1574 int i;
1575
1576 if (!container_cgroup || !hierarchies)
1577 return 0;
1578
1579 for (i = 0; hierarchies[i]; i++) {
1580 int ret;
1581 struct hierarchy *h = hierarchies[i];
1582
1583 if (!h->fullcgpath)
1584 continue;
1585
1586 ret = recursive_destroy(h->fullcgpath);
1587 if (ret < 0)
1588 WARN("Failed to destroy \"%s\"", h->fullcgpath);
1589
1590 free(h->fullcgpath);
1591 h->fullcgpath = NULL;
1592 }
1593
1594 return 0;
1595 }
1596
1597 struct generic_userns_exec_data {
1598 struct cgfsng_handler_data *d;
1599 struct lxc_conf *conf;
1600 uid_t origuid; /* target uid in parent namespace */
1601 char *path;
1602 };
1603
1604 static int cgroup_rmdir_wrapper(void *data)
1605 {
1606 int ret;
1607 struct generic_userns_exec_data *arg = data;
1608 uid_t nsuid = (arg->conf->root_nsuid_map != NULL) ? 0 : arg->conf->init_uid;
1609 gid_t nsgid = (arg->conf->root_nsgid_map != NULL) ? 0 : arg->conf->init_gid;
1610
1611 ret = setresgid(nsgid, nsgid, nsgid);
1612 if (ret < 0) {
1613 SYSERROR("Failed to setresgid(%d, %d, %d)", (int)nsgid,
1614 (int)nsgid, (int)nsgid);
1615 return -1;
1616 }
1617
1618 ret = setresuid(nsuid, nsuid, nsuid);
1619 if (ret < 0) {
1620 SYSERROR("Failed to setresuid(%d, %d, %d)", (int)nsuid,
1621 (int)nsuid, (int)nsuid);
1622 return -1;
1623 }
1624
1625 ret = setgroups(0, NULL);
1626 if (ret < 0 && errno != EPERM) {
1627 SYSERROR("Failed to setgroups(0, NULL)");
1628 return -1;
1629 }
1630
1631 return cgroup_rmdir(arg->d->container_cgroup);
1632 }
1633
1634 static void cgfsng_destroy(void *hdata, struct lxc_conf *conf)
1635 {
1636 int ret;
1637 struct cgfsng_handler_data *d = hdata;
1638 struct generic_userns_exec_data wrap;
1639
1640 if (!d)
1641 return;
1642
1643 wrap.origuid = 0;
1644 wrap.d = hdata;
1645 wrap.conf = conf;
1646
1647 if (conf && !lxc_list_empty(&conf->id_map))
1648 ret = userns_exec_1(conf, cgroup_rmdir_wrapper, &wrap,
1649 "cgroup_rmdir_wrapper");
1650 else
1651 ret = cgroup_rmdir(d->container_cgroup);
1652 if (ret < 0) {
1653 WARN("Failed to destroy cgroups");
1654 return;
1655 }
1656
1657 free_handler_data(d);
1658 }
1659
1660 struct cgroup_ops *cgfsng_ops_init(void)
1661 {
1662 if (getenv("LXC_DEBUG_CGFSNG"))
1663 lxc_cgfsng_debug = true;
1664
1665 if (!cg_init())
1666 return NULL;
1667
1668 return &cgfsng_ops;
1669 }
1670
1671 static bool cg_unified_create_cgroup(struct hierarchy *h, char *cgname)
1672 {
1673 size_t i, parts_len;
1674 char **it;
1675 size_t full_len = 0;
1676 char *add_controllers = NULL, *cgroup = NULL;
1677 char **parts = NULL;
1678 bool bret = false;
1679
1680 if (h->version != CGROUP2_SUPER_MAGIC)
1681 return true;
1682
1683 if (!h->controllers)
1684 return true;
1685
1686 /* For now we simply enable all controllers that we have detected by
1687 * creating a string like "+memory +pids +cpu +io".
1688 * TODO: In the near future we might want to support "-<controller>"
1689 * etc. but whether supporting semantics like this make sense will need
1690 * some thinking.
1691 */
1692 for (it = h->controllers; it && *it; it++) {
1693 full_len += strlen(*it) + 2;
1694 add_controllers = must_realloc(add_controllers, full_len + 1);
1695 if (h->controllers[0] == *it)
1696 add_controllers[0] = '\0';
1697 strcat(add_controllers, "+");
1698 strcat(add_controllers, *it);
1699 if ((it + 1) && *(it + 1))
1700 strcat(add_controllers, " ");
1701 }
1702
1703 parts = lxc_string_split(cgname, '/');
1704 if (!parts)
1705 goto on_error;
1706 parts_len = lxc_array_len((void **)parts);
1707 if (parts_len > 0)
1708 parts_len--;
1709
1710 cgroup = must_make_path(h->mountpoint, h->base_cgroup, NULL);
1711 for (i = 0; i < parts_len; i++) {
1712 int ret;
1713 char *target;
1714
1715 cgroup = must_append_path(cgroup, parts[i], NULL);
1716 target = must_make_path(cgroup, "cgroup.subtree_control", NULL);
1717 ret = lxc_write_to_file(target, add_controllers, full_len, false);
1718 free(target);
1719 if (ret < 0) {
1720 SYSERROR("Could not enable \"%s\" controllers in the "
1721 "unified cgroup \"%s\"", add_controllers, cgroup);
1722 goto on_error;
1723 }
1724 }
1725
1726 bret = true;
1727
1728 on_error:
1729 lxc_free_array((void **)parts, free);
1730 free(add_controllers);
1731 free(cgroup);
1732 return bret;
1733 }
1734
1735 static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname)
1736 {
1737 int ret;
1738
1739 h->fullcgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
1740 if (dir_exists(h->fullcgpath)) {
1741 ERROR("The cgroup \"%s\" already existed", h->fullcgpath);
1742 return false;
1743 }
1744
1745 if (!cg_legacy_handle_cpuset_hierarchy(h, cgname)) {
1746 ERROR("Failed to handle legacy cpuset controller");
1747 return false;
1748 }
1749
1750 ret = mkdir_p(h->fullcgpath, 0755);
1751 if (ret < 0) {
1752 ERROR("Failed to create cgroup \"%s\"", h->fullcgpath);
1753 return false;
1754 }
1755
1756 return cg_unified_create_cgroup(h, cgname);
1757 }
1758
1759 static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)
1760 {
1761 int ret;
1762
1763 ret = rmdir(h->fullcgpath);
1764 if (ret < 0)
1765 SYSERROR("Failed to rmdir(\"%s\") from failed creation attempt", h->fullcgpath);
1766
1767 free(h->fullcgpath);
1768 h->fullcgpath = NULL;
1769 }
1770
1771 /* Try to create the same cgroup in all hierarchies. Start with cgroup_pattern;
1772 * next cgroup_pattern-1, -2, ..., -999.
1773 */
1774 static inline bool cgfsng_create(void *hdata)
1775 {
1776 int i;
1777 size_t len;
1778 char *container_cgroup, *offset, *tmp;
1779 int idx = 0;
1780 struct cgfsng_handler_data *d = hdata;
1781
1782 if (!d)
1783 return false;
1784
1785 if (d->container_cgroup) {
1786 WARN("cgfsng_create called a second time");
1787 return false;
1788 }
1789
1790 if (d->cgroup_meta.dir)
1791 tmp = lxc_string_join("/", (const char *[]){d->cgroup_meta.dir, d->name, NULL}, false);
1792 else
1793 tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
1794 if (!tmp) {
1795 ERROR("Failed expanding cgroup name pattern");
1796 return false;
1797 }
1798 len = strlen(tmp) + 5; /* leave room for -NNN\0 */
1799 container_cgroup = must_alloc(len);
1800 strcpy(container_cgroup, tmp);
1801 free(tmp);
1802 offset = container_cgroup + len - 5;
1803
1804 again:
1805 if (idx == 1000) {
1806 ERROR("Too many conflicting cgroup names");
1807 goto out_free;
1808 }
1809
1810 if (idx) {
1811 int ret;
1812
1813 ret = snprintf(offset, 5, "-%d", idx);
1814 if (ret < 0 || (size_t)ret >= 5) {
1815 FILE *f = fopen("/dev/null", "w");
1816 if (f) {
1817 fprintf(f, "Workaround for GCC7 bug: "
1818 "https://gcc.gnu.org/bugzilla/"
1819 "show_bug.cgi?id=78969");
1820 fclose(f);
1821 }
1822 }
1823 }
1824
1825 for (i = 0; hierarchies[i]; i++) {
1826 if (!create_path_for_hierarchy(hierarchies[i], container_cgroup)) {
1827 int j;
1828 ERROR("Failed to create cgroup \"%s\"", hierarchies[i]->fullcgpath);
1829 free(hierarchies[i]->fullcgpath);
1830 hierarchies[i]->fullcgpath = NULL;
1831 for (j = 0; j < i; j++)
1832 remove_path_for_hierarchy(hierarchies[j], container_cgroup);
1833 idx++;
1834 goto again;
1835 }
1836 }
1837
1838 d->container_cgroup = container_cgroup;
1839
1840 return true;
1841
1842 out_free:
1843 free(container_cgroup);
1844
1845 return false;
1846 }
1847
1848 static bool cgfsng_enter(void *hdata, pid_t pid)
1849 {
1850 int i, len;
1851 char pidstr[25];
1852
1853 len = snprintf(pidstr, 25, "%d", pid);
1854 if (len < 0 || len >= 25)
1855 return false;
1856
1857 for (i = 0; hierarchies[i]; i++) {
1858 int ret;
1859 char *fullpath;
1860
1861 fullpath = must_make_path(hierarchies[i]->fullcgpath,
1862 "cgroup.procs", NULL);
1863 ret = lxc_write_to_file(fullpath, pidstr, len, false);
1864 if (ret != 0) {
1865 SYSERROR("Failed to enter cgroup \"%s\"", fullpath);
1866 free(fullpath);
1867 return false;
1868 }
1869 free(fullpath);
1870 }
1871
1872 return true;
1873 }
1874
1875 static int chowmod(char *path, uid_t chown_uid, gid_t chown_gid,
1876 mode_t chmod_mode)
1877 {
1878 int ret;
1879
1880 ret = chown(path, chown_uid, chown_gid);
1881 if (ret < 0) {
1882 WARN("%s - Failed to chown(%s, %d, %d)", strerror(errno), path,
1883 (int)chown_uid, (int)chown_gid);
1884 return -1;
1885 }
1886
1887 ret = chmod(path, chmod_mode);
1888 if (ret < 0) {
1889 WARN("%s - Failed to chmod(%s, %d)", strerror(errno), path,
1890 (int)chmod_mode);
1891 return -1;
1892 }
1893
1894 return 0;
1895 }
1896
1897 /* chgrp the container cgroups to container group. We leave
1898 * the container owner as cgroup owner. So we must make the
1899 * directories 775 so that the container can create sub-cgroups.
1900 *
1901 * Also chown the tasks and cgroup.procs files. Those may not
1902 * exist depending on kernel version.
1903 */
1904 static int chown_cgroup_wrapper(void *data)
1905 {
1906 int i, ret;
1907 uid_t destuid;
1908 struct generic_userns_exec_data *arg = data;
1909 uid_t nsuid = (arg->conf->root_nsuid_map != NULL) ? 0 : arg->conf->init_uid;
1910 gid_t nsgid = (arg->conf->root_nsgid_map != NULL) ? 0 : arg->conf->init_gid;
1911
1912 ret = setresgid(nsgid, nsgid, nsgid);
1913 if (ret < 0) {
1914 SYSERROR("Failed to setresgid(%d, %d, %d)",
1915 (int)nsgid, (int)nsgid, (int)nsgid);
1916 return -1;
1917 }
1918
1919 ret = setresuid(nsuid, nsuid, nsuid);
1920 if (ret < 0) {
1921 SYSERROR("Failed to setresuid(%d, %d, %d)",
1922 (int)nsuid, (int)nsuid, (int)nsuid);
1923 return -1;
1924 }
1925
1926 ret = setgroups(0, NULL);
1927 if (ret < 0 && errno != EPERM) {
1928 SYSERROR("Failed to setgroups(0, NULL)");
1929 return -1;
1930 }
1931
1932 destuid = get_ns_uid(arg->origuid);
1933
1934 for (i = 0; hierarchies[i]; i++) {
1935 char *fullpath;
1936 char *path = hierarchies[i]->fullcgpath;
1937
1938 ret = chowmod(path, destuid, nsgid, 0775);
1939 if (ret < 0)
1940 return -1;
1941
1942 /* Failures to chown() these are inconvenient but not
1943 * detrimental We leave these owned by the container launcher,
1944 * so that container root can write to the files to attach. We
1945 * chmod() them 664 so that container systemd can write to the
1946 * files (which systemd in wily insists on doing).
1947 */
1948
1949 if (hierarchies[i]->version == CGROUP_SUPER_MAGIC) {
1950 fullpath = must_make_path(path, "tasks", NULL);
1951 (void)chowmod(fullpath, destuid, nsgid, 0664);
1952 free(fullpath);
1953 }
1954
1955 fullpath = must_make_path(path, "cgroup.procs", NULL);
1956 (void)chowmod(fullpath, destuid, 0, 0664);
1957 free(fullpath);
1958
1959 if (hierarchies[i]->version != CGROUP2_SUPER_MAGIC)
1960 continue;
1961
1962 fullpath = must_make_path(path, "cgroup.subtree_control", NULL);
1963 (void)chowmod(fullpath, destuid, nsgid, 0664);
1964 free(fullpath);
1965
1966 fullpath = must_make_path(path, "cgroup.threads", NULL);
1967 (void)chowmod(fullpath, destuid, nsgid, 0664);
1968 free(fullpath);
1969 }
1970
1971 return 0;
1972 }
1973
1974 static bool cgfsng_chown(void *hdata, struct lxc_conf *conf)
1975 {
1976 struct cgfsng_handler_data *d = hdata;
1977 struct generic_userns_exec_data wrap;
1978
1979 if (!d)
1980 return false;
1981
1982 if (lxc_list_empty(&conf->id_map))
1983 return true;
1984
1985 wrap.origuid = geteuid();
1986 wrap.path = NULL;
1987 wrap.d = d;
1988 wrap.conf = conf;
1989
1990 if (userns_exec_1(conf, chown_cgroup_wrapper, &wrap,
1991 "chown_cgroup_wrapper") < 0) {
1992 ERROR("Error requesting cgroup chown in new user namespace");
1993 return false;
1994 }
1995
1996 return true;
1997 }
1998
1999 /* cgroup-full:* is done, no need to create subdirs */
2000 static bool cg_mount_needs_subdirs(int type)
2001 {
2002 if (type >= LXC_AUTO_CGROUP_FULL_RO)
2003 return false;
2004
2005 return true;
2006 }
2007
2008 /* After $rootfs/sys/fs/container/controller/the/cg/path has been created,
2009 * remount controller ro if needed and bindmount the cgroupfs onto
2010 * controll/the/cg/path.
2011 */
2012 static int cg_legacy_mount_controllers(int type, struct hierarchy *h,
2013 char *controllerpath, char *cgpath,
2014 const char *container_cgroup)
2015 {
2016 int ret, remount_flags;
2017 char *sourcepath;
2018 int flags = MS_BIND;
2019
2020 if (type == LXC_AUTO_CGROUP_RO || type == LXC_AUTO_CGROUP_MIXED) {
2021 ret = mount(controllerpath, controllerpath, "cgroup", MS_BIND, NULL);
2022 if (ret < 0) {
2023 SYSERROR("Failed to bind mount \"%s\" onto \"%s\"",
2024 controllerpath, controllerpath);
2025 return -1;
2026 }
2027
2028 remount_flags = add_required_remount_flags(controllerpath,
2029 controllerpath,
2030 flags | MS_REMOUNT);
2031 ret = mount(controllerpath, controllerpath, "cgroup",
2032 MS_REMOUNT | MS_BIND | MS_RDONLY, NULL);
2033 if (ret < 0) {
2034 SYSERROR("Failed to remount \"%s\" ro", controllerpath);
2035 return -1;
2036 }
2037
2038 INFO("Remounted %s read-only", controllerpath);
2039 }
2040
2041 sourcepath = must_make_path(h->mountpoint, h->base_cgroup,
2042 container_cgroup, NULL);
2043 if (type == LXC_AUTO_CGROUP_RO)
2044 flags |= MS_RDONLY;
2045
2046 ret = mount(sourcepath, cgpath, "cgroup", flags, NULL);
2047 if (ret < 0) {
2048 SYSERROR("Failed to mount \"%s\" onto \"%s\"", h->controllers[0], cgpath);
2049 free(sourcepath);
2050 return -1;
2051 }
2052 INFO("Mounted \"%s\" onto \"%s\"", h->controllers[0], cgpath);
2053
2054 if (flags & MS_RDONLY) {
2055 remount_flags = add_required_remount_flags(sourcepath, cgpath,
2056 flags | MS_REMOUNT);
2057 ret = mount(sourcepath, cgpath, "cgroup", remount_flags, NULL);
2058 if (ret < 0) {
2059 SYSERROR("Failed to remount \"%s\" ro", cgpath);
2060 free(sourcepath);
2061 return -1;
2062 }
2063 INFO("Remounted %s read-only", cgpath);
2064 }
2065
2066 free(sourcepath);
2067 INFO("Completed second stage cgroup automounts for \"%s\"", cgpath);
2068 return 0;
2069 }
2070
2071 /* __cg_mount_direct
2072 *
2073 * Mount cgroup hierarchies directly without using bind-mounts. The main
2074 * uses-cases are mounting cgroup hierarchies in cgroup namespaces and mounting
2075 * cgroups for the LXC_AUTO_CGROUP_FULL option.
2076 */
2077 static int __cg_mount_direct(int type, struct hierarchy *h,
2078 const char *controllerpath)
2079 {
2080 int ret;
2081 char *controllers = NULL;
2082 char *fstype = "cgroup2";
2083 unsigned long flags = 0;
2084
2085 flags |= MS_NOSUID;
2086 flags |= MS_NOEXEC;
2087 flags |= MS_NODEV;
2088 flags |= MS_RELATIME;
2089
2090 if (type == LXC_AUTO_CGROUP_RO || type == LXC_AUTO_CGROUP_FULL_RO)
2091 flags |= MS_RDONLY;
2092
2093 if (h->version != CGROUP2_SUPER_MAGIC) {
2094 controllers = lxc_string_join(",", (const char **)h->controllers, false);
2095 if (!controllers)
2096 return -ENOMEM;
2097 fstype = "cgroup";
2098 }
2099
2100 ret = mount("cgroup", controllerpath, fstype, flags, controllers);
2101 free(controllers);
2102 if (ret < 0) {
2103 SYSERROR("Failed to mount \"%s\" with cgroup filesystem type %s", controllerpath, fstype);
2104 return -1;
2105 }
2106
2107 DEBUG("Mounted \"%s\" with cgroup filesystem type %s", controllerpath, fstype);
2108 return 0;
2109 }
2110
2111 static inline int cg_mount_in_cgroup_namespace(int type, struct hierarchy *h,
2112 const char *controllerpath)
2113 {
2114 return __cg_mount_direct(type, h, controllerpath);
2115 }
2116
2117 static inline int cg_mount_cgroup_full(int type, struct hierarchy *h,
2118 const char *controllerpath)
2119 {
2120 if (type < LXC_AUTO_CGROUP_FULL_RO || type > LXC_AUTO_CGROUP_FULL_MIXED)
2121 return 0;
2122
2123 return __cg_mount_direct(type, h, controllerpath);
2124 }
2125
2126 static bool cgfsng_mount(void *hdata, const char *root, int type)
2127 {
2128 int i, ret;
2129 char *tmpfspath = NULL;
2130 bool has_cgns = false, retval = false, wants_force_mount = false;
2131 struct lxc_handler *handler = hdata;
2132 struct cgfsng_handler_data *d = handler->cgroup_data;
2133
2134 if ((type & LXC_AUTO_CGROUP_MASK) == 0)
2135 return true;
2136
2137 if (type & LXC_AUTO_CGROUP_FORCE) {
2138 type &= ~LXC_AUTO_CGROUP_FORCE;
2139 wants_force_mount = true;
2140 }
2141
2142 if (!wants_force_mount){
2143 if (!lxc_list_empty(&handler->conf->keepcaps))
2144 wants_force_mount = !in_caplist(CAP_SYS_ADMIN, &handler->conf->keepcaps);
2145 else
2146 wants_force_mount = in_caplist(CAP_SYS_ADMIN, &handler->conf->caps);
2147 }
2148
2149 has_cgns = cgns_supported();
2150 if (has_cgns && !wants_force_mount)
2151 return true;
2152
2153 if (type == LXC_AUTO_CGROUP_NOSPEC)
2154 type = LXC_AUTO_CGROUP_MIXED;
2155 else if (type == LXC_AUTO_CGROUP_FULL_NOSPEC)
2156 type = LXC_AUTO_CGROUP_FULL_MIXED;
2157
2158 /* Mount tmpfs */
2159 tmpfspath = must_make_path(root, "/sys/fs/cgroup", NULL);
2160 ret = safe_mount(NULL, tmpfspath, "tmpfs",
2161 MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME,
2162 "size=10240k,mode=755", root);
2163 if (ret < 0)
2164 goto on_error;
2165
2166 for (i = 0; hierarchies[i]; i++) {
2167 char *controllerpath, *path2;
2168 struct hierarchy *h = hierarchies[i];
2169 char *controller = strrchr(h->mountpoint, '/');
2170
2171 if (!controller)
2172 continue;
2173 controller++;
2174
2175 controllerpath = must_make_path(tmpfspath, controller, NULL);
2176 if (dir_exists(controllerpath)) {
2177 free(controllerpath);
2178 continue;
2179 }
2180
2181 ret = mkdir(controllerpath, 0755);
2182 if (ret < 0) {
2183 SYSERROR("Error creating cgroup path: %s", controllerpath);
2184 free(controllerpath);
2185 goto on_error;
2186 }
2187
2188 if (has_cgns && wants_force_mount) {
2189 /* If cgroup namespaces are supported but the container
2190 * will not have CAP_SYS_ADMIN after it has started we
2191 * need to mount the cgroups manually.
2192 */
2193 ret = cg_mount_in_cgroup_namespace(type, h, controllerpath);
2194 free(controllerpath);
2195 if (ret < 0)
2196 goto on_error;
2197
2198 continue;
2199 }
2200
2201 ret = cg_mount_cgroup_full(type, h, controllerpath);
2202 if (ret < 0) {
2203 free(controllerpath);
2204 goto on_error;
2205 }
2206
2207 if (!cg_mount_needs_subdirs(type)) {
2208 free(controllerpath);
2209 continue;
2210 }
2211
2212 path2 = must_make_path(controllerpath, h->base_cgroup,
2213 d->container_cgroup, NULL);
2214 ret = mkdir_p(path2, 0755);
2215 if (ret < 0) {
2216 free(controllerpath);
2217 free(path2);
2218 goto on_error;
2219 }
2220
2221 ret = cg_legacy_mount_controllers(type, h, controllerpath,
2222 path2, d->container_cgroup);
2223 free(controllerpath);
2224 free(path2);
2225 if (ret < 0)
2226 goto on_error;
2227 }
2228 retval = true;
2229
2230 on_error:
2231 free(tmpfspath);
2232 return retval;
2233 }
2234
2235 static int recursive_count_nrtasks(char *dirname)
2236 {
2237 struct dirent *direntp;
2238 DIR *dir;
2239 int count = 0, ret;
2240 char *path;
2241
2242 dir = opendir(dirname);
2243 if (!dir)
2244 return 0;
2245
2246 while ((direntp = readdir(dir))) {
2247 struct stat mystat;
2248
2249 if (!direntp)
2250 break;
2251
2252 if (!strcmp(direntp->d_name, ".") ||
2253 !strcmp(direntp->d_name, ".."))
2254 continue;
2255
2256 path = must_make_path(dirname, direntp->d_name, NULL);
2257
2258 if (lstat(path, &mystat))
2259 goto next;
2260
2261 if (!S_ISDIR(mystat.st_mode))
2262 goto next;
2263
2264 count += recursive_count_nrtasks(path);
2265 next:
2266 free(path);
2267 }
2268
2269 path = must_make_path(dirname, "cgroup.procs", NULL);
2270 ret = lxc_count_file_lines(path);
2271 if (ret != -1)
2272 count += ret;
2273 free(path);
2274
2275 (void)closedir(dir);
2276
2277 return count;
2278 }
2279
2280 static int cgfsng_nrtasks(void *hdata)
2281 {
2282 int count;
2283 char *path;
2284 struct cgfsng_handler_data *d = hdata;
2285
2286 if (!d || !d->container_cgroup || !hierarchies)
2287 return -1;
2288
2289 path = must_make_path(hierarchies[0]->fullcgpath, NULL);
2290 count = recursive_count_nrtasks(path);
2291 free(path);
2292 return count;
2293 }
2294
2295 /* Only root needs to escape to the cgroup of its init. */
2296 static bool cgfsng_escape()
2297 {
2298 int i;
2299
2300 if (geteuid())
2301 return true;
2302
2303 for (i = 0; hierarchies[i]; i++) {
2304 int ret;
2305 char *fullpath;
2306
2307 fullpath = must_make_path(hierarchies[i]->mountpoint,
2308 hierarchies[i]->base_cgroup,
2309 "cgroup.procs", NULL);
2310 ret = lxc_write_to_file(fullpath, "0", 2, false);
2311 if (ret != 0) {
2312 SYSERROR("Failed to escape to cgroup \"%s\"", fullpath);
2313 free(fullpath);
2314 return false;
2315 }
2316 free(fullpath);
2317 }
2318
2319 return true;
2320 }
2321
2322 static int cgfsng_num_hierarchies(void)
2323 {
2324 int i;
2325
2326 for (i = 0; hierarchies[i]; i++)
2327 ;
2328
2329 return i;
2330 }
2331
2332 static bool cgfsng_get_hierarchies(int n, char ***out)
2333 {
2334 int i;
2335
2336 /* sanity check n */
2337 for (i = 0; i < n; i++)
2338 if (!hierarchies[i])
2339 return false;
2340
2341 *out = hierarchies[i]->controllers;
2342
2343 return true;
2344 }
2345
2346 #define THAWED "THAWED"
2347 #define THAWED_LEN (strlen(THAWED))
2348
2349 /* TODO: If the unified cgroup hierarchy grows a freezer controller this needs
2350 * to be adapted.
2351 */
2352 static bool cgfsng_unfreeze(void *hdata)
2353 {
2354 int ret;
2355 char *fullpath;
2356 struct hierarchy *h;
2357
2358 h = get_hierarchy("freezer");
2359 if (!h)
2360 return false;
2361
2362 fullpath = must_make_path(h->fullcgpath, "freezer.state", NULL);
2363 ret = lxc_write_to_file(fullpath, THAWED, THAWED_LEN, false);
2364 free(fullpath);
2365 if (ret < 0)
2366 return false;
2367
2368 return true;
2369 }
2370
2371 static const char *cgfsng_get_cgroup(void *hdata, const char *controller)
2372 {
2373 struct hierarchy *h;
2374
2375 h = get_hierarchy(controller);
2376 if (!h) {
2377 SYSERROR("Failed to find hierarchy for controller \"%s\"",
2378 controller ? controller : "(null)");
2379 return NULL;
2380 }
2381
2382 return h->fullcgpath ? h->fullcgpath + strlen(h->mountpoint) : NULL;
2383 }
2384
2385 /* Given a cgroup path returned from lxc_cmd_get_cgroup_path, build a full path,
2386 * which must be freed by the caller.
2387 */
2388 static inline char *build_full_cgpath_from_monitorpath(struct hierarchy *h,
2389 const char *inpath,
2390 const char *filename)
2391 {
2392 return must_make_path(h->mountpoint, inpath, filename, NULL);
2393 }
2394
2395 /* Technically, we're always at a delegation boundary here (This is especially
2396 * true when cgroup namespaces are available.). The reasoning is that in order
2397 * for us to have been able to start a container in the first place the root
2398 * cgroup must have been a leaf node. Now, either the container's init system
2399 * has populated the cgroup and kept it as a leaf node or it has created
2400 * subtrees. In the former case we will simply attach to the leaf node we
2401 * created when we started the container in the latter case we create our own
2402 * cgroup for the attaching process.
2403 */
2404 static int __cg_unified_attach(const struct hierarchy *h, const char *name,
2405 const char *lxcpath, const char *pidstr,
2406 size_t pidstr_len, const char *controller)
2407 {
2408 int ret;
2409 size_t len;
2410 int fret = -1, idx = 0;
2411 char *base_path = NULL, *container_cgroup = NULL, *full_path = NULL;
2412
2413 container_cgroup = lxc_cmd_get_cgroup_path(name, lxcpath, controller);
2414 /* not running */
2415 if (!container_cgroup)
2416 return 0;
2417
2418 base_path = must_make_path(h->mountpoint, container_cgroup, NULL);
2419 full_path = must_make_path(base_path, "cgroup.procs", NULL);
2420 /* cgroup is populated */
2421 ret = lxc_write_to_file(full_path, pidstr, pidstr_len, false);
2422 if (ret < 0 && errno != EBUSY)
2423 goto on_error;
2424
2425 if (ret == 0)
2426 goto on_success;
2427
2428 free(full_path);
2429
2430 len = strlen(base_path) + sizeof("/lxc-1000") - 1 +
2431 sizeof("/cgroup-procs") - 1;
2432 full_path = must_alloc(len + 1);
2433 do {
2434 if (idx)
2435 ret = snprintf(full_path, len + 1, "%s/lxc-%d",
2436 base_path, idx);
2437 else
2438 ret = snprintf(full_path, len + 1, "%s/lxc", base_path);
2439 if (ret < 0 || (size_t)ret >= len + 1)
2440 goto on_error;
2441
2442 ret = mkdir_p(full_path, 0755);
2443 if (ret < 0 && errno != EEXIST)
2444 goto on_error;
2445
2446 strcat(full_path, "/cgroup.procs");
2447 ret = lxc_write_to_file(full_path, pidstr, len, false);
2448 if (ret == 0)
2449 goto on_success;
2450
2451 /* this is a non-leaf node */
2452 if (errno != EBUSY)
2453 goto on_error;
2454
2455 } while (++idx > 0 && idx < 1000);
2456
2457 on_success:
2458 if (idx < 1000)
2459 fret = 0;
2460
2461 on_error:
2462 free(base_path);
2463 free(container_cgroup);
2464 free(full_path);
2465
2466 return fret;
2467 }
2468
2469 static bool cgfsng_attach(const char *name, const char *lxcpath, pid_t pid)
2470 {
2471 int i, len, ret;
2472 char pidstr[25];
2473
2474 len = snprintf(pidstr, 25, "%d", pid);
2475 if (len < 0 || len >= 25)
2476 return false;
2477
2478 for (i = 0; hierarchies[i]; i++) {
2479 char *path;
2480 char *fullpath = NULL;
2481 struct hierarchy *h = hierarchies[i];
2482
2483 if (h->version == CGROUP2_SUPER_MAGIC) {
2484 ret = __cg_unified_attach(h, name, lxcpath, pidstr, len,
2485 h->controllers[0]);
2486 if (ret < 0)
2487 return false;
2488
2489 continue;
2490 }
2491
2492 path = lxc_cmd_get_cgroup_path(name, lxcpath, h->controllers[0]);
2493 /* not running */
2494 if (!path)
2495 continue;
2496
2497 fullpath = build_full_cgpath_from_monitorpath(h, path, "cgroup.procs");
2498 ret = lxc_write_to_file(fullpath, pidstr, len, false);
2499 if (ret < 0) {
2500 SYSERROR("Failed to attach %d to %s", (int)pid, fullpath);
2501 free(fullpath);
2502 return false;
2503 }
2504 free(fullpath);
2505 }
2506
2507 return true;
2508 }
2509
2510 /* Called externally (i.e. from 'lxc-cgroup') to query cgroup limits. Here we
2511 * don't have a cgroup_data set up, so we ask the running container through the
2512 * commands API for the cgroup path.
2513 */
2514 static int cgfsng_get(const char *filename, char *value, size_t len,
2515 const char *name, const char *lxcpath)
2516 {
2517 int ret = -1;
2518 size_t controller_len;
2519 char *controller, *p, *path;
2520 struct hierarchy *h;
2521
2522 controller_len = strlen(filename);
2523 controller = alloca(controller_len + 1);
2524 strcpy(controller, filename);
2525 p = strchr(controller, '.');
2526 if (p)
2527 *p = '\0';
2528
2529 path = lxc_cmd_get_cgroup_path(name, lxcpath, controller);
2530 /* not running */
2531 if (!path)
2532 return -1;
2533
2534 h = get_hierarchy(controller);
2535 if (h) {
2536 char *fullpath;
2537
2538 fullpath = build_full_cgpath_from_monitorpath(h, path, filename);
2539 ret = lxc_read_from_file(fullpath, value, len);
2540 free(fullpath);
2541 }
2542 free(path);
2543
2544 return ret;
2545 }
2546
2547 /* Called externally (i.e. from 'lxc-cgroup') to set new cgroup limits. Here we
2548 * don't have a cgroup_data set up, so we ask the running container through the
2549 * commands API for the cgroup path.
2550 */
2551 static int cgfsng_set(const char *filename, const char *value, const char *name,
2552 const char *lxcpath)
2553 {
2554 int ret = -1;
2555 size_t controller_len;
2556 char *controller, *p, *path;
2557 struct hierarchy *h;
2558
2559 controller_len = strlen(filename);
2560 controller = alloca(controller_len + 1);
2561 strcpy(controller, filename);
2562 p = strchr(controller, '.');
2563 if (p)
2564 *p = '\0';
2565
2566 path = lxc_cmd_get_cgroup_path(name, lxcpath, controller);
2567 /* not running */
2568 if (!path)
2569 return -1;
2570
2571 h = get_hierarchy(controller);
2572 if (h) {
2573 char *fullpath;
2574
2575 fullpath = build_full_cgpath_from_monitorpath(h, path, filename);
2576 ret = lxc_write_to_file(fullpath, value, strlen(value), false);
2577 free(fullpath);
2578 }
2579 free(path);
2580
2581 return ret;
2582 }
2583
2584 /* take devices cgroup line
2585 * /dev/foo rwx
2586 * and convert it to a valid
2587 * type major:minor mode
2588 * line. Return <0 on error. Dest is a preallocated buffer long enough to hold
2589 * the output.
2590 */
2591 static int convert_devpath(const char *invalue, char *dest)
2592 {
2593 int n_parts;
2594 char *p, *path, type;
2595 unsigned long minor, major;
2596 struct stat sb;
2597 int ret = -EINVAL;
2598 char *mode = NULL;
2599
2600 path = must_copy_string(invalue);
2601
2602 /* Read path followed by mode. Ignore any trailing text.
2603 * A ' # comment' would be legal. Technically other text is not
2604 * legal, we could check for that if we cared to.
2605 */
2606 for (n_parts = 1, p = path; *p && n_parts < 3; p++) {
2607 if (*p != ' ')
2608 continue;
2609 *p = '\0';
2610
2611 if (n_parts != 1)
2612 break;
2613 p++;
2614 n_parts++;
2615
2616 while (*p == ' ')
2617 p++;
2618
2619 mode = p;
2620
2621 if (*p == '\0')
2622 goto out;
2623 }
2624
2625 if (n_parts == 1)
2626 goto out;
2627
2628 ret = stat(path, &sb);
2629 if (ret < 0)
2630 goto out;
2631
2632 mode_t m = sb.st_mode & S_IFMT;
2633 switch (m) {
2634 case S_IFBLK:
2635 type = 'b';
2636 break;
2637 case S_IFCHR:
2638 type = 'c';
2639 break;
2640 default:
2641 ERROR("Unsupported device type %i for \"%s\"", m, path);
2642 ret = -EINVAL;
2643 goto out;
2644 }
2645
2646 major = MAJOR(sb.st_rdev);
2647 minor = MINOR(sb.st_rdev);
2648 ret = snprintf(dest, 50, "%c %lu:%lu %s", type, major, minor, mode);
2649 if (ret < 0 || ret >= 50) {
2650 ERROR("Error on configuration value \"%c %lu:%lu %s\" (max 50 "
2651 "chars)", type, major, minor, mode);
2652 ret = -ENAMETOOLONG;
2653 goto out;
2654 }
2655 ret = 0;
2656
2657 out:
2658 free(path);
2659 return ret;
2660 }
2661
2662 /* Called from setup_limits - here we have the container's cgroup_data because
2663 * we created the cgroups.
2664 */
2665 static int cg_legacy_set_data(const char *filename, const char *value,
2666 struct cgfsng_handler_data *d)
2667 {
2668 size_t len;
2669 char *fullpath, *p;
2670 /* "b|c <2^64-1>:<2^64-1> r|w|m" = 47 chars max */
2671 char converted_value[50];
2672 struct hierarchy *h;
2673 int ret = 0;
2674 char *controller = NULL;
2675
2676 len = strlen(filename);
2677 controller = alloca(len + 1);
2678 strcpy(controller, filename);
2679 p = strchr(controller, '.');
2680 if (p)
2681 *p = '\0';
2682
2683 if (strcmp("devices.allow", filename) == 0 && value[0] == '/') {
2684 ret = convert_devpath(value, converted_value);
2685 if (ret < 0)
2686 return ret;
2687 value = converted_value;
2688 }
2689
2690 h = get_hierarchy(controller);
2691 if (!h) {
2692 ERROR("Failed to setup limits for the \"%s\" controller. "
2693 "The controller seems to be unused by \"cgfsng\" cgroup "
2694 "driver or not enabled on the cgroup hierarchy",
2695 controller);
2696 errno = ENOENT;
2697 return -ENOENT;
2698 }
2699
2700 fullpath = must_make_path(h->fullcgpath, filename, NULL);
2701 ret = lxc_write_to_file(fullpath, value, strlen(value), false);
2702 free(fullpath);
2703 return ret;
2704 }
2705
2706 static bool __cg_legacy_setup_limits(void *hdata,
2707 struct lxc_list *cgroup_settings,
2708 bool do_devices)
2709 {
2710 struct lxc_list *iterator, *next, *sorted_cgroup_settings;
2711 struct lxc_cgroup *cg;
2712 struct cgfsng_handler_data *d = hdata;
2713 bool ret = false;
2714
2715 if (lxc_list_empty(cgroup_settings))
2716 return true;
2717
2718 sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
2719 if (!sorted_cgroup_settings)
2720 return false;
2721
2722 lxc_list_for_each(iterator, sorted_cgroup_settings) {
2723 cg = iterator->elem;
2724
2725 if (do_devices == !strncmp("devices", cg->subsystem, 7)) {
2726 if (cg_legacy_set_data(cg->subsystem, cg->value, d)) {
2727 if (do_devices && (errno == EACCES || errno == EPERM)) {
2728 WARN("Failed to set \"%s\" to \"%s\"",
2729 cg->subsystem, cg->value);
2730 continue;
2731 }
2732 WARN("Failed to set \"%s\" to \"%s\"",
2733 cg->subsystem, cg->value);
2734 goto out;
2735 }
2736 DEBUG("Set controller \"%s\" set to \"%s\"",
2737 cg->subsystem, cg->value);
2738 }
2739 }
2740
2741 ret = true;
2742 INFO("Limits for the legacy cgroup hierarchies have been setup");
2743 out:
2744 lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) {
2745 lxc_list_del(iterator);
2746 free(iterator);
2747 }
2748 free(sorted_cgroup_settings);
2749 return ret;
2750 }
2751
2752 static bool __cg_unified_setup_limits(void *hdata,
2753 struct lxc_list *cgroup_settings)
2754 {
2755 struct lxc_list *iterator;
2756 struct hierarchy *h = unified;
2757
2758 if (lxc_list_empty(cgroup_settings))
2759 return true;
2760
2761 if (!h)
2762 return false;
2763
2764 lxc_list_for_each(iterator, cgroup_settings) {
2765 int ret;
2766 char *fullpath;
2767 struct lxc_cgroup *cg = iterator->elem;
2768
2769 fullpath = must_make_path(h->fullcgpath, cg->subsystem, NULL);
2770 ret = lxc_write_to_file(fullpath, cg->value, strlen(cg->value), false);
2771 free(fullpath);
2772 if (ret < 0) {
2773 SYSERROR("Failed to set \"%s\" to \"%s\"",
2774 cg->subsystem, cg->value);
2775 return false;
2776 }
2777 TRACE("Set \"%s\" to \"%s\"", cg->subsystem, cg->value);
2778 }
2779
2780 INFO("Limits for the unified cgroup hierarchy have been setup");
2781 return true;
2782 }
2783
2784 static bool cgfsng_setup_limits(void *hdata, struct lxc_conf *conf,
2785 bool do_devices)
2786 {
2787 bool bret;
2788
2789 bret = __cg_legacy_setup_limits(hdata, &conf->cgroup, do_devices);
2790 if (!bret)
2791 return false;
2792
2793 return __cg_unified_setup_limits(hdata, &conf->cgroup2);
2794 }
2795
2796 static struct cgroup_ops cgfsng_ops = {
2797 .init = cgfsng_init,
2798 .destroy = cgfsng_destroy,
2799 .create = cgfsng_create,
2800 .enter = cgfsng_enter,
2801 .escape = cgfsng_escape,
2802 .num_hierarchies = cgfsng_num_hierarchies,
2803 .get_hierarchies = cgfsng_get_hierarchies,
2804 .get_cgroup = cgfsng_get_cgroup,
2805 .get = cgfsng_get,
2806 .set = cgfsng_set,
2807 .unfreeze = cgfsng_unfreeze,
2808 .setup_limits = cgfsng_setup_limits,
2809 .driver = "cgfsng",
2810 .version = "1.0.0",
2811 .attach = cgfsng_attach,
2812 .chown = cgfsng_chown,
2813 .mount_cgroup = cgfsng_mount,
2814 .nrtasks = cgfsng_nrtasks,
2815 };