static bool cgm_dbus_connect(void) { DBusError dbus_error; dbus_error_init(&dbus_error); connection = dbus_connection_open_private(CGMANAGER_DBUS_SOCK, &dbus_error); if (!connection) { dbus_error_free(&dbus_error); return false; } dbus_connection_set_exit_on_disconnect(connection, FALSE); dbus_error_free(&dbus_error); cgroup_manager = nih_dbus_proxy_new(NULL, connection, NULL /* p2p */, "/org/linuxcontainers/cgmanager", NULL, NULL); if (!cgroup_manager) { NihError *nerr; nerr = nih_error_get(); nih_free(nerr); cgm_dbus_disconnect(); return false; } // force fd passing negotiation if (cgmanager_ping_sync(NULL, cgroup_manager, 0) != 0) { NihError *nerr; nerr = nih_error_get(); nih_free(nerr); cgm_dbus_disconnect(); return false; } return true; }
int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { const char *PAM_user = NULL; int ret; if (!cgm_dbus_connect()) { mysyslog(LOG_ERR, "Failed to connect to cgmanager\n"); return PAM_SESSION_ERR; } if (argc > 1 && strcmp(argv[0], "-c") == 0) ctrl_list = validate_and_dup(argv[1]); if (!ctrl_list) get_active_controllers(); cgm_escape(); ret = pam_get_user(pamh, &PAM_user, NULL); if (ret != PAM_SUCCESS) { cgm_dbus_disconnect(); mysyslog(LOG_ERR, "PAM-CGM: couldn't get user\n"); return PAM_SESSION_ERR; } ret = handle_login(PAM_user); cgm_dbus_disconnect(); return ret; }
static int chown_cgroup_wrapper(void *data) { struct chown_data *arg = data; char **slist = subsystems; int i, ret = -1; uid_t destuid; if (setresgid(0,0,0) < 0) SYSERROR("Failed to setgid to 0"); if (setresuid(0,0,0) < 0) SYSERROR("Failed to setuid to 0"); if (setgroups(0, NULL) < 0) SYSERROR("Failed to clear groups"); cgm_dbus_disconnect(); if (!cgm_dbus_connect()) { ERROR("Error connecting to cgroup manager"); return -1; } destuid = get_ns_uid(arg->origuid); if (cgm_supports_multiple_controllers) slist = subsystems_inone; for (i = 0; slist[i]; i++) { if (do_chown_cgroup(slist[i], arg->cgroup_path, destuid) < 0) { ERROR("Failed to chown %s:%s to container root", slist[i], arg->cgroup_path); goto fail; } } ret = 0; fail: cgm_dbus_disconnect(); return ret; }
static void *cgm_init(const char *name) { struct cgm_data *d; if (!cgm_dbus_connect()) { ERROR("Error connecting to cgroup manager"); return NULL; } check_supports_multiple_controllers(-1); d = malloc(sizeof(*d)); if (!d) { cgm_dbus_disconnect(); return NULL; } memset(d, 0, sizeof(*d)); d->name = strdup(name); if (!d->name) { cgm_dbus_disconnect(); goto err1; } d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern"); // cgm_create immediately gets called so keep the connection open return d; err1: free(d); return NULL; }
/* * TODO: this should be re-written to use the get_config_item("lxc.id_map") * cmd api instead of getting the idmap from c->lxc_conf. The reason is * that the id_maps may be different if the container was started with a * -f or -s argument. * The reason I'm punting on that is because we'll need to parse the * idmap results. */ static bool cgm_attach(const char *name, const char *lxcpath, pid_t pid) { bool pass; char *cgroup = NULL; if (!cgm_dbus_connect()) { ERROR("Error connecting to cgroup manager"); return false; } // cgm_create makes sure that we have the same cgroup name for all // subsystems, so since this is a slow command over the cmd socket, // just get the cgroup name for the first one. cgroup = try_get_abs_cgroup(name, lxcpath, subsystems[0]); if (!cgroup) { ERROR("Failed to get cgroup for controller %s", subsystems[0]); cgm_dbus_disconnect(); return false; } pass = do_cgm_enter(pid, cgroup, abs_cgroup_supported()); cgm_dbus_disconnect(); if (!pass) ERROR("Failed to enter group %s", cgroup); free_abs_cgroup(cgroup); return pass; }
bool cgm_create(const char *controller, const char *cg, uid_t uid, gid_t gid) { int32_t e; pid_t pid = fork(); if (pid) { if (wait_for_pid(pid) != 0) return false; return true; } if (setgroups(0, NULL)) _exit(1); if (setresgid(gid, gid, gid)) _exit(1); if (setresuid(uid, uid, uid)) _exit(1); if (!cgm_dbus_connect()) { _exit(1); } if ( cgmanager_create_sync(NULL, cgroup_manager, controller, cg, &e) != 0) { NihError *nerr; nerr = nih_error_get(); fprintf(stderr, "call to create failed (%s:%s): %s\n", controller, cg, nerr->message); nih_free(nerr); cgm_dbus_disconnect(); _exit(1); } cgm_dbus_disconnect(); _exit(0); }
static bool cgm_dbus_connect(void) { DBusError dbus_error; static DBusConnection *connection; cgm_lock(); if (!dbus_threads_initialized) { // tell dbus to do struct locking for thread safety dbus_threads_init_default(); dbus_threads_initialized = true; } dbus_error_init(&dbus_error); connection = dbus_connection_open_private(CGMANAGER_DBUS_SOCK, &dbus_error); if (!connection) { DEBUG("Failed opening dbus connection: %s: %s", dbus_error.name, dbus_error.message); dbus_error_free(&dbus_error); cgm_unlock(); return false; } dbus_connection_set_exit_on_disconnect(connection, FALSE); dbus_error_free(&dbus_error); cgroup_manager = nih_dbus_proxy_new(NULL, connection, NULL /* p2p */, "/org/linuxcontainers/cgmanager", NULL, NULL); dbus_connection_unref(connection); if (!cgroup_manager) { NihError *nerr; nerr = nih_error_get(); ERROR("Error opening cgmanager proxy: %s", nerr->message); nih_free(nerr); cgm_dbus_disconnect(); return false; } // get the api version if (cgmanager_get_api_version_sync(NULL, cgroup_manager, &api_version) != 0) { NihError *nerr; nerr = nih_error_get(); ERROR("Error cgroup manager api version: %s", nerr->message); nih_free(nerr); cgm_dbus_disconnect(); return false; } if (api_version < CGM_SUPPORTS_NAMED) cull_user_controllers(); return true; }
static inline bool cgm_enter(void *hdata, pid_t pid) { struct cgm_data *d = hdata; char **slist = subsystems; bool ret = false; int i; if (!d || !d->cgroup_path) return false; if (!cgm_dbus_connect()) { ERROR("Error connecting to cgroup manager"); return false; } if (cgm_all_controllers_same) slist = subsystems_inone; for (i = 0; slist[i]; i++) { if (!lxc_cgmanager_enter(pid, slist[i], d->cgroup_path, false)) goto out; } ret = true; out: cgm_dbus_disconnect(); return ret; }
/* * nrtasks is called by the utmp helper by the container monitor. * cgmanager socket was closed after cgroup setup was complete, so we need * to reopen here. * * Return -1 on error. */ static int cgm_get_nrtasks(void *hdata) { struct cgm_data *d = hdata; int32_t *pids; size_t pids_len; if (!d || !d->cgroup_path) return -1; if (!cgm_dbus_connect()) { ERROR("Error connecting to cgroup manager"); return -1; } if (cgmanager_get_tasks_sync(NULL, cgroup_manager, subsystems[0], d->cgroup_path, &pids, &pids_len) != 0) { NihError *nerr; nerr = nih_error_get(); ERROR("call to cgmanager_get_tasks_sync failed: %s", nerr->message); nih_free(nerr); pids_len = -1; goto out; } nih_free(pids); out: cgm_dbus_disconnect(); return pids_len; }
bool cgm_list_children(const char *controller, const char *cgroup, char ***list) { if (!cgm_dbus_connect()) { return false; } if ( cgmanager_list_children_sync(NULL, cgroup_manager, controller, cgroup, list) != 0 ) { NihError *nerr; nerr = nih_error_get(); fprintf(stderr, "call to list_children (%s:%s) failed: %s\n", controller, cgroup, nerr->message); nih_free(nerr); cgm_dbus_disconnect(); return false; } cgm_dbus_disconnect(); return true; }
bool cgm_get_controllers(char ***contrls) { if (!cgm_dbus_connect()) { return false; } if ( cgmanager_list_controllers_sync(NULL, cgroup_manager, contrls) != 0 ) { NihError *nerr; nerr = nih_error_get(); fprintf(stderr, "call to list_controllers failed: %s\n", nerr->message); nih_free(nerr); cgm_dbus_disconnect(); return false; } cgm_dbus_disconnect(); return true; }
bool cgm_escape_cgroup(void) { if (!cgm_dbus_connect()) { return false; } if ( cgmanager_move_pid_abs_sync(NULL, cgroup_manager, "all", "/", (int32_t) getpid()) != 0 ) { NihError *nerr; nerr = nih_error_get(); fprintf(stderr, "call to move_pid_abs (all:/) failed: %s\n", nerr->message); nih_free(nerr); cgm_dbus_disconnect(); return false; } cgm_dbus_disconnect(); return true; }
static bool lxc_list_controllers(char ***list) { if (!cgm_dbus_connect()) { ERROR("Error connecting to cgroup manager"); return false; } if (cgmanager_list_controllers_sync(NULL, cgroup_manager, list) != 0) { NihError *nerr; nerr = nih_error_get(); ERROR("call to cgmanager_list_controllers_sync failed: %s", nerr->message); nih_free(nerr); cgm_dbus_disconnect(); return false; } cgm_dbus_disconnect(); return true; }
bool cgm_chown_file(const char *controller, const char *cg, uid_t uid, gid_t gid) { if (!cgm_dbus_connect()) { return false; } if ( cgmanager_chown_sync(NULL, cgroup_manager, controller, cg, uid, gid) != 0) { NihError *nerr; nerr = nih_error_get(); fprintf(stderr, "call to chown (%s:%s, %d, %d) failed: %s\n", controller, cg, uid, gid, nerr->message); nih_free(nerr); cgm_dbus_disconnect(); return false; } cgm_dbus_disconnect(); return true; }
bool cgm_chmod_file(const char *controller, const char *file, mode_t mode) { if (!cgm_dbus_connect()) { return false; } if ( cgmanager_chmod_sync(NULL, cgroup_manager, controller, file, "", mode) != 0) { NihError *nerr; nerr = nih_error_get(); fprintf(stderr, "call to chmod (%s:%s, %d) failed: %s\n", controller, file, mode, nerr->message); nih_free(nerr); cgm_dbus_disconnect(); return false; } cgm_dbus_disconnect(); return true; }
/* * 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; }
int cg_create(const char *controller, const char *path, const char *suffix) { _cleanup_free_ char *fs = NULL; int r; #ifdef HAVE_CGMANAGER /* CGManager support */ int existed; if (cgm_dbus_connect()) { if (!controller) { cgm_dbus_disconnect(); return -1; } r = cgm_create(normalize_controller(controller), path, &existed); cgm_dbus_disconnect(); if (!r) return -1; return 1; } #endif r = cg_get_path_and_check(controller, path, suffix, &fs); if (r < 0) return r; r = mkdir_parents_label(fs, 0755); if (r < 0) return r; if (mkdir(fs, 0755) < 0) { if (errno == EEXIST) return 0; return -errno; } return 1; }
bool cgm_move_pid(const char *controller, const char *cgroup, pid_t pid) { if (!cgm_dbus_connect()) { return false; } if ( cgmanager_move_pid_sync(NULL, cgroup_manager, controller, cgroup, (int32_t) pid) != 0 ) { NihError *nerr; nerr = nih_error_get(); fprintf(stderr, "call to move_pid (%s:%s, %d) failed: %s\n", controller, cgroup, pid, nerr->message); nih_free(nerr); cgm_dbus_disconnect(); return false; } cgm_dbus_disconnect(); return true; }
bool cgm_list_keys(const char *controller, const char *cgroup, struct cgm_keys ***keys) { if (!cgm_dbus_connect()) { return false; } if ( cgmanager_list_keys_sync(NULL, cgroup_manager, controller, cgroup, (CgmanagerListKeysOutputElement ***)keys) != 0 ) { NihError *nerr; nerr = nih_error_get(); fprintf(stderr, "call to list_keys (%s:%s) failed: %s\n", controller, cgroup, nerr->message); nih_free(nerr); cgm_dbus_disconnect(); return false; } cgm_dbus_disconnect(); return true; }
/* * called during cgroup.c:cgroup_ops_init(), at startup. No threads. * We check whether we can talk to cgmanager, escape to root cgroup if * we are root, then close the connection. */ struct cgroup_ops *cgm_ops_init(void) { if (!collect_subsytems()) return NULL; if (!cgm_dbus_connect()) goto err1; // root; try to escape to root cgroup if (geteuid() == 0 && !lxc_cgmanager_escape()) goto err2; cgm_dbus_disconnect(); return &cgmanager_ops; err2: cgm_dbus_disconnect(); err1: free_subsystems(); return NULL; }
bool cgm_set_value(const char *controller, const char *cgroup, const char *file, const char *value) { if (!cgm_dbus_connect()) { return false; } if ( cgmanager_set_value_sync(NULL, cgroup_manager, controller, cgroup, file, value) != 0 ) { NihError *nerr; nerr = nih_error_get(); fprintf(stderr, "call to set_value (%s:%s, %s, %s) failed: %s\n", controller, cgroup, file, value, nerr->message); nih_free(nerr); cgm_dbus_disconnect(); return false; } cgm_dbus_disconnect(); return true; }
char *cgm_get_pid_cgroup(pid_t pid, const char *controller) { char *output = NULL; if (!cgm_dbus_connect()) { return NULL; } if ( cgmanager_get_pid_cgroup_sync(NULL, cgroup_manager, controller, pid, &output) != 0 ) { NihError *nerr; nerr = nih_error_get(); fprintf(stderr, "call to get_pid_cgroup (%s) failed: %s\n", controller, nerr->message); nih_free(nerr); cgm_dbus_disconnect(); return NULL; } cgm_dbus_disconnect(); return output; }
bool cgm_dbus_connect(void) { DBusError dbus_error; static DBusConnection *connection; dbus_error_init(&dbus_error); connection = dbus_connection_open_private(CGMANAGER_DBUS_SOCK, &dbus_error); if (!connection) { fprintf(stderr, "Failed opening dbus connection: %s: %s\n", dbus_error.name, dbus_error.message); dbus_error_free(&dbus_error); return false; } dbus_connection_set_exit_on_disconnect(connection, FALSE); dbus_error_free(&dbus_error); cgroup_manager = nih_dbus_proxy_new(NULL, connection, NULL /* p2p */, "/org/linuxcontainers/cgmanager", NULL, NULL); dbus_connection_unref(connection); if (!cgroup_manager) { NihError *nerr; nerr = nih_error_get(); fprintf(stderr, "Error opening cgmanager proxy: %s\n", nerr->message); nih_free(nerr); cgm_dbus_disconnect(); return false; } // get the api version if (cgmanager_get_api_version_sync(NULL, cgroup_manager, &api_version) != 0) { NihError *nerr; nerr = nih_error_get(); fprintf(stderr, "Error cgroup manager api version: %s\n", nerr->message); nih_free(nerr); cgm_dbus_disconnect(); return false; } return true; }
static void *cgm_init(const char *name) { struct cgm_data *d; if (!cgm_dbus_connect()) { ERROR("Error connecting to cgroup manager"); return NULL; } d = malloc(sizeof(*d)); if (!d) { cgm_dbus_disconnect(); return NULL; } memset(d, 0, sizeof(*d)); d->name = strdup(name); if (!d->name) { cgm_dbus_disconnect(); goto err1; } /* if we are running as root, use system cgroup pattern, otherwise * just create a cgroup under the current one. But also fall back to * that if for some reason reading the configuration fails and no * default value is available */ if (geteuid() == 0) d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern"); if (!d->cgroup_pattern) d->cgroup_pattern = "%n"; // cgm_create immediately gets called so keep the connection open return d; err1: free(d); return NULL; }
static bool cgm_chown(void *hdata, struct lxc_conf *conf) { struct cgm_data *d = hdata; if (!d || !d->cgroup_path) return false; if (!cgm_dbus_connect()) { ERROR("Error connecting to cgroup manager"); return false; } if (!chown_cgroup(d->cgroup_path, conf)) WARN("Failed to chown %s to container root", d->cgroup_path); cgm_dbus_disconnect(); return true; }
bool cgm_remove(const char *controller, const char *cg) { /* * tempting to make remove be recursive, but this is a filesystem, * so best to opt for least surprise */ int32_t r = 0, e; if (!cgm_dbus_connect()) { return false; } if ( cgmanager_remove_sync(NULL, cgroup_manager, controller, cg, r, &e) != 0) { NihError *nerr; nerr = nih_error_get(); fprintf(stderr, "call to remove (%s:%s) failed: %s\n", controller, cg, nerr->message); nih_free(nerr); cgm_dbus_disconnect(); return false; } cgm_dbus_disconnect(); return true; }
static inline bool cgm_enter(void *hdata, pid_t pid) { struct cgm_data *d = hdata; bool ret = false; if (!cgm_dbus_connect()) { ERROR("Error connecting to cgroup manager"); return false; } if (!d || !d->cgroup_path) goto out; if (do_cgm_enter(pid, d->cgroup_path, false)) ret = true; out: cgm_dbus_disconnect(); return ret; }
static void do_function(void *arguments) { char path[100]; int existed; char *value; bool err = false; if (!cgm_dbus_connect()) { fprintf(stderr, "Error connecting to dbus\n"); return; } sprintf(path, "cgmtest-%d", gettid()); if (connect_only) { if (cgmanager_create_sync(NULL, cgroup_manager, "freezer", path, &existed) != 0) { NihError *nerr = nih_error_get(); fprintf(stderr, "Error creating freezer cgroup: %s\n", nerr->message); nih_free(nerr); err = true; } if (cgmanager_get_value_sync(NULL, cgroup_manager, "freezer", path, "freezer.state", &value) != 0) { NihError *nerr = nih_error_get(); fprintf(stderr, "Error querying freezer cgroup: %s\n", nerr->message); nih_free(nerr); err = true; } if (cgmanager_remove_sync(NULL, cgroup_manager, "freezer", path, 1, &existed) != 0) { NihError *nerr = nih_error_get(); fprintf(stderr, "Error removing freezer cgroup: %s\n", nerr->message); nih_free(nerr); err = true; } } cgm_dbus_disconnect(); if (err) { fflush(stderr); exit(1); } }
/* Called after a failed container startup */ static void cgm_destroy(void *hdata) { struct cgm_data *d = hdata; char **slist = subsystems; int i; if (!d || !d->cgroup_path) return; if (!cgm_dbus_connect()) { ERROR("Error connecting to cgroup manager"); return; } if (cgm_supports_multiple_controllers) slist = subsystems_inone; for (i = 0; slist[i]; i++) cgm_remove_cgroup(slist[i], d->cgroup_path); free(d->name); free(d->cgroup_path); free(d); cgm_dbus_disconnect(); }
/* * Escape to the root cgroup if we are root, so that the container will * be in "/lxc/c1" rather than "/user/..../c1" * called internally with connection already open */ static bool cgm_escape(void) { bool ret = true, cgm_needs_disconnect = false; pid_t me = getpid(); char **slist = subsystems; int i; if (!cgroup_manager) { if (!cgm_dbus_connect()) { ERROR("Error connecting to cgroup manager"); return false; } cgm_needs_disconnect = true; } if (cgm_all_controllers_same) slist = subsystems_inone; for (i = 0; slist[i]; i++) { if (cgmanager_move_pid_abs_sync(NULL, cgroup_manager, slist[i], "/", me) != 0) { NihError *nerr; nerr = nih_error_get(); ERROR("call to cgmanager_move_pid_abs_sync(%s) failed: %s", slist[i], nerr->message); nih_free(nerr); ret = false; break; } } if (cgm_needs_disconnect) cgm_dbus_disconnect(); return ret; }