[lxc-devel] [PATCH] attach: Support unprivileged containers
Serge Hallyn
serge.hallyn at ubuntu.com
Tue Jan 21 03:33:24 UTC 2014
Quoting Stéphane Graber (stgraber at ubuntu.com):
> 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 <stgraber at ubuntu.com>
Awesome, thanks Stéphane.
Acked-by: Serge E. Hallyn <serge.hallyn at ubuntu.com>
> ---
> 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
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel
More information about the lxc-devel
mailing list