Quoting Stéphane Graber ([email protected]):
> This change makes lxc-attach and the matching API functions work
> properly with unprivileged containers.
> 
> The trick needed to make that possible was to always start with the
> userns when attaching and also relocate the cgroup management code so
> that the intermediate process is moved to the cgroup before attaching to
> the container's namespace as doing so later would fail due to missing
> permissions.
> 
> Signed-off-by: Stéphane Graber <[email protected]>

Awesome, thanks Stéphane.

Acked-by: Serge E. Hallyn <[email protected]>

> ---
>  src/lxc/attach.c       | 87 
> ++++++++++++++++++++++++++++++--------------------
>  src/lxc/lxc_attach.c   |  5 ---
>  src/lxc/lxccontainer.c | 10 ------
>  3 files changed, 52 insertions(+), 50 deletions(-)
> 
> diff --git a/src/lxc/attach.c b/src/lxc/attach.c
> index de32549..3ee1d4d 100644
> --- a/src/lxc/attach.c
> +++ b/src/lxc/attach.c
> @@ -144,10 +144,10 @@ static int lxc_attach_to_ns(pid_t pid, int which)
>        * the file for user namepsaces in /proc/$pid/ns will be called
>        * 'user' once the kernel supports it
>        */
> -     static char *ns[] = { "mnt", "pid", "uts", "ipc", "user", "net" };
> +     static char *ns[] = { "user", "mnt", "pid", "uts", "ipc", "net" };
>       static int flags[] = {
> -             CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
> -             CLONE_NEWUSER, CLONE_NEWNET
> +             CLONE_NEWUSER, CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, 
> CLONE_NEWIPC,
> +             CLONE_NEWNET
>       };
>       static const int size = sizeof(ns) / sizeof(char *);
>       int fd[size];
> @@ -593,7 +593,7 @@ static lxc_attach_options_t attach_static_default_options 
> = LXC_ATTACH_OPTIONS_D
>  int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t 
> exec_function, void* exec_payload, lxc_attach_options_t* options, pid_t* 
> attached_process)
>  {
>       int ret, status;
> -     pid_t init_pid, pid, attached_pid;
> +     pid_t init_pid, pid, attached_pid, expected;
>       struct lxc_proc_context_info *init_ctx;
>       char* cwd;
>       char* new_cwd;
> @@ -689,7 +689,6 @@ int lxc_attach(const char* name, const char* lxcpath, 
> lxc_attach_exec_t exec_fun
>  
>       if (pid) {
>               pid_t to_cleanup_pid = pid;
> -             int expected = 0;
>  
>               /* inital thread, we close the socket that is for the
>                * subprocesses
> @@ -697,6 +696,44 @@ int lxc_attach(const char* name, const char* lxcpath, 
> lxc_attach_exec_t exec_fun
>               close(ipc_sockets[1]);
>               free(cwd);
>  
> +             /* 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);
> +                             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 */
> +             status = 0;
> +             ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status));
> +             if (ret <= 0) {
> +                     ERROR("error using IPC to notify attached process for 
> initialization (0)");
> +                     goto cleanup_error;
> +             }
> +
>               /* get pid from intermediate process */
>               ret = lxc_read_nointr_expect(ipc_sockets[0], &attached_pid, 
> sizeof(attached_pid), NULL);
>               if (ret <= 0) {
> @@ -730,36 +767,6 @@ int lxc_attach(const char* name, const char* lxcpath, 
> lxc_attach_exec_t exec_fun
>                       goto cleanup_error;
>               }
>  
> -             /* 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)attached_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)attached_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, attached_pid, 
> false);
> -                     lxc_cgroup_process_info_free(container_info);
> -                     if (ret < 0) {
> -                             ERROR("could not move attached process %ld to 
> cgroup of container", (long)attached_pid);
> -                             goto cleanup_error;
> -                     }
> -             }
> -
>               /* tell attached process we're done */
>               status = 2;
>               ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status));
> @@ -798,6 +805,16 @@ int lxc_attach(const char* name, const char* lxcpath, 
> lxc_attach_exec_t exec_fun
>        */
>       close(ipc_sockets[0]);
>  
> +     /* Wait for the parent to have setup cgroups */
> +     expected = 0;
> +     status = -1;
> +     ret = lxc_read_nointr_expect(ipc_sockets[1], &status, sizeof(status), 
> &expected);
> +     if (ret <= 0) {
> +             ERROR("error communicating with child process");
> +             shutdown(ipc_sockets[1], SHUT_RDWR);
> +             rexit(-1);
> +     }
> +
>       /* attach now, create another subprocess later, since pid namespaces
>        * only really affect the children of the current process
>        */
> diff --git a/src/lxc/lxc_attach.c b/src/lxc/lxc_attach.c
> index 1159d09..6744c05 100644
> --- a/src/lxc/lxc_attach.c
> +++ b/src/lxc/lxc_attach.c
> @@ -188,11 +188,6 @@ int main(int argc, char *argv[])
>       lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
>       lxc_attach_command_t command;
>  
> -        if (geteuid() != 0) {
> -                ERROR("lxc-attach is not currently supported with 
> unprivileged containers");
> -                return -1;
> -        }
> -
>       ret = lxc_caps_init();
>       if (ret)
>               return ret;
> diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
> index 368cb46..38cf24e 100644
> --- a/src/lxc/lxccontainer.c
> +++ b/src/lxc/lxccontainer.c
> @@ -2567,11 +2567,6 @@ static int lxcapi_attach(struct lxc_container *c, 
> lxc_attach_exec_t exec_functio
>       if (!c)
>               return -1;
>  
> -     if (am_unpriv()) {
> -             ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__);
> -             return -1;
> -     }
> -
>       return lxc_attach(c->name, c->config_path, exec_function, exec_payload, 
> options, attached_process);
>  }
>  
> @@ -2584,11 +2579,6 @@ static int lxcapi_attach_run_wait(struct lxc_container 
> *c, lxc_attach_options_t
>       if (!c)
>               return -1;
>  
> -     if (am_unpriv()) {
> -             ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__);
> -             return -1;
> -     }
> -
>       command.program = (char*)program;
>       command.argv = (char**)argv;
>       r = lxc_attach(c->name, c->config_path, lxc_attach_run_command, 
> &command, options, &pid);
> -- 
> 1.8.5.3
> 
> _______________________________________________
> lxc-devel mailing list
> [email protected]
> http://lists.linuxcontainers.org/listinfo/lxc-devel
_______________________________________________
lxc-devel mailing list
[email protected]
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to