/* * Make sure that all the controllers are writeable. * If any are not, then * - if they are listed in lxc.cgroup.use, refuse to start * - else if they are crucial subsystems, refuse to start * - else warn and do not use them */ static bool verify_final_subsystems(const char *cgroup_use) { int i; bool dropped_any = false; bool bret = false; const char *cgroup_pattern; char tmpnam[50], *probe; if (!cgm_dbus_connect()) { ERROR("Error connecting to cgroup manager"); return false; } cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern"); i = snprintf(tmpnam, 50, "lxcprobe-%d", getpid()); if (i < 0 || i >= 50) { ERROR("Attack - format string modified?"); return false; } probe = lxc_string_replace("%n", tmpnam, cgroup_pattern); if (!probe) goto out; i = 0; while (i < nr_subsystems) { char *p = get_last_controller_in_list(subsystems[i]); if (!subsys_is_writeable(p, probe)) { if (is_crucial_subsys(p)) { ERROR("Cannot write to crucial subsystem %s\n", subsystems[i]); goto out; } if (cgroup_use && any_in_comma_list(subsystems[i], cgroup_use)) { ERROR("Cannot write to subsystem %s which is requested in lxc.cgroup.use\n", subsystems[i]); goto out; } WARN("Cannot write to subsystem %s, continuing with out it\n", subsystems[i]); dropped_any = true; drop_subsystem(i); } else { cgm_remove_cgroup(subsystems[i], probe); i++; } } if (dropped_any) cgm_all_controllers_same = false; bret = true; out: free(probe); cgm_dbus_disconnect(); return bret; }
static inline bool cgm_create(struct lxc_handler *handler) { int i, index=0, baselen, ret; int32_t existed; char result[MAXPATHLEN], *tmp; char *cgroup_path = handler->cgroup_info->data; // XXX we should send a hint to the cgmanager that when these // cgroups become empty they should be deleted. Requires a cgmanager // extension memset(result, 0, MAXPATHLEN); tmp = lxc_string_replace("%n", handler->name, handler->cgroup_info->cgroup_pattern); if (!tmp) return false; if (strlen(tmp) > MAXPATHLEN) return false; strcpy(result, tmp); baselen = strlen(result); free(tmp); tmp = result; while (*tmp == '/') tmp++; again: if (index == 100) { // turn this into a warn later ERROR("cgroup error? 100 cgroups with this name already running"); return false; } if (index) { ret = snprintf(result+baselen, MAXPATHLEN-baselen, "-%d", index); if (ret < 0 || ret >= MAXPATHLEN-baselen) return false; } existed = 0; for (i = 0; i < nr_subsystems; i++) { if (!lxc_cgmanager_create(subsystems[i], tmp, &existed)) { ERROR("Error creating cgroup %s:%s", subsystems[i], result); cleanup_cgroups(tmp); return false; } if (existed == 1) goto next; } // success cgroup_path = strdup(tmp); if (!cgroup_path) { cleanup_cgroups(tmp); return false; } handler->cgroup_info->data = cgroup_path; return true; next: cleanup_cgroups(tmp); index++; goto again; }
void test_lxc_string_replace(void) { char *s; s = lxc_string_replace("A", "A", "A"); lxc_test_assert_abort(strcmp(s, "A") == 0); free(s); s = lxc_string_replace("A", "AA", "A"); lxc_test_assert_abort(strcmp(s, "AA") == 0); free(s); s = lxc_string_replace("A", "AA", "BA"); lxc_test_assert_abort(strcmp(s, "BAA") == 0); free(s); s = lxc_string_replace("A", "AA", "BAB"); lxc_test_assert_abort(strcmp(s, "BAAB") == 0); free(s); s = lxc_string_replace("AA", "A", "AA"); lxc_test_assert_abort(strcmp(s, "A") == 0); free(s); s = lxc_string_replace("AA", "A", "BAA"); lxc_test_assert_abort(strcmp(s, "BA") == 0); free(s); s = lxc_string_replace("AA", "A", "BAAB"); lxc_test_assert_abort(strcmp(s, "BAB") == 0); free(s); s = lxc_string_replace("\"A\"A", "\"A\"", "B\"A\"AB"); lxc_test_assert_abort(strcmp(s, "B\"A\"B") == 0); free(s); }
static inline bool cgm_create(void *hdata) { struct cgm_data *d = hdata; char **slist = subsystems; int i, index=0, baselen, ret; int32_t existed; char result[MAXPATHLEN], *tmp, *cgroup_path; if (!d) return false; // XXX we should send a hint to the cgmanager that when these // cgroups become empty they should be deleted. Requires a cgmanager // extension memset(result, 0, MAXPATHLEN); tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern); if (!tmp) goto bad; if (strlen(tmp) >= MAXPATHLEN) { free(tmp); goto bad; } strcpy(result, tmp); baselen = strlen(result); free(tmp); tmp = result; while (*tmp == '/') tmp++; again: if (index == 100) { // turn this into a warn later ERROR("cgroup error? 100 cgroups with this name already running"); goto bad; } if (index) { ret = snprintf(result+baselen, MAXPATHLEN-baselen, "-%d", index); if (ret < 0 || ret >= MAXPATHLEN-baselen) goto bad; } existed = 0; if (cgm_supports_multiple_controllers) slist = subsystems_inone; for (i = 0; slist[i]; i++) { if (!lxc_cgmanager_create(slist[i], tmp, &existed)) { ERROR("Error creating cgroup %s:%s", slist[i], result); cleanup_cgroups(tmp); goto bad; } if (existed == 1) goto next; } // success cgroup_path = strdup(tmp); if (!cgroup_path) { cleanup_cgroups(tmp); goto bad; } d->cgroup_path = cgroup_path; cgm_dbus_disconnect(); return true; next: index++; goto again; bad: cgm_dbus_disconnect(); return false; }