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
