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 <[email protected]>

Acked-by: Stéphane Graber <[email protected]>

> ---
>  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
> [email protected]
> http://lists.linuxcontainers.org/listinfo/lxc-devel

-- 
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com

Attachment: signature.asc
Description: Digital signature

_______________________________________________
lxc-devel mailing list
[email protected]
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to