X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=src%2Flxc%2Fcgroups%2Fcgfsng.c;h=b0f90f222971b4ed945ee282761b3174f33e43f6;hb=c05b17bd66142da80ab9031cb19ee8e4441c59e9;hp=97913209c7fddc2a7ebe3d64af87917a81e10e7f;hpb=15418afe93e4b1cc196b56f99b58086efba2bdd7;p=mirror_lxc.git diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c index 97913209c..b0f90f222 100644 --- a/src/lxc/cgroups/cgfsng.c +++ b/src/lxc/cgroups/cgfsng.c @@ -31,7 +31,7 @@ * * This new implementation assumes that cgroup filesystems are mounted * under /sys/fs/cgroup/clist where clist is either the controller, or - * a comman-separated list of controllers. + * a comma-separated list of controllers. */ #ifndef _GNU_SOURCE @@ -58,6 +58,7 @@ #include "config.h" #include "log.h" #include "macro.h" +#include "memory_utils.h" #include "storage/storage.h" #include "utils.h" @@ -84,12 +85,6 @@ static void free_string_list(char **clist) free(clist); } -/* Allocate a pointer, do not fail. */ -static void *must_alloc(size_t sz) -{ - return must_realloc(NULL, sz); -} - /* Given a pointer to a null-terminated array of pointers, realloc to add one * entry, and point the new entry to NULL. Do not fail. Return the index to the * second-to-last entry - that is, the one which is now available for use @@ -134,7 +129,7 @@ static char *cg_legacy_must_prefix_named(char *entry) char *prefixed; len = strlen(entry); - prefixed = must_alloc(len + 6); + prefixed = must_realloc(NULL, len + 6); memcpy(prefixed, "name=", STRLITERALLEN("name=")); memcpy(prefixed + STRLITERALLEN("name="), entry, len); @@ -237,10 +232,11 @@ static void append_line(char **dest, size_t oldlen, char *new, size_t newlen) /* Slurp in a whole file */ static char *read_file(const char *fnam) { - FILE *f; - char *line = NULL, *buf = NULL; - size_t len = 0, fulllen = 0; + __do_free char *line = NULL; + __do_fclose FILE *f = NULL; int linelen; + char *buf = NULL; + size_t len = 0, fulllen = 0; f = fopen(fnam, "r"); if (!f) @@ -249,8 +245,6 @@ static char *read_file(const char *fnam) append_line(&buf, fulllen, line, linelen); fulllen += linelen; } - fclose(f); - free(line); return buf; } @@ -326,6 +320,7 @@ static char *lxc_cpumask_to_cpulist(uint32_t *bitarr, size_t nbits) { int ret; size_t i; + char *tmp = NULL; char **cpulist = NULL; char numstr[INTTYPE_TO_STRLEN(size_t)] = {0}; @@ -349,7 +344,10 @@ static char *lxc_cpumask_to_cpulist(uint32_t *bitarr, size_t nbits) if (!cpulist) return NULL; - return lxc_string_join(",", (const char **)cpulist, false); + tmp = lxc_string_join(",", (const char **)cpulist, false); + lxc_free_array((void **)cpulist, free); + + return tmp; } static ssize_t get_max_cpus(char *cpulist) @@ -384,14 +382,18 @@ static ssize_t get_max_cpus(char *cpulist) } #define __ISOL_CPUS "/sys/devices/system/cpu/isolated" +#define __OFFLINE_CPUS "/sys/devices/system/cpu/offline" static bool cg_legacy_filter_and_set_cpus(char *path, bool am_initialized) { + __do_free char *cpulist = NULL, *fpath = NULL, *isolcpus = NULL, + *offlinecpus = NULL, *posscpus = NULL; + __do_free uint32_t *isolmask = NULL, *offlinemask = NULL, + *possmask = NULL; int ret; ssize_t i; - char *lastslash, *fpath, oldv; - ssize_t maxisol = 0, maxposs = 0; - char *cpulist = NULL, *isolcpus = NULL, *posscpus = NULL; - uint32_t *isolmask = NULL, *possmask = NULL; + char oldv; + char *lastslash; + ssize_t maxisol = 0, maxoffline = 0, maxposs = 0; bool bret = false, flipped_bit = false; lastslash = strrchr(path, '/'); @@ -402,80 +404,91 @@ static bool cg_legacy_filter_and_set_cpus(char *path, bool am_initialized) oldv = *lastslash; *lastslash = '\0'; fpath = must_make_path(path, "cpuset.cpus", NULL); + *lastslash = oldv; posscpus = read_file(fpath); if (!posscpus) { SYSERROR("Failed to read file \"%s\"", fpath); - goto on_error; + return false; } /* Get maximum number of cpus found in possible cpuset. */ maxposs = get_max_cpus(posscpus); if (maxposs < 0 || maxposs >= INT_MAX - 1) - goto on_error; + return false; - if (!file_exists(__ISOL_CPUS)) { - /* This system doesn't expose isolated cpus. */ - DEBUG("The path \""__ISOL_CPUS"\" to read isolated cpus from does not exist"); - cpulist = posscpus; - /* No isolated cpus but we weren't already initialized by - * someone. We should simply copy the parents cpuset.cpus - * values. - */ - if (!am_initialized) { - DEBUG("Copying cpu settings of parent cgroup"); - goto copy_parent; + if (file_exists(__ISOL_CPUS)) { + isolcpus = read_file(__ISOL_CPUS); + if (!isolcpus) { + SYSERROR("Failed to read file \"%s\"", __ISOL_CPUS); + return false; } - /* No isolated cpus but we were already initialized by someone. - * Nothing more to do for us. - */ - goto on_success; - } - isolcpus = read_file(__ISOL_CPUS); - if (!isolcpus) { - SYSERROR("Failed to read file \""__ISOL_CPUS"\""); - goto on_error; - } - if (!isdigit(isolcpus[0])) { - TRACE("No isolated cpus detected"); - cpulist = posscpus; - /* No isolated cpus but we weren't already initialized by - * someone. We should simply copy the parents cpuset.cpus - * values. - */ - if (!am_initialized) { - DEBUG("Copying cpu settings of parent cgroup"); - goto copy_parent; + if (isdigit(isolcpus[0])) { + /* Get maximum number of cpus found in isolated cpuset. */ + maxisol = get_max_cpus(isolcpus); + if (maxisol < 0 || maxisol >= INT_MAX - 1) + return false; } - /* No isolated cpus but we were already initialized by someone. - * Nothing more to do for us. - */ - goto on_success; + + if (maxposs < maxisol) + maxposs = maxisol; + maxposs++; + } else { + TRACE("The path \""__ISOL_CPUS"\" to read isolated cpus from does not exist"); } - /* Get maximum number of cpus found in isolated cpuset. */ - maxisol = get_max_cpus(isolcpus); - if (maxisol < 0 || maxisol >= INT_MAX - 1) - goto on_error; + if (file_exists(__OFFLINE_CPUS)) { + offlinecpus = read_file(__OFFLINE_CPUS); + if (!offlinecpus) { + SYSERROR("Failed to read file \"%s\"", __OFFLINE_CPUS); + return false; + } + + if (isdigit(offlinecpus[0])) { + /* Get maximum number of cpus found in offline cpuset. */ + maxoffline = get_max_cpus(offlinecpus); + if (maxoffline < 0 || maxoffline >= INT_MAX - 1) + return false; + } + + if (maxposs < maxoffline) + maxposs = maxoffline; + maxposs++; + } else { + TRACE("The path \""__OFFLINE_CPUS"\" to read offline cpus from does not exist"); + } - if (maxposs < maxisol) - maxposs = maxisol; - maxposs++; + if ((maxisol == 0) && (maxoffline == 0)) { + cpulist = move_ptr(posscpus); + goto copy_parent; + } possmask = lxc_cpumask(posscpus, maxposs); if (!possmask) { ERROR("Failed to create cpumask for possible cpus"); - goto on_error; + return false; } - isolmask = lxc_cpumask(isolcpus, maxposs); - if (!isolmask) { - ERROR("Failed to create cpumask for isolated cpus"); - goto on_error; + if (maxisol > 0) { + isolmask = lxc_cpumask(isolcpus, maxposs); + if (!isolmask) { + ERROR("Failed to create cpumask for isolated cpus"); + return false; + } + } + + if (maxoffline > 0) { + offlinemask = lxc_cpumask(offlinecpus, maxposs); + if (!offlinemask) { + ERROR("Failed to create cpumask for offline cpus"); + return false; + } } for (i = 0; i <= maxposs; i++) { - if (!is_set(i, isolmask) || !is_set(i, possmask)) + if ((isolmask && !is_set(i, isolmask)) || + (offlinemask && !is_set(i, offlinemask)) || + !is_set(i, possmask)) continue; flipped_bit = true; @@ -483,51 +496,41 @@ static bool cg_legacy_filter_and_set_cpus(char *path, bool am_initialized) } if (!flipped_bit) { - DEBUG("No isolated cpus present in cpuset"); - goto on_success; + DEBUG("No isolated or offline cpus present in cpuset"); + return true; } - DEBUG("Removed isolated cpus from cpuset"); + DEBUG("Removed isolated or offline cpus from cpuset"); cpulist = lxc_cpumask_to_cpulist(possmask, maxposs); if (!cpulist) { ERROR("Failed to create cpu list"); - goto on_error; + return false; } copy_parent: - *lastslash = oldv; - free(fpath); - fpath = must_make_path(path, "cpuset.cpus", NULL); - ret = lxc_write_to_file(fpath, cpulist, strlen(cpulist), false, 0666); - if (ret < 0) { - SYSERROR("Failed to write cpu list to \"%s\"", fpath); - goto on_error; - } - -on_success: - bret = true; - -on_error: - free(fpath); - - free(isolcpus); - free(isolmask); + if (!am_initialized) { + fpath = must_make_path(path, "cpuset.cpus", NULL); + ret = lxc_write_to_file(fpath, cpulist, strlen(cpulist), false, + 0666); + if (ret < 0) { + SYSERROR("Failed to write cpu list to \"%s\"", fpath); + return false; + } - if (posscpus != cpulist) - free(posscpus); - free(possmask); + TRACE("Copied cpu settings of parent cgroup"); + } - free(cpulist); - return bret; + return true; } /* Copy contents of parent(@path)/@file to @path/@file */ static bool copy_parent_file(char *path, char *file) { + __do_free char *child_path = NULL, *parent_path = NULL, *value = NULL; int ret; - char *fpath, *lastslash, oldv; + char oldv; int len = 0; - char *value = NULL; + char *lastslash = NULL; lastslash = strrchr(path, '/'); if (!lastslash) { @@ -536,31 +539,26 @@ static bool copy_parent_file(char *path, char *file) } oldv = *lastslash; *lastslash = '\0'; - fpath = must_make_path(path, file, NULL); - len = lxc_read_from_file(fpath, NULL, 0); - if (len <= 0) - goto on_error; + parent_path = must_make_path(path, file, NULL); + len = lxc_read_from_file(parent_path, NULL, 0); + if (len <= 0) { + SYSERROR("Failed to determine buffer size"); + return false; + } - value = must_alloc(len + 1); - ret = lxc_read_from_file(fpath, value, len); - if (ret != len) - goto on_error; - free(fpath); + value = must_realloc(NULL, len + 1); + ret = lxc_read_from_file(parent_path, value, len); + if (ret != len) { + SYSERROR("Failed to read from parent file \"%s\"", parent_path); + return false; + } *lastslash = oldv; - fpath = must_make_path(path, file, NULL); - ret = lxc_write_to_file(fpath, value, len, false, 0666); + child_path = must_make_path(path, file, NULL); + ret = lxc_write_to_file(child_path, value, len, false, 0666); if (ret < 0) - SYSERROR("Failed to write \"%s\" to file \"%s\"", value, fpath); - free(fpath); - free(value); + SYSERROR("Failed to write \"%s\" to file \"%s\"", value, child_path); return ret >= 0; - -on_error: - SYSERROR("Failed to read file \"%s\"", fpath); - free(fpath); - free(value); - return false; } /* Initialize the cpuset hierarchy in first directory of @gname and set @@ -570,9 +568,10 @@ on_error: */ static bool cg_legacy_handle_cpuset_hierarchy(struct hierarchy *h, char *cgname) { + __do_free char *cgpath = NULL, *clonechildrenpath = NULL; int ret; char v; - char *cgpath, *clonechildrenpath, *slash; + char *slash; if (!string_in_list(h->controllers, "cpuset")) return true; @@ -591,60 +590,46 @@ static bool cg_legacy_handle_cpuset_hierarchy(struct hierarchy *h, char *cgname) if (ret < 0) { if (errno != EEXIST) { SYSERROR("Failed to create directory \"%s\"", cgpath); - free(cgpath); return false; } } clonechildrenpath = must_make_path(cgpath, "cgroup.clone_children", NULL); /* unified hierarchy doesn't have clone_children */ - if (!file_exists(clonechildrenpath)) { - free(clonechildrenpath); - free(cgpath); + if (!file_exists(clonechildrenpath)) return true; - } ret = lxc_read_from_file(clonechildrenpath, &v, 1); if (ret < 0) { SYSERROR("Failed to read file \"%s\"", clonechildrenpath); - free(clonechildrenpath); - free(cgpath); return false; } /* Make sure any isolated cpus are removed from cpuset.cpus. */ if (!cg_legacy_filter_and_set_cpus(cgpath, v == '1')) { SYSERROR("Failed to remove isolated cpus"); - free(clonechildrenpath); - free(cgpath); return false; } /* Already set for us by someone else. */ if (v == '1') { DEBUG("\"cgroup.clone_children\" was already set to \"1\""); - free(clonechildrenpath); - free(cgpath); return true; } /* copy parent's settings */ if (!copy_parent_file(cgpath, "cpuset.mems")) { SYSERROR("Failed to copy \"cpuset.mems\" settings"); - free(cgpath); - free(clonechildrenpath); return false; } - free(cgpath); ret = lxc_write_to_file(clonechildrenpath, "1", 1, false, 0666); if (ret < 0) { /* Set clone_children so children inherit our settings */ SYSERROR("Failed to write 1 to \"%s\"", clonechildrenpath); - free(clonechildrenpath); return false; } - free(clonechildrenpath); + return true; } @@ -709,11 +694,6 @@ static bool all_controllers_found(struct cgroup_ops *ops) char **cur; struct hierarchy **hlist = ops->hierarchies; - if (!controller_found(hlist, "freezer")) { - ERROR("No freezer controller mountpoint found"); - return false; - } - if (!ops->cgroup_use) return true; @@ -738,7 +718,7 @@ static char **cg_hybrid_get_controllers(char **klist, char **nlist, char *line, * for legacy hierarchies. */ int i; - char *dup, *p2, *tok; + char *p2, *tok; char *p = line, *sep = ","; char **aret = NULL; @@ -766,19 +746,18 @@ static char **cg_hybrid_get_controllers(char **klist, char **nlist, char *line, *p2 = '\0'; if (type == CGROUP_SUPER_MAGIC) { + __do_free char *dup = NULL; + /* strdup() here for v1 hierarchies. Otherwise * lxc_iterate_parts() will destroy mountpoints such as * "/sys/fs/cgroup/cpu,cpuacct". */ - dup = strdup(p); + dup = must_copy_string(p); if (!dup) return NULL; - lxc_iterate_parts(tok, dup, sep) { + lxc_iterate_parts (tok, dup, sep) must_append_controller(klist, nlist, &aret, tok); - } - - free(dup); } *p2 = ' '; @@ -797,7 +776,8 @@ static char **cg_unified_make_empty_controller(void) static char **cg_unified_get_controllers(const char *file) { - char *buf, *tok; + __do_free char *buf = NULL; + char *tok; char *sep = " \t\n"; char **aret = NULL; @@ -814,7 +794,6 @@ static char **cg_unified_get_controllers(const char *file) aret[newentry] = copy; } - free(buf); return aret; } @@ -824,13 +803,14 @@ static struct hierarchy *add_hierarchy(struct hierarchy ***h, char **clist, char struct hierarchy *new; int newentry; - new = must_alloc(sizeof(*new)); + new = must_realloc(NULL, sizeof(*new)); new->controllers = clist; new->mountpoint = mountpoint; new->container_base_path = container_base_path; new->container_full_path = NULL; new->monitor_full_path = NULL; new->version = type; + new->cgroup2_chown = NULL; newentry = append_null_to_list((void ***)h); (*h)[newentry] = new; @@ -863,7 +843,7 @@ static char *cg_hybrid_get_mountpoint(char *line) *p2 = '\0'; len = strlen(p); - sret = must_alloc(len + 1); + sret = must_realloc(NULL, len + 1); memcpy(sret, p, len); sret[len] = '\0'; return sret; @@ -879,7 +859,7 @@ static char *copy_to_eol(char *p) return NULL; len = p2 - p; - sret = must_alloc(len + 1); + sret = must_realloc(NULL, len + 1); memcpy(sret, p, len); sret[len] = '\0'; return sret; @@ -890,7 +870,8 @@ static char *copy_to_eol(char *p) */ static bool controller_in_clist(char *cgline, char *c) { - char *tok, *eol, *tmp; + __do_free char *tmp = NULL; + char *tok, *eol; size_t len; eol = strchr(cgline, ':'); @@ -898,14 +879,13 @@ static bool controller_in_clist(char *cgline, char *c) return false; len = eol - cgline; - tmp = alloca(len + 1); + tmp = must_realloc(NULL, len + 1); memcpy(tmp, cgline, len); tmp[len] = '\0'; - lxc_iterate_parts(tok, tmp, ",") { + lxc_iterate_parts(tok, tmp, ",") if (strcmp(tok, c) == 0) return true; - } return false; } @@ -957,8 +937,8 @@ static void must_append_string(char ***list, char *entry) static int get_existing_subsystems(char ***klist, char ***nlist) { - FILE *f; - char *line = NULL; + __do_free char *line = NULL; + __do_fclose FILE *f = NULL; size_t len = 0; f = fopen("/proc/self/cgroup", "r"); @@ -996,8 +976,6 @@ static int get_existing_subsystems(char ***klist, char ***nlist) } } - free(line); - fclose(f); return 0; } @@ -1119,6 +1097,9 @@ __cgfsng_ops static void cgfsng_payload_destroy(struct cgroup_ops *ops, int ret; struct generic_userns_exec_data wrap; + if (!ops->hierarchies) + return; + wrap.origuid = 0; wrap.container_cgroup = ops->container_cgroup; wrap.hierarchies = ops->hierarchies; @@ -1139,7 +1120,6 @@ __cgfsng_ops static void cgfsng_monitor_destroy(struct cgroup_ops *ops, struct lxc_handler *handler) { int len; - char *pivot_path; struct lxc_conf *conf = handler->conf; char pidstr[INTTYPE_TO_STRLEN(pid_t)]; @@ -1151,7 +1131,10 @@ __cgfsng_ops static void cgfsng_monitor_destroy(struct cgroup_ops *ops, return; for (int i = 0; ops->hierarchies[i]; i++) { + __do_free char *pivot_path = NULL; int ret; + char *chop; + char pivot_cgroup[] = PIVOT_CGROUP; struct hierarchy *h = ops->hierarchies[i]; if (!h->monitor_full_path) @@ -1169,32 +1152,49 @@ __cgfsng_ops static void cgfsng_monitor_destroy(struct cgroup_ops *ops, PIVOT_CGROUP, "cgroup.procs", NULL); + chop = strrchr(pivot_path, '/'); + if (chop) + *chop = '\0'; + + /* + * Make sure not to pass in the ro string literal PIVOT_CGROUP + * here. + */ + if (!cg_legacy_handle_cpuset_hierarchy(h, pivot_cgroup)) { + WARN("Failed to handle legacy cpuset controller"); + continue; + } + ret = mkdir_p(pivot_path, 0755); - if (ret < 0 && errno != EEXIST) - goto next; + if (ret < 0 && errno != EEXIST) { + SYSWARN("Failed to create cgroup \"%s\"\n", pivot_path); + continue; + } + + if (chop) + *chop = '/'; /* Move ourselves into the pivot cgroup to delete our own * cgroup. */ ret = lxc_write_to_file(pivot_path, pidstr, len, false, 0666); - if (ret != 0) - goto next; + if (ret != 0) { + SYSWARN("Failed to move monitor %s to \"%s\"\n", pidstr, pivot_path); + continue; + } ret = recursive_destroy(h->monitor_full_path); if (ret < 0) WARN("Failed to destroy \"%s\"", h->monitor_full_path); - - next: - free(pivot_path); } } static bool cg_unified_create_cgroup(struct hierarchy *h, char *cgname) { + __do_free char *add_controllers = NULL, *cgroup = NULL; size_t i, parts_len; char **it; size_t full_len = 0; - char *add_controllers = NULL, *cgroup = NULL; char **parts = NULL; bool bret = false; @@ -1235,12 +1235,11 @@ static bool cg_unified_create_cgroup(struct hierarchy *h, char *cgname) cgroup = must_make_path(h->mountpoint, h->container_base_path, NULL); for (i = 0; i < parts_len; i++) { int ret; - char *target; + __do_free char *target = NULL; cgroup = must_append_path(cgroup, parts[i], NULL); target = must_make_path(cgroup, "cgroup.subtree_control", NULL); ret = lxc_write_to_file(target, add_controllers, full_len, false, 0666); - free(target); if (ret < 0) { SYSERROR("Could not enable \"%s\" controllers in the " "unified cgroup \"%s\"", add_controllers, cgroup); @@ -1252,8 +1251,6 @@ static bool cg_unified_create_cgroup(struct hierarchy *h, char *cgname) on_error: lxc_free_array((void **)parts, free); - free(add_controllers); - free(cgroup); return bret; } @@ -1265,9 +1262,9 @@ static int mkdir_eexist_on_last(const char *dir, mode_t mode) orig_len = strlen(dir); do { + __do_free char *makeme; int ret; size_t cur_len; - char *makeme; dir = tmp + strspn(tmp, "/"); tmp = dir + strcspn(dir, "/"); @@ -1282,12 +1279,9 @@ static int mkdir_eexist_on_last(const char *dir, mode_t mode) if (ret < 0) { if ((errno != EEXIST) || (orig_len == cur_len)) { SYSERROR("Failed to create directory \"%s\"", makeme); - free(makeme); return -1; } } - free(makeme); - } while (tmp != dir); return 0; @@ -1354,16 +1348,19 @@ static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname, bool mo } __cgfsng_ops static inline bool cgfsng_monitor_create(struct cgroup_ops *ops, - struct lxc_handler *handler) + struct lxc_handler *handler) { - char *monitor_cgroup, *offset, *tmp; + __do_free char *monitor_cgroup = NULL; + char *offset, *tmp; int i, idx = 0; size_t len; - bool bret = false; struct lxc_conf *conf = handler->conf; if (!conf) - return bret; + return false; + + if (!ops->hierarchies) + return true; if (conf->cgroup_meta.dir) tmp = lxc_string_join("/", @@ -1374,29 +1371,29 @@ __cgfsng_ops static inline bool cgfsng_monitor_create(struct cgroup_ops *ops, else tmp = must_make_path(ops->monitor_pattern, handler->name, NULL); if (!tmp) - return bret; + return false; len = strlen(tmp) + 5; /* leave room for -NNN\0 */ - monitor_cgroup = must_alloc(len); - (void)strlcpy(monitor_cgroup, tmp, len); - free(tmp); + monitor_cgroup = must_realloc(tmp, len); offset = monitor_cgroup + len - 5; + *offset = 0; do { if (idx) { int ret = snprintf(offset, 5, "-%d", idx); if (ret < 0 || (size_t)ret >= 5) - goto on_error; + return false; } for (i = 0; ops->hierarchies[i]; i++) { - if (!monitor_create_path_for_hierarchy(ops->hierarchies[i], monitor_cgroup)) { - ERROR("Failed to create cgroup \"%s\"", ops->hierarchies[i]->monitor_full_path); - free(ops->hierarchies[i]->container_full_path); - ops->hierarchies[i]->container_full_path = NULL; - + if (!monitor_create_path_for_hierarchy(ops->hierarchies[i], + monitor_cgroup)) { + ERROR("Failed to create cgroup \"%s\"", + ops->hierarchies[i]->monitor_full_path); for (int j = 0; j < i; j++) - remove_path_for_hierarchy(ops->hierarchies[j], monitor_cgroup, true); + remove_path_for_hierarchy(ops->hierarchies[j], + monitor_cgroup, + true); idx++; break; @@ -1404,15 +1401,11 @@ __cgfsng_ops static inline bool cgfsng_monitor_create(struct cgroup_ops *ops, } } while (ops->hierarchies[i] && idx > 0 && idx < 1000); - if (idx < 1000) { - bret = true; - INFO("The monitor process uses \"%s\" as cgroup", monitor_cgroup); - } - -on_error: - free(monitor_cgroup); + if (idx == 1000) + return false; - return bret; + INFO("The monitor process uses \"%s\" as cgroup", monitor_cgroup); + return true; } /* Try to create the same cgroup in all hierarchies. Start with cgroup_pattern; @@ -1421,20 +1414,22 @@ on_error: __cgfsng_ops static inline bool cgfsng_payload_create(struct cgroup_ops *ops, struct lxc_handler *handler) { + __do_free char *container_cgroup = NULL, *tmp = NULL; int i; size_t len; - char *container_cgroup, *offset, *tmp; + char *offset; int idx = 0; struct lxc_conf *conf = handler->conf; - if (ops->container_cgroup) { - WARN("cgfsng_create called a second time: %s", ops->container_cgroup); + if (ops->container_cgroup) return false; - } if (!conf) return false; + if (!ops->hierarchies) + return true; + if (conf->cgroup_meta.dir) tmp = lxc_string_join("/", (const char *[]){conf->cgroup_meta.dir, handler->name, NULL}, false); else @@ -1445,53 +1440,38 @@ __cgfsng_ops static inline bool cgfsng_payload_create(struct cgroup_ops *ops, } len = strlen(tmp) + 5; /* leave room for -NNN\0 */ - container_cgroup = must_alloc(len); + container_cgroup = must_realloc(NULL, len); (void)strlcpy(container_cgroup, tmp, len); - free(tmp); offset = container_cgroup + len - 5; -again: - if (idx == 1000) { - ERROR("Too many conflicting cgroup names"); - goto out_free; - } - - if (idx) { - int ret; - - ret = snprintf(offset, 5, "-%d", idx); - if (ret < 0 || (size_t)ret >= 5) { - FILE *f = fopen("/dev/null", "w"); - if (f) { - fprintf(f, "Workaround for GCC7 bug: " - "https://gcc.gnu.org/bugzilla/" - "show_bug.cgi?id=78969"); - fclose(f); - } + do { + if (idx) { + int ret = snprintf(offset, 5, "-%d", idx); + if (ret < 0 || (size_t)ret >= 5) + return false; } - } - for (i = 0; ops->hierarchies[i]; i++) { - if (!container_create_path_for_hierarchy(ops->hierarchies[i], container_cgroup)) { - ERROR("Failed to create cgroup \"%s\"", ops->hierarchies[i]->container_full_path); - free(ops->hierarchies[i]->container_full_path); - ops->hierarchies[i]->container_full_path = NULL; - for (int j = 0; j < i; j++) - remove_path_for_hierarchy(ops->hierarchies[j], container_cgroup, false); - idx++; - goto again; + for (i = 0; ops->hierarchies[i]; i++) { + if (!container_create_path_for_hierarchy(ops->hierarchies[i], + container_cgroup)) { + ERROR("Failed to create cgroup \"%s\"", + ops->hierarchies[i]->container_full_path); + for (int j = 0; j < i; j++) + remove_path_for_hierarchy(ops->hierarchies[j], + container_cgroup, + false); + idx++; + break; + } } - } + } while (ops->hierarchies[i] && idx > 0 && idx < 1000); - ops->container_cgroup = container_cgroup; - INFO("The container uses \"%s\" as cgroup", container_cgroup); + if (idx == 1000) + return false; + INFO("The container process uses \"%s\" as cgroup", container_cgroup); + ops->container_cgroup = move_ptr(container_cgroup); return true; - -out_free: - free(container_cgroup); - - return false; } __cgfsng_ops static bool __do_cgroup_enter(struct cgroup_ops *ops, pid_t pid, @@ -1500,13 +1480,16 @@ __cgfsng_ops static bool __do_cgroup_enter(struct cgroup_ops *ops, pid_t pid, int len; char pidstr[INTTYPE_TO_STRLEN(pid_t)]; + if (!ops->hierarchies) + return true; + len = snprintf(pidstr, sizeof(pidstr), "%d", pid); if (len < 0 || (size_t)len >= sizeof(pidstr)) return false; for (int i = 0; ops->hierarchies[i]; i++) { int ret; - char *path; + __do_free char *path = NULL; if (monitor) path = must_make_path(ops->hierarchies[i]->monitor_full_path, @@ -1517,10 +1500,8 @@ __cgfsng_ops static bool __do_cgroup_enter(struct cgroup_ops *ops, pid_t pid, ret = lxc_write_to_file(path, pidstr, len, false, 0666); if (ret != 0) { SYSERROR("Failed to enter cgroup \"%s\"", path); - free(path); return false; } - free(path); } return true; @@ -1596,7 +1577,7 @@ static int chown_cgroup_wrapper(void *data) destuid = 0; for (i = 0; arg->hierarchies[i]; i++) { - char *fullpath; + __do_free char *fullpath = NULL; char *path = arg->hierarchies[i]->container_full_path; ret = chowmod(path, destuid, nsgid, 0775); @@ -1613,23 +1594,18 @@ static int chown_cgroup_wrapper(void *data) if (arg->hierarchies[i]->version == CGROUP_SUPER_MAGIC) { fullpath = must_make_path(path, "tasks", NULL); (void)chowmod(fullpath, destuid, nsgid, 0664); - free(fullpath); } fullpath = must_make_path(path, "cgroup.procs", NULL); (void)chowmod(fullpath, destuid, nsgid, 0664); - free(fullpath); if (arg->hierarchies[i]->version != CGROUP2_SUPER_MAGIC) continue; - fullpath = must_make_path(path, "cgroup.subtree_control", NULL); - (void)chowmod(fullpath, destuid, nsgid, 0664); - free(fullpath); - - fullpath = must_make_path(path, "cgroup.threads", NULL); - (void)chowmod(fullpath, destuid, nsgid, 0664); - free(fullpath); + for (char **p = arg->hierarchies[i]->cgroup2_chown; p && *p; p++) { + fullpath = must_make_path(path, *p, NULL); + (void)chowmod(fullpath, destuid, nsgid, 0664); + } } return 0; @@ -1643,6 +1619,9 @@ __cgfsng_ops static bool cgfsng_chown(struct cgroup_ops *ops, if (lxc_list_empty(&conf->id_map)) return true; + if (!ops->hierarchies) + return true; + wrap.origuid = geteuid(); wrap.path = NULL; wrap.hierarchies = ops->hierarchies; @@ -1668,14 +1647,14 @@ static bool cg_mount_needs_subdirs(int type) /* After $rootfs/sys/fs/container/controller/the/cg/path has been created, * remount controller ro if needed and bindmount the cgroupfs onto - * controll/the/cg/path. + * control/the/cg/path. */ static int cg_legacy_mount_controllers(int type, struct hierarchy *h, char *controllerpath, char *cgpath, const char *container_cgroup) { + __do_free char *sourcepath = NULL; int ret, remount_flags; - char *sourcepath; int flags = MS_BIND; if (type == LXC_AUTO_CGROUP_RO || type == LXC_AUTO_CGROUP_MIXED) { @@ -1708,7 +1687,6 @@ static int cg_legacy_mount_controllers(int type, struct hierarchy *h, ret = mount(sourcepath, cgpath, "cgroup", flags, NULL); if (ret < 0) { SYSERROR("Failed to mount \"%s\" onto \"%s\"", h->controllers[0], cgpath); - free(sourcepath); return -1; } INFO("Mounted \"%s\" onto \"%s\"", h->controllers[0], cgpath); @@ -1719,13 +1697,11 @@ static int cg_legacy_mount_controllers(int type, struct hierarchy *h, ret = mount(sourcepath, cgpath, "cgroup", remount_flags, NULL); if (ret < 0) { SYSERROR("Failed to remount \"%s\" ro", cgpath); - free(sourcepath); return -1; } INFO("Remounted %s read-only", cgpath); } - free(sourcepath); INFO("Completed second stage cgroup automounts for \"%s\"", cgpath); return 0; } @@ -1740,7 +1716,7 @@ static int __cg_mount_direct(int type, struct hierarchy *h, const char *controllerpath) { int ret; - char *controllers = NULL; + __do_free char *controllers = NULL; char *fstype = "cgroup2"; unsigned long flags = 0; @@ -1760,7 +1736,6 @@ static int __cg_mount_direct(int type, struct hierarchy *h, } ret = mount("cgroup", controllerpath, fstype, flags, controllers); - free(controllers); if (ret < 0) { SYSERROR("Failed to mount \"%s\" with cgroup filesystem type %s", controllerpath, fstype); return -1; @@ -1789,10 +1764,13 @@ __cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops, struct lxc_handler *handler, const char *root, int type) { + __do_free char *tmpfspath = NULL; int i, ret; - char *tmpfspath = NULL; bool has_cgns = false, retval = false, wants_force_mount = false; + if (!ops->hierarchies) + return true; + if ((type & LXC_AUTO_CGROUP_MASK) == 0) return true; @@ -1826,7 +1804,7 @@ __cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops, goto on_error; for (i = 0; ops->hierarchies[i]; i++) { - char *controllerpath, *path2; + __do_free char *controllerpath = NULL, *path2 = NULL; struct hierarchy *h = ops->hierarchies[i]; char *controller = strrchr(h->mountpoint, '/'); @@ -1835,15 +1813,12 @@ __cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops, controller++; controllerpath = must_make_path(tmpfspath, controller, NULL); - if (dir_exists(controllerpath)) { - free(controllerpath); + if (dir_exists(controllerpath)) continue; - } ret = mkdir(controllerpath, 0755); if (ret < 0) { SYSERROR("Error creating cgroup path: %s", controllerpath); - free(controllerpath); goto on_error; } @@ -1853,7 +1828,6 @@ __cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops, * need to mount the cgroups manually. */ ret = cg_mount_in_cgroup_namespace(type, h, controllerpath); - free(controllerpath); if (ret < 0) goto on_error; @@ -1861,45 +1835,35 @@ __cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops, } ret = cg_mount_cgroup_full(type, h, controllerpath); - if (ret < 0) { - free(controllerpath); + if (ret < 0) goto on_error; - } - if (!cg_mount_needs_subdirs(type)) { - free(controllerpath); + if (!cg_mount_needs_subdirs(type)) continue; - } path2 = must_make_path(controllerpath, h->container_base_path, ops->container_cgroup, NULL); ret = mkdir_p(path2, 0755); - if (ret < 0) { - free(controllerpath); - free(path2); + if (ret < 0) goto on_error; - } ret = cg_legacy_mount_controllers(type, h, controllerpath, path2, ops->container_cgroup); - free(controllerpath); - free(path2); if (ret < 0) goto on_error; } retval = true; on_error: - free(tmpfspath); return retval; } static int recursive_count_nrtasks(char *dirname) { + __do_free char *path = NULL; + __do_closedir DIR *dir = NULL; struct dirent *direntp; - DIR *dir; int count = 0, ret; - char *path; dir = opendir(dirname); if (!dir) @@ -1915,38 +1879,32 @@ static int recursive_count_nrtasks(char *dirname) path = must_make_path(dirname, direntp->d_name, NULL); if (lstat(path, &mystat)) - goto next; + continue; if (!S_ISDIR(mystat.st_mode)) - goto next; + continue; count += recursive_count_nrtasks(path); - next: - free(path); } path = must_make_path(dirname, "cgroup.procs", NULL); ret = lxc_count_file_lines(path); if (ret != -1) count += ret; - free(path); - - (void)closedir(dir); return count; } __cgfsng_ops static int cgfsng_nrtasks(struct cgroup_ops *ops) { + __do_free char *path = NULL; int count; - char *path; if (!ops->container_cgroup || !ops->hierarchies) return -1; path = must_make_path(ops->hierarchies[0]->container_full_path, NULL); count = recursive_count_nrtasks(path); - free(path); return count; } @@ -1956,12 +1914,12 @@ __cgfsng_ops static bool cgfsng_escape(const struct cgroup_ops *ops, { int i; - if (conf->cgroup_meta.relative || geteuid()) + if (conf->cgroup_meta.relative || geteuid() || !ops->hierarchies) return true; for (i = 0; ops->hierarchies[i]; i++) { int ret; - char *fullpath; + __do_free char *fullpath = NULL; fullpath = must_make_path(ops->hierarchies[i]->mountpoint, ops->hierarchies[i]->container_base_path, @@ -1969,10 +1927,8 @@ __cgfsng_ops static bool cgfsng_escape(const struct cgroup_ops *ops, ret = lxc_write_to_file(fullpath, "0", 2, false, 0666); if (ret != 0) { SYSERROR("Failed to escape to cgroup \"%s\"", fullpath); - free(fullpath); return false; } - free(fullpath); } return true; @@ -1980,9 +1936,12 @@ __cgfsng_ops static bool cgfsng_escape(const struct cgroup_ops *ops, __cgfsng_ops static int cgfsng_num_hierarchies(struct cgroup_ops *ops) { - int i; + int i = 0; - for (i = 0; ops->hierarchies[i]; i++) + if (!ops->hierarchies) + return 0; + + for (; ops->hierarchies[i]; i++) ; return i; @@ -1992,6 +1951,9 @@ __cgfsng_ops static bool cgfsng_get_hierarchies(struct cgroup_ops *ops, int n, c { int i; + if (!ops->hierarchies) + return false; + /* sanity check n */ for (i = 0; i < n; i++) if (!ops->hierarchies[i]) @@ -2011,7 +1973,7 @@ __cgfsng_ops static bool cgfsng_get_hierarchies(struct cgroup_ops *ops, int n, c __cgfsng_ops static bool cgfsng_unfreeze(struct cgroup_ops *ops) { int ret; - char *fullpath; + __do_free char *fullpath = NULL; struct hierarchy *h; h = get_hierarchy(ops, "freezer"); @@ -2020,7 +1982,6 @@ __cgfsng_ops static bool cgfsng_unfreeze(struct cgroup_ops *ops) fullpath = must_make_path(h->container_full_path, "freezer.state", NULL); ret = lxc_write_to_file(fullpath, THAWED, THAWED_LEN, false, 0666); - free(fullpath); if (ret < 0) return false; @@ -2065,10 +2026,11 @@ static int __cg_unified_attach(const struct hierarchy *h, const char *name, const char *lxcpath, const char *pidstr, size_t pidstr_len, const char *controller) { + __do_free char *base_path = NULL, *container_cgroup = NULL, + *full_path = NULL; int ret; size_t len; int fret = -1, idx = 0; - char *base_path = NULL, *container_cgroup = NULL, *full_path = NULL; container_cgroup = lxc_cmd_get_cgroup_path(name, lxcpath, controller); /* not running */ @@ -2085,11 +2047,9 @@ static int __cg_unified_attach(const struct hierarchy *h, const char *name, if (ret == 0) goto on_success; - free(full_path); - len = strlen(base_path) + STRLITERALLEN("/lxc-1000") + STRLITERALLEN("/cgroup-procs"); - full_path = must_alloc(len + 1); + full_path = must_realloc(NULL, len + 1); do { if (idx) ret = snprintf(full_path, len + 1, "%s/lxc-%d", @@ -2112,17 +2072,14 @@ static int __cg_unified_attach(const struct hierarchy *h, const char *name, if (errno != EBUSY) goto on_error; - } while (++idx > 0 && idx < 1000); + idx++; + } while (idx < 1000); on_success: if (idx < 1000) fret = 0; on_error: - free(base_path); - free(container_cgroup); - free(full_path); - return fret; } @@ -2132,13 +2089,15 @@ __cgfsng_ops static bool cgfsng_attach(struct cgroup_ops *ops, const char *name, int i, len, ret; char pidstr[INTTYPE_TO_STRLEN(pid_t)]; + if (!ops->hierarchies) + return true; + len = snprintf(pidstr, sizeof(pidstr), "%d", pid); if (len < 0 || (size_t)len >= sizeof(pidstr)) return false; for (i = 0; ops->hierarchies[i]; i++) { - char *path; - char *fullpath = NULL; + __do_free char *fullpath = NULL, *path = NULL; struct hierarchy *h = ops->hierarchies[i]; if (h->version == CGROUP2_SUPER_MAGIC) { @@ -2156,14 +2115,11 @@ __cgfsng_ops static bool cgfsng_attach(struct cgroup_ops *ops, const char *name, continue; fullpath = build_full_cgpath_from_monitorpath(h, path, "cgroup.procs"); - free(path); ret = lxc_write_to_file(fullpath, pidstr, len, false, 0666); if (ret < 0) { SYSERROR("Failed to attach %d to %s", (int)pid, fullpath); - free(fullpath); return false; } - free(fullpath); } return true; @@ -2177,15 +2133,13 @@ __cgfsng_ops static int cgfsng_get(struct cgroup_ops *ops, const char *filename, char *value, size_t len, const char *name, const char *lxcpath) { - int ret = -1; - size_t controller_len; - char *controller, *p, *path; + __do_free char *path = NULL; + __do_free char *controller = NULL; + char *p; struct hierarchy *h; + int ret = -1; - controller_len = strlen(filename); - controller = alloca(controller_len + 1); - (void)strlcpy(controller, filename, controller_len + 1); - + controller = must_copy_string(filename); p = strchr(controller, '.'); if (p) *p = '\0'; @@ -2197,13 +2151,11 @@ __cgfsng_ops static int cgfsng_get(struct cgroup_ops *ops, const char *filename, h = get_hierarchy(ops, controller); if (h) { - char *fullpath; + __do_free char *fullpath = NULL; fullpath = build_full_cgpath_from_monitorpath(h, path, filename); ret = lxc_read_from_file(fullpath, value, len); - free(fullpath); } - free(path); return ret; } @@ -2216,15 +2168,13 @@ __cgfsng_ops static int cgfsng_set(struct cgroup_ops *ops, const char *filename, const char *value, const char *name, const char *lxcpath) { - int ret = -1; - size_t controller_len; - char *controller, *p, *path; + __do_free char *path = NULL; + __do_free char *controller = NULL; + char *p; struct hierarchy *h; + int ret = -1; - controller_len = strlen(filename); - controller = alloca(controller_len + 1); - (void)strlcpy(controller, filename, controller_len + 1); - + controller = must_copy_string(filename); p = strchr(controller, '.'); if (p) *p = '\0'; @@ -2236,13 +2186,11 @@ __cgfsng_ops static int cgfsng_set(struct cgroup_ops *ops, h = get_hierarchy(ops, controller); if (h) { - char *fullpath; + __do_free char *fullpath = NULL; fullpath = build_full_cgpath_from_monitorpath(h, path, filename); ret = lxc_write_to_file(fullpath, value, strlen(value), false, 0666); - free(fullpath); } - free(path); return ret; } @@ -2256,8 +2204,9 @@ __cgfsng_ops static int cgfsng_set(struct cgroup_ops *ops, */ static int convert_devpath(const char *invalue, char *dest) { + __do_free char *path = NULL; int n_parts; - char *p, *path, type; + char *p, type; unsigned long minor, major; struct stat sb; int ret = -EINVAL; @@ -2269,7 +2218,7 @@ static int convert_devpath(const char *invalue, char *dest) * A ' # comment' would be legal. Technically other text is not * legal, we could check for that if we cared to. */ - for (n_parts = 1, p = path; *p && n_parts < 3; p++) { + for (n_parts = 1, p = path; *p; p++) { if (*p != ' ') continue; *p = '\0'; @@ -2321,7 +2270,6 @@ static int convert_devpath(const char *invalue, char *dest) ret = 0; out: - free(path); return ret; } @@ -2331,18 +2279,15 @@ out: static int cg_legacy_set_data(struct cgroup_ops *ops, const char *filename, const char *value) { - size_t len; - char *fullpath, *p; + __do_free char *controller = NULL; + __do_free char *fullpath = NULL; + char *p; /* "b|c <2^64-1>:<2^64-1> r|w|m" = 47 chars max */ char converted_value[50]; struct hierarchy *h; int ret = 0; - char *controller = NULL; - - len = strlen(filename); - controller = alloca(len + 1); - (void)strlcpy(controller, filename, len + 1); + controller = must_copy_string(filename); p = strchr(controller, '.'); if (p) *p = '\0'; @@ -2366,7 +2311,6 @@ static int cg_legacy_set_data(struct cgroup_ops *ops, const char *filename, fullpath = must_make_path(h->container_full_path, filename, NULL); ret = lxc_write_to_file(fullpath, value, strlen(value), false, 0666); - free(fullpath); return ret; } @@ -2374,13 +2318,17 @@ static bool __cg_legacy_setup_limits(struct cgroup_ops *ops, struct lxc_list *cgroup_settings, bool do_devices) { - struct lxc_list *iterator, *next, *sorted_cgroup_settings; + __do_free struct lxc_list *sorted_cgroup_settings = NULL; + struct lxc_list *iterator, *next; struct lxc_cgroup *cg; bool ret = false; if (lxc_list_empty(cgroup_settings)) return true; + if (!ops->hierarchies) + return false; + sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings); if (!sorted_cgroup_settings) return false; @@ -2411,7 +2359,7 @@ out: lxc_list_del(iterator); free(iterator); } - free(sorted_cgroup_settings); + return ret; } @@ -2428,13 +2376,12 @@ static bool __cg_unified_setup_limits(struct cgroup_ops *ops, return false; lxc_list_for_each(iterator, cgroup_settings) { + __do_free char *fullpath = NULL; int ret; - char *fullpath; struct lxc_cgroup *cg = iterator->elem; fullpath = must_make_path(h->container_full_path, cg->subsystem, NULL); ret = lxc_write_to_file(fullpath, cg->value, strlen(cg->value), false, 0666); - free(fullpath); if (ret < 0) { SYSERROR("Failed to set \"%s\" to \"%s\"", cg->subsystem, cg->value); @@ -2448,13 +2395,10 @@ static bool __cg_unified_setup_limits(struct cgroup_ops *ops, } __cgfsng_ops static bool cgfsng_setup_limits(struct cgroup_ops *ops, - struct lxc_conf *conf, - bool do_devices) + struct lxc_conf *conf, + bool do_devices) { - bool bret; - - bret = __cg_legacy_setup_limits(ops, &conf->cgroup, do_devices); - if (!bret) + if (!__cg_legacy_setup_limits(ops, &conf->cgroup, do_devices)) return false; return __cg_unified_setup_limits(ops, &conf->cgroup2); @@ -2463,15 +2407,13 @@ __cgfsng_ops static bool cgfsng_setup_limits(struct cgroup_ops *ops, static bool cgroup_use_wants_controllers(const struct cgroup_ops *ops, char **controllers) { - char **cur_ctrl, **cur_use; - if (!ops->cgroup_use) return true; - for (cur_ctrl = controllers; cur_ctrl && *cur_ctrl; cur_ctrl++) { + for (char **cur_ctrl = controllers; cur_ctrl && *cur_ctrl; cur_ctrl++) { bool found = false; - for (cur_use = ops->cgroup_use; cur_use && *cur_use; cur_use++) { + for (char **cur_use = ops->cgroup_use; cur_use && *cur_use; cur_use++) { if (strcmp(*cur_use, *cur_ctrl) != 0) continue; @@ -2488,16 +2430,45 @@ static bool cgroup_use_wants_controllers(const struct cgroup_ops *ops, return true; } +static void cg_unified_delegate(char ***delegate) +{ + __do_free char *tmp = NULL; + int idx; + char *standard[] = {"cgroup.subtree_control", "cgroup.threads", NULL}; + + tmp = read_file("/sys/kernel/cgroup/delegate"); + if (!tmp) { + for (char **p = standard; p && *p; p++) { + idx = append_null_to_list((void ***)delegate); + (*delegate)[idx] = must_copy_string(*p); + } + } else { + char *token; + lxc_iterate_parts (token, tmp, " \t\n") { + /* + * We always need to chown this for both cgroup and + * cgroup2. + */ + if (strcmp(token, "cgroup.procs") == 0) + continue; + + idx = append_null_to_list((void ***)delegate); + (*delegate)[idx] = must_copy_string(token); + } + } +} + /* At startup, parse_hierarchies finds all the info we need about cgroup * mountpoints and current cgroups, and stores it in @d. */ -static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative) +static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative, + bool unprivileged) { + __do_free char *basecginfo = NULL; + __do_free char *line = NULL; + __do_fclose FILE *f = NULL; int ret; - char *basecginfo; - FILE *f; size_t len = 0; - char *line = NULL; char **klist = NULL, **nlist = NULL; /* Root spawned containers escape the current cgroup, so use init's @@ -2513,14 +2484,12 @@ static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative) ret = get_existing_subsystems(&klist, &nlist); if (ret < 0) { ERROR("Failed to retrieve available legacy cgroup controllers"); - free(basecginfo); return false; } f = fopen("/proc/self/mountinfo", "r"); if (!f) { ERROR("Failed to open \"/proc/self/mountinfo\""); - free(basecginfo); return false; } @@ -2606,8 +2575,11 @@ static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative) goto next; new = add_hierarchy(&ops->hierarchies, controller_list, mountpoint, base_cgroup, type); - if (type == CGROUP2_SUPER_MAGIC && !ops->unified) + if (type == CGROUP2_SUPER_MAGIC && !ops->unified) { + if (unprivileged) + cg_unified_delegate(&new->cgroup2_chown); ops->unified = new; + } continue; @@ -2620,11 +2592,6 @@ static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative) free_string_list(klist); free_string_list(nlist); - free(basecginfo); - - fclose(f); - free(line); - TRACE("Writable cgroup hierarchies:"); lxc_cgfsng_print_hierarchies(ops); @@ -2656,7 +2623,8 @@ static int cg_is_pure_unified(void) /* Get current cgroup from /proc/self/cgroup for the cgroupfs v2 hierarchy. */ static char *cg_unified_get_current_cgroup(bool relative) { - char *basecginfo, *base_cgroup; + __do_free char *basecginfo = NULL; + char *base_cgroup; char *copy = NULL; if (!relative && (geteuid() == 0)) @@ -2676,18 +2644,20 @@ static char *cg_unified_get_current_cgroup(bool relative) goto cleanup_on_err; cleanup_on_err: - free(basecginfo); if (copy) trim(copy); return copy; } -static int cg_unified_init(struct cgroup_ops *ops, bool relative) +static int cg_unified_init(struct cgroup_ops *ops, bool relative, + bool unprivileged) { + __do_free char *subtree_path = NULL; int ret; - char *mountpoint, *subtree_path; + char *mountpoint; char **delegatable; + struct hierarchy *new; char *base_cgroup = NULL; ret = cg_is_pure_unified(); @@ -2710,7 +2680,6 @@ static int cg_unified_init(struct cgroup_ops *ops, bool relative) subtree_path = must_make_path(mountpoint, base_cgroup, "cgroup.subtree_control", NULL); delegatable = cg_unified_get_controllers(subtree_path); - free(subtree_path); if (!delegatable) delegatable = cg_unified_make_empty_controller(); if (!delegatable[0]) @@ -2723,9 +2692,12 @@ static int cg_unified_init(struct cgroup_ops *ops, bool relative) * controllers per container. */ - add_hierarchy(&ops->hierarchies, delegatable, mountpoint, base_cgroup, CGROUP2_SUPER_MAGIC); + new = add_hierarchy(&ops->hierarchies, delegatable, mountpoint, base_cgroup, CGROUP2_SUPER_MAGIC); + if (!unprivileged) + cg_unified_delegate(&new->cgroup2_chown); ops->cgroup_layout = CGROUP_LAYOUT_UNIFIED; + ops->unified = new; return CGROUP2_SUPER_MAGIC; } @@ -2737,26 +2709,24 @@ static bool cg_init(struct cgroup_ops *ops, struct lxc_conf *conf) tmp = lxc_global_config_value("lxc.cgroup.use"); if (tmp) { - char *chop, *cur, *pin; + __do_free char *pin = NULL; + char *chop, *cur; pin = must_copy_string(tmp); chop = pin; - lxc_iterate_parts(cur, chop, ",") { + lxc_iterate_parts(cur, chop, ",") must_append_string(&ops->cgroup_use, cur); - } - - free(pin); } - ret = cg_unified_init(ops, relative); + ret = cg_unified_init(ops, relative, !lxc_list_empty(&conf->id_map)); if (ret < 0) return false; if (ret == CGROUP2_SUPER_MAGIC) return true; - return cg_hybrid_init(ops, relative); + return cg_hybrid_init(ops, relative, !lxc_list_empty(&conf->id_map)); } __cgfsng_ops static bool cgfsng_data_init(struct cgroup_ops *ops) @@ -2778,7 +2748,7 @@ __cgfsng_ops static bool cgfsng_data_init(struct cgroup_ops *ops) struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf) { - struct cgroup_ops *cgfsng_ops; + __do_free struct cgroup_ops *cgfsng_ops = NULL; cgfsng_ops = malloc(sizeof(struct cgroup_ops)); if (!cgfsng_ops) @@ -2787,10 +2757,8 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf) memset(cgfsng_ops, 0, sizeof(struct cgroup_ops)); cgfsng_ops->cgroup_layout = CGROUP_LAYOUT_UNKNOWN; - if (!cg_init(cgfsng_ops, conf)) { - free(cgfsng_ops); + if (!cg_init(cgfsng_ops, conf)) return NULL; - } cgfsng_ops->data_init = cgfsng_data_init; cgfsng_ops->payload_destroy = cgfsng_payload_destroy; @@ -2814,5 +2782,5 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf) cgfsng_ops->mount = cgfsng_mount; cgfsng_ops->nrtasks = cgfsng_nrtasks; - return cgfsng_ops; + return move_ptr(cgfsng_ops); }