From f4364484454c754ed905bfb85bd2727a0a5d0475 Mon Sep 17 00:00:00 2001 From: =?utf8?q?St=C3=A9phane=20Graber?= Date: Mon, 20 Jan 2014 15:26:15 -0500 Subject: [PATCH] attach: Support unprivileged containers MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Acked-by: Serge E. Hallyn --- 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 de325497b..3ee1d4d1c 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 1159d0958..6744c0587 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 368cb46bf..38cf24e97 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); -- 2.47.2