[lxc-devel] [PATCH] cgmanager: implement attach
Stéphane Graber
stgraber at ubuntu.com
Fri Jan 31 09:42:58 UTC 2014
On Thu, Jan 30, 2014 at 12:15:32PM +0000, Serge Hallyn wrote:
> The cgroupfs-specific code is moved from attach.c to cgroup.c.
>
> lxc-cgmanager now only chgrps the container's cgroup, so that the
> unprivileged user still owns the tasks file allowing him to enter
> the container cgroup (for attach).
>
> Some other changes rolled into the cgmanager update:
>
> Make the list of subsystems not per-handler, as it will not change. As
> a result, the only state we need to keep in the per-handler cgroup data
> is the char *cgroup_path, so we can drop the cgm_data struct altogether.
>
> Catch nih errors (as not doing so causes later crashes).
>
> Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
Acked-by: Stéphane Graber <stgraber at ubuntu.com>
> ---
> src/lxc/attach.c | 26 +----
> src/lxc/cgmanager.c | 310 ++++++++++++++++++++++++++++++++++------------------
> src/lxc/cgroup.c | 35 ++++++
> src/lxc/cgroup.h | 2 +
> src/lxc/utils.c | 25 +++++
> src/lxc/utils.h | 5 +
> 6 files changed, 271 insertions(+), 132 deletions(-)
>
> diff --git a/src/lxc/attach.c b/src/lxc/attach.c
> index 3ee1d4d..8b9bc8d 100644
> --- a/src/lxc/attach.c
> +++ b/src/lxc/attach.c
> @@ -698,32 +698,8 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
>
> /* attach to cgroup, if requested */
> if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) {
> - struct cgroup_meta_data *meta_data;
> - struct cgroup_process_info *container_info;
> -
> - meta_data = lxc_cgroup_load_meta();
> - if (!meta_data) {
> - ERROR("could not move attached process %ld to cgroup of container", (long)pid);
> + if (!lxc_cgroup_attach(name, lxcpath, pid))
> goto cleanup_error;
> - }
> -
> - container_info = lxc_cgroup_get_container_info(name, lxcpath, meta_data);
> - lxc_cgroup_put_meta(meta_data);
> - if (!container_info) {
> - ERROR("could not move attached process %ld to cgroup of container", (long)pid);
> - goto cleanup_error;
> - }
> -
> - /*
> - * TODO - switch over to using a cgroup_operation. We can't use
> - * cgroup_enter() as that takes a handler.
> - */
> - ret = lxc_cgroupfs_enter(container_info, pid, false);
> - lxc_cgroup_process_info_free(container_info);
> - if (ret < 0) {
> - ERROR("could not move attached process %ld to cgroup of container", (long)pid);
> - goto cleanup_error;
> - }
> }
>
> /* Let the child process know to go ahead */
> diff --git a/src/lxc/cgmanager.c b/src/lxc/cgmanager.c
> index bd3d7ff..2097a25 100644
> --- a/src/lxc/cgmanager.c
> +++ b/src/lxc/cgmanager.c
> @@ -55,12 +55,15 @@ lxc_log_define(lxc_cgmanager, lxc);
> #include <nih-dbus/dbus_connection.h>
> #include <cgmanager-client/cgmanager-client.h>
> #include <nih/alloc.h>
> +#include <nih/error.h>
> NihDBusProxy *cgroup_manager = NULL;
>
> extern struct cgroup_ops *active_cg_ops;
> bool cgmanager_initialized = false;
> bool use_cgmanager = true;
> static struct cgroup_ops cgmanager_ops;
> +static int nr_subsystems;
> +static char **subsystems;
>
> bool lxc_init_cgmanager(void);
> static void cgmanager_disconnected(DBusConnection *connection)
> @@ -105,10 +108,8 @@ static int send_creds(int sock, int rpid, int ruid, int rgid)
> msg.msg_iov = &iov;
> msg.msg_iovlen = 1;
>
> - if (sendmsg(sock, &msg, 0) < 0) {
> - perror("sendmsg");
> + if (sendmsg(sock, &msg, 0) < 0)
> return -1;
> - }
> return 0;
> }
>
> @@ -121,7 +122,12 @@ bool lxc_init_cgmanager(void)
>
> connection = nih_dbus_connect(CGMANAGER_DBUS_SOCK, cgmanager_disconnected);
> if (!connection) {
> - ERROR("Error opening cgmanager connection at %s", CGMANAGER_DBUS_SOCK);
> + NihError *nerr;
> + nerr = nih_error_get();
> + ERROR("Error opening cgmanager connection at %s: %s", CGMANAGER_DBUS_SOCK,
> + nerr->message);
> + nih_free(nerr);
> + dbus_error_free(&dbus_error);
> return false;
> }
> dbus_connection_set_exit_on_disconnect(connection, FALSE);
> @@ -131,28 +137,31 @@ bool lxc_init_cgmanager(void)
> "/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);
> return false;
> }
> active_cg_ops = &cgmanager_ops;
> + // force fd passing negotiation
> + if (cgmanager_ping_sync(NULL, cgroup_manager, 0) != 0) {
> + NihError *nerr;
> + nerr = nih_error_get();
> + ERROR("Error pinging cgroup manager: %s", nerr->message);
> + nih_free(nerr);
> + }
> return true;
> }
>
> -/*
> - * Use the cgmanager to move a task into a cgroup for a particular
> - * hierarchy.
> - * All the subsystems in this hierarchy are co-mounted, so we only
> - * need to transition the task into one of the cgroups
> - */
> -static bool lxc_cgmanager_enter(pid_t pid, char *controller, char *cgroup_path)
> -{
> - return cgmanager_move_pid_sync(NULL, cgroup_manager, controller,
> - cgroup_path, pid) == 0;
> -}
> -
> static bool lxc_cgmanager_create(const char *controller, const char *cgroup_path, int32_t *existed)
> {
> if ( cgmanager_create_sync(NULL, cgroup_manager, controller,
> cgroup_path, existed) != 0) {
> + NihError *nerr;
> + nerr = nih_error_get();
> + ERROR("call to cgmanager_create_sync failed: %s", nerr->message);
> + nih_free(nerr);
> ERROR("Failed to create %s:%s", controller, cgroup_path);
> return false;
> }
> @@ -163,17 +172,16 @@ static bool lxc_cgmanager_create(const char *controller, const char *cgroup_path
> struct chown_data {
> const char *controller;
> const char *cgroup_path;
> + uid_t origuid;
> };
>
> -static int do_chown_cgroup(const char *controller, const char *cgroup_path)
> +static int do_chown_cgroup(const char *controller, const char *cgroup_path,
> + uid_t origuid)
> {
> int sv[2] = {-1, -1}, optval = 1, ret = -1;
> char buf[1];
>
> - if (setgid(0) < 0)
> - WARN("Failed to setgid to 0");
> - if (setuid(0) < 0)
> - WARN("Failed to setuid to 0");
> + uid_t caller_nsuid = get_ns_uid(origuid);
>
> if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) {
> SYSERROR("Error creating socketpair");
> @@ -189,7 +197,10 @@ static int do_chown_cgroup(const char *controller, const char *cgroup_path)
> }
> if ( cgmanager_chown_scm_sync(NULL, cgroup_manager, controller,
> cgroup_path, sv[1]) != 0) {
> - ERROR("call to cgmanager_chown_scm_sync failed");
> + NihError *nerr;
> + nerr = nih_error_get();
> + ERROR("call to cgmanager_chown_scm_sync failed: %s", nerr->message);
> + nih_free(nerr);
> goto out;
> }
> /* now send credentials */
> @@ -206,7 +217,7 @@ static int do_chown_cgroup(const char *controller, const char *cgroup_path)
> goto out;
> }
> if (send_creds(sv[0], getpid(), getuid(), getgid())) {
> - ERROR("Error sending pid over SCM_CREDENTIAL");
> + SYSERROR("%s: Error sending pid over SCM_CREDENTIAL", __func__);
> goto out;
> }
> FD_ZERO(&rfds);
> @@ -219,8 +230,8 @@ static int do_chown_cgroup(const char *controller, const char *cgroup_path)
> ERROR("Error getting reply from server over socketpair");
> goto out;
> }
> - if (send_creds(sv[0], getpid(), 0, 0)) {
> - ERROR("Error sending pid over SCM_CREDENTIAL");
> + if (send_creds(sv[0], getpid(), caller_nsuid, 0)) {
> + SYSERROR("%s: Error sending pid over SCM_CREDENTIAL", __func__);
> goto out;
> }
> FD_ZERO(&rfds);
> @@ -241,21 +252,26 @@ out:
> static int chown_cgroup_wrapper(void *data)
> {
> struct chown_data *arg = data;
> - return do_chown_cgroup(arg->controller, arg->cgroup_path);
> +
> + if (setresgid(0,0,0) < 0)
> + SYSERROR("Failed to setgid to 0");
> + if (setresuid(0,0,0) < 0)
> + SYSERROR("Failed to setuid to 0");
> + return do_chown_cgroup(arg->controller, arg->cgroup_path, arg->origuid);
> }
>
> static bool chown_cgroup(const char *controller, const char *cgroup_path,
> struct lxc_conf *conf)
> {
> struct chown_data data;
> - data.controller = controller;
> - data.cgroup_path = cgroup_path;
>
> - if (lxc_list_empty(&conf->id_map)) {
> - if (do_chown_cgroup(controller, cgroup_path) < 0)
> - return false;
> + if (lxc_list_empty(&conf->id_map))
> + /* If there's no mapping then we don't need to chown */
> return true;
> - }
> +
> + data.controller = controller;
> + data.cgroup_path = cgroup_path;
> + data.origuid = geteuid();
>
> if (userns_exec_1(conf, chown_cgroup_wrapper, &data) < 0) {
> ERROR("Error requesting cgroup chown in new namespace");
> @@ -264,50 +280,45 @@ static bool chown_cgroup(const char *controller, const char *cgroup_path,
> return true;
> }
>
> -struct cgm_data {
> - int nr_subsystems;
> - char **subsystems;
> - char *cgroup_path;
> -};
> -
> #define CG_REMOVE_RECURSIVE 1
> -void cgmanager_remove_cgroup(const char *controller, const char *path)
> +static void cgm_remove_cgroup(const char *controller, const char *path)
> {
> int existed;
> if ( cgmanager_remove_sync(NULL, cgroup_manager, controller,
> - path, CG_REMOVE_RECURSIVE, &existed) != 0)
> + path, CG_REMOVE_RECURSIVE, &existed) != 0) {
> + NihError *nerr;
> + nerr = nih_error_get();
> + ERROR("call to cgmanager_remove_sync failed: %s", nerr->message);
> + nih_free(nerr);
> ERROR("Error removing %s:%s", controller, path);
> + }
> if (existed == -1)
> INFO("cgroup removal attempt: %s:%s did not exist", controller, path);
> }
>
> static void cgm_destroy(struct lxc_handler *handler)
> {
> - struct cgm_data *d = handler->cgroup_info->data;
> + char *cgroup_path = handler->cgroup_info->data;
> int i;
>
> - if (!d)
> + if (!cgroup_path)
> return;
> - for (i=0; i<d->nr_subsystems; i++) {
> - if (d->cgroup_path)
> - cgmanager_remove_cgroup(d->subsystems[i], d->cgroup_path);
> - free(d->subsystems[i]);
> - }
> - free(d->subsystems);
> - free(d->cgroup_path);
> - free(d);
> +
> + for (i = 0; i < nr_subsystems; i++)
> + cgm_remove_cgroup(subsystems[i], cgroup_path);
> +
> + free(cgroup_path);
> handler->cgroup_info->data = NULL;
> }
>
> /*
> * remove all the cgroups created
> */
> -static inline void cleanup_cgroups(struct cgm_data *d, char *path)
> +static inline void cleanup_cgroups(char *path)
> {
> int i;
> - for (i = 0; i < d->nr_subsystems; i++) {
> - cgmanager_remove_cgroup(d->subsystems[i], path);
> - }
> + for (i = 0; i < nr_subsystems; i++)
> + cgm_remove_cgroup(subsystems[i], path);
> }
>
> static inline bool cgm_create(struct lxc_handler *handler)
> @@ -315,7 +326,7 @@ static inline bool cgm_create(struct lxc_handler *handler)
> int i, index=0, baselen, ret;
> int32_t existed;
> char result[MAXPATHLEN], *tmp;
> - struct cgm_data *d = handler->cgroup_info->data;
> + 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
> @@ -344,44 +355,70 @@ again:
> return false;
> }
> existed = 0;
> - for (i = 0; i < d->nr_subsystems; i++) {
> - if (!lxc_cgmanager_create(d->subsystems[i], tmp, &existed)) {
> - ERROR("Error creating cgroup %s:%s", d->subsystems[i], result);
> - cleanup_cgroups(d, tmp);
> + 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
> - d->cgroup_path = strdup(tmp);
> - if (!d->cgroup_path) {
> - cleanup_cgroups(d, tmp);
> + cgroup_path = strdup(tmp);
> + if (!cgroup_path) {
> + cleanup_cgroups(tmp);
> return false;
> }
> + handler->cgroup_info->data = cgroup_path;
> return true;
> next:
> - cleanup_cgroups(d, tmp);
> + cleanup_cgroups(tmp);
> index++;
> goto again;
> }
>
> -static inline bool cgm_enter(struct lxc_handler *handler)
> +/*
> + * Use the cgmanager to move a task into a cgroup for a particular
> + * hierarchy.
> + * All the subsystems in this hierarchy are co-mounted, so we only
> + * need to transition the task into one of the cgroups
> + */
> +static bool lxc_cgmanager_enter(pid_t pid, const char *controller,
> + const char *cgroup_path)
> +{
> + if (cgmanager_move_pid_sync(NULL, cgroup_manager, controller,
> + cgroup_path, pid) != 0) {
> + NihError *nerr;
> + nerr = nih_error_get();
> + ERROR("call to cgmanager_move_pid_sync failed: %s", nerr->message);
> + nih_free(nerr);
> + return false;
> + }
> + return true;
> +}
> +
> +static bool do_cgm_enter(pid_t pid, const char *cgroup_path)
> {
> - struct cgm_data *d = handler->cgroup_info->data;
> int i;
>
> - for (i = 0; i < d->nr_subsystems; i++) {
> - if (!lxc_cgmanager_enter(handler->pid, d->subsystems[i], d->cgroup_path))
> + for (i = 0; i < nr_subsystems; i++) {
> + if (!lxc_cgmanager_enter(pid, subsystems[i], cgroup_path))
> return false;
> }
> return true;
> }
>
> +static inline bool cgm_enter(struct lxc_handler *handler)
> +{
> + char *cgroup_path = handler->cgroup_info->data;
> + return do_cgm_enter(handler->pid, cgroup_path);
> +}
> +
> static char *cgm_get_cgroup(struct lxc_handler *handler, const char *subsystem)
> {
> - struct cgm_data *d = handler->cgroup_info->data;
> - return d->cgroup_path;
> + char *cgroup_path = handler->cgroup_info->data;
> + return cgroup_path;
> }
>
> int cgm_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
> @@ -401,8 +438,14 @@ int cgm_get(const char *filename, char *value, size_t len, const char *name, con
> if (!cgroup)
> return -1;
> if (cgmanager_get_value_sync(NULL, cgroup_manager, controller, cgroup, filename, &result) != 0) {
> - ERROR("Error getting value for %s from cgmanager for cgroup %s (%s:%s)",
> - filename, cgroup, lxcpath, name);
> + /*
> + * must consume the nih error
> + * However don't print out an error as the key may simply not exist
> + * on the host
> + */
> + NihError *nerr;
> + nerr = nih_error_get();
> + nih_free(nerr);
> free(cgroup);
> return -1;
> }
> @@ -433,8 +476,13 @@ static int cgm_do_set(const char *controller, const char *file,
> int ret;
> ret = cgmanager_set_value_sync(NULL, cgroup_manager, controller,
> cgroup, file, value);
> - if (ret != 0)
> + if (ret != 0) {
> + NihError *nerr;
> + nerr = nih_error_get();
> + ERROR("call to cgmanager_remove_sync failed: %s", nerr->message);
> + nih_free(nerr);
> ERROR("Error setting cgroup %s limit %s", file, cgroup);
> + }
> return ret;
> }
>
> @@ -462,26 +510,18 @@ int cgm_set(const char *filename, const char *value, const char *name, const cha
> return ret;
> }
>
> -/*
> - * TODO really this should be done once for global data, not once
> - * per container
> - */
> -static inline bool cgm_init(struct lxc_handler *handler)
> +static bool collect_subsytems(void)
> {
> - struct cgm_data *d = malloc(sizeof(*d));
> char *line = NULL, *tab1;
> size_t sz = 0, i;
> FILE *f;
>
> - if (!d)
> - return false;
> - d->nr_subsystems = 0;
> - d->subsystems = NULL;
> + if (subsystems) // already initialized
> + return true;
> +
> f = fopen_cloexec("/proc/cgroups", "r");
> - if (!f) {
> - free(d);
> + if (!f)
> return false;
> - }
> while (getline(&line, &sz, f) != -1) {
> char **tmp;
> if (line[0] == '#')
> @@ -492,37 +532,51 @@ static inline bool cgm_init(struct lxc_handler *handler)
> if (!tab1)
> continue;
> *tab1 = '\0';
> - tmp = realloc(d->subsystems, (d->nr_subsystems+1)*sizeof(char *));
> - if (!tmp) {
> + tmp = realloc(subsystems, (nr_subsystems+1)*sizeof(char *));
> + if (!tmp)
> goto out_free;
> - }
> - d->subsystems = tmp;
> - d->subsystems[d->nr_subsystems] = strdup(line);
> - if (!d->subsystems[d->nr_subsystems])
> +
> + subsystems = tmp;
> + tmp[nr_subsystems] = strdup(line);
> + if (!tmp[nr_subsystems])
> goto out_free;
> - d->nr_subsystems++;
> + nr_subsystems++;
> }
> fclose(f);
>
> - d->cgroup_path = NULL;
> - handler->cgroup_info->data = d;
> + if (!nr_subsystems) {
> + ERROR("No cgroup subsystems found");
> + return false;
> + }
> +
> return true;
>
> out_free:
> - for (i=0; i<d->nr_subsystems; i++)
> - free(d->subsystems[i]);
> - free(d->subsystems);
> - free(d);
> + fclose(f);
> + for (i = 0; i < nr_subsystems; i++)
> + free(subsystems[i]);
> + free(subsystems);
> + subsystems = NULL;
> + nr_subsystems = 0;
> return false;
> }
>
> +static inline bool cgm_init(struct lxc_handler *handler)
> +{
> + return collect_subsytems();
> +}
> +
> static int cgm_unfreeze_fromhandler(struct lxc_handler *handler)
> {
> - struct cgm_data *d = handler->cgroup_info->data;
> + char *cgroup_path = handler->cgroup_info->data;
>
> - if (cgmanager_set_value_sync(NULL, cgroup_manager, "freezer", d->cgroup_path,
> + if (cgmanager_set_value_sync(NULL, cgroup_manager, "freezer", cgroup_path,
> "freezer.state", "THAWED") != 0) {
> - ERROR("Error unfreezing %s", d->cgroup_path);
> + NihError *nerr;
> + nerr = nih_error_get();
> + ERROR("call to cgmanager_set_value_sync failed: %s", nerr->message);
> + nih_free(nerr);
> + ERROR("Error unfreezing %s", cgroup_path);
> return -1;
> }
> return 0;
> @@ -534,7 +588,7 @@ static bool setup_limits(struct lxc_handler *h, bool do_devices)
> struct lxc_cgroup *cg;
> bool ret = false;
> struct lxc_list *cgroup_settings = &h->conf->cgroup;
> - struct cgm_data *d = h->cgroup_info->data;
> + char *cgroup_path = h->cgroup_info->data;
>
> if (lxc_list_empty(cgroup_settings))
> return true;
> @@ -550,7 +604,7 @@ static bool setup_limits(struct lxc_handler *h, bool do_devices)
> p = strchr(controller, '.');
> if (p)
> *p = '\0';
> - if (cgm_do_set(controller, cg->subsystem, d->cgroup_path
> + if (cgm_do_set(controller, cg->subsystem, cgroup_path
> , cg->value) < 0) {
> ERROR("Error setting %s to %s for %s\n",
> cg->subsystem, cg->value, h->name);
> @@ -573,17 +627,58 @@ static bool cgm_setup_limits(struct lxc_handler *handler, bool with_devices)
>
> static bool cgm_chown(struct lxc_handler *handler)
> {
> - struct cgm_data *d = handler->cgroup_info->data;
> + char *cgroup_path = handler->cgroup_info->data;
> int i;
>
> - for (i = 0; i < d->nr_subsystems; i++) {
> - if (!chown_cgroup(d->subsystems[i], d->cgroup_path, handler->conf))
> + for (i = 0; i < nr_subsystems; i++) {
> + if (!chown_cgroup(subsystems[i], cgroup_path, handler->conf))
> WARN("Failed to chown %s:%s to container root",
> - d->subsystems[i], d->cgroup_path);
> + subsystems[i], cgroup_path);
> }
> return true;
> }
>
> +/*
> + * 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 = false;
> + char *cgroup = NULL;
> + struct lxc_container *c;
> +
> + c = lxc_container_new(name, lxcpath);
> + if (!c) {
> + ERROR("Could not load container %s:%s", lxcpath, name);
> + return false;
> + }
> + if (!collect_subsytems()) {
> + ERROR("Error collecting cgroup subsystems");
> + goto out;
> + }
> + // 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 = lxc_cmd_get_cgroup_path(name, lxcpath, subsystems[0]);
> + if (!cgroup) {
> + ERROR("Failed to get cgroup for controller %s", subsystems[0]);
> + goto out;
> + }
> +
> + if (!(pass = do_cgm_enter(pid, cgroup)))
> + ERROR("Failed to enter group %s", cgroup);
> +
> +out:
> + free(cgroup);
> + lxc_container_put(c);
> + return pass;
> +}
> +
> static struct cgroup_ops cgmanager_ops = {
> .destroy = cgm_destroy,
> .init = cgm_init,
> @@ -597,5 +692,6 @@ static struct cgroup_ops cgmanager_ops = {
> .setup_limits = cgm_setup_limits,
> .name = "cgmanager",
> .chown = cgm_chown,
> + .attach = cgm_attach,
> };
> #endif
> diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c
> index a44982a..7456413 100644
> --- a/src/lxc/cgroup.c
> +++ b/src/lxc/cgroup.c
> @@ -2303,6 +2303,34 @@ bool cgroupfs_setup_limits(struct lxc_handler *h, bool with_devices)
> return do_setup_cgroup_limits(h, &h->conf->cgroup, with_devices) == 0;
> }
>
> +bool lxc_cgroupfs_attach(const char *name, const char *lxcpath, pid_t pid)
> +{
> + struct cgroup_meta_data *meta_data;
> + struct cgroup_process_info *container_info;
> + int ret;
> +
> + meta_data = lxc_cgroup_load_meta();
> + if (!meta_data) {
> + ERROR("could not move attached process %d to cgroup of container", pid);
> + return false;
> + }
> +
> + container_info = lxc_cgroup_get_container_info(name, lxcpath, meta_data);
> + lxc_cgroup_put_meta(meta_data);
> + if (!container_info) {
> + ERROR("could not move attached process %d to cgroup of container", pid);
> + return false;
> + }
> +
> + ret = lxc_cgroupfs_enter(container_info, pid, false);
> + lxc_cgroup_process_info_free(container_info);
> + if (ret < 0) {
> + ERROR("could not move attached process %d to cgroup of container", pid);
> + return false;
> + }
> + return true;
> +}
> +
> static struct cgroup_ops cgfs_ops = {
> .destroy = cgfs_destroy,
> .init = cgfs_init,
> @@ -2315,6 +2343,7 @@ static struct cgroup_ops cgfs_ops = {
> .unfreeze_fromhandler = cgfs_unfreeze_fromhandler,
> .setup_limits = cgroupfs_setup_limits,
> .name = "cgroupfs",
> + .attach = lxc_cgroupfs_attach,
> .chown = NULL,
> };
> static void init_cg_ops(void)
> @@ -2421,3 +2450,9 @@ bool cgroup_chown(struct lxc_handler *handler)
> return active_cg_ops->chown(handler);
> return true;
> }
> +
> +bool lxc_cgroup_attach(const char *name, const char *lxcpath, pid_t pid)
> +{
> + init_cg_ops();
> + return active_cg_ops->attach(name, lxcpath, pid);
> +}
> diff --git a/src/lxc/cgroup.h b/src/lxc/cgroup.h
> index a2e7cd3..a172ffb 100644
> --- a/src/lxc/cgroup.h
> +++ b/src/lxc/cgroup.h
> @@ -182,6 +182,7 @@ struct cgroup_ops {
> int (*unfreeze_fromhandler)(struct lxc_handler *handler);
> bool (*setup_limits)(struct lxc_handler *handler, bool with_devices);
> bool (*chown)(struct lxc_handler *handler);
> + bool (*attach)(const char *name, const char *lxcpath, pid_t pid);
> const char *name;
> };
>
> @@ -216,6 +217,7 @@ extern bool cgroup_enter(struct lxc_handler *handler);
> extern void cgroup_cleanup(struct lxc_handler *handler);
> extern bool cgroup_create_legacy(struct lxc_handler *handler);
> extern char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem);
> +extern bool lxc_cgroup_attach(const char *name, const char *lxcpath, pid_t pid);
> extern int lxc_cgroup_set(const char *filename, const char *value, const char *name, const char *lxcpath);
> extern int lxc_cgroup_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
> extern int lxc_unfreeze_fromhandler(struct lxc_handler *handler);
> diff --git a/src/lxc/utils.c b/src/lxc/utils.c
> index 2f9e08b..5ab4c77 100644
> --- a/src/lxc/utils.c
> +++ b/src/lxc/utils.c
> @@ -1111,3 +1111,28 @@ int randseed(bool srand_it)
>
> return seed;
> }
> +
> +uid_t get_ns_uid(uid_t orig)
> +{
> + char *line = NULL;
> + size_t sz = 0;
> + uid_t nsid, hostid, range;
> + FILE *f = fopen("/proc/self/uid_map", "r");
> + if (!f)
> + return 0;
> +
> + while (getline(&line, &sz, f) != -1) {
> + if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3)
> + continue;
> + if (hostid <= orig && hostid + range > orig) {
> + nsid += orig - hostid;
> + goto found;
> + }
> + }
> +
> + nsid = 0;
> +found:
> + fclose(f);
> + free(line);
> + return nsid;
> +}
> diff --git a/src/lxc/utils.h b/src/lxc/utils.h
> index e148fd8..f9037b7 100644
> --- a/src/lxc/utils.h
> +++ b/src/lxc/utils.h
> @@ -265,4 +265,9 @@ extern int randseed(bool);
> inline static bool am_unpriv(void) {
> return geteuid() != 0;
> }
> +
> +/*
> + * parse /proc/self/uid_map to find what @orig maps to
> + */
> +extern uid_t get_ns_uid(uid_t orig);
> #endif
> --
> 1.8.5.3
>
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel
--
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20140131/a6544cba/attachment-0001.pgp>
More information about the lxc-devel
mailing list