[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