[lxc-devel] [PATCH v3 3/6] lxc-attach: Detect which namespaces to attach to dynamically

Serge Hallyn serge.hallyn at canonical.com
Thu May 24 14:17:44 UTC 2012


Quoting Christian Seiler (christian at iwakd.de):
> Use the command interface to contact lxc-start to receive the set of
> flags passed to clone() when starting the container. This allows lxc-attach
> to determine which namespaces were used for the container and select only
> those to attach to.
> 
> Signed-off-by: Christian Seiler <christian at iwakd.de>
> Cc: Daniel Lezcano <daniel.lezcano at free.fr>
> Cc: Serge Hallyn <serge.hallyn at canonical.com>

Looks nice, thanks.

Acked-by: Serge Hallyn <serge.hallyn at canonical.com>

> ---
>  src/lxc/attach.c     |   42 +++++++++++++++++++++++++++++++++++++-----
>  src/lxc/attach.h     |    2 +-
>  src/lxc/lxc_attach.c |   16 +++++++++++++++-
>  3 files changed, 53 insertions(+), 7 deletions(-)
> 
> diff --git a/src/lxc/attach.c b/src/lxc/attach.c
> index a95b3d3..37e667f 100644
> --- a/src/lxc/attach.c
> +++ b/src/lxc/attach.c
> @@ -121,13 +121,22 @@ out_error:
>  	return NULL;
>  }
>  
> -int lxc_attach_to_ns(pid_t pid)
> +int lxc_attach_to_ns(pid_t pid, int which)
>  {
>  	char path[MAXPATHLEN];
> -	char *ns[] = { "pid", "mnt", "net", "ipc", "uts" };
> -	const int size = sizeof(ns) / sizeof(char *);
> +	/* according to <http://article.gmane.org/gmane.linux.kernel.containers.lxc.devel/1429>,
> +	 * 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 int flags[] = {
> +		CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
> +		CLONE_NEWUSER, CLONE_NEWNET
> +	};
> +	static const int size = sizeof(ns) / sizeof(char *);
>  	int fd[size];
> -	int i;
> +	int i, j, saved_errno;
> +
>  
>  	snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid);
>  	if (access(path, X_OK)) {
> @@ -136,16 +145,39 @@ int lxc_attach_to_ns(pid_t pid)
>  	}
>  
>  	for (i = 0; i < size; i++) {
> +		/* ignore if we are not supposed to attach to that
> +		 * namespace
> +		 */
> +		if (which != -1 && !(which & flags[i])) {
> +			fd[i] = -1;
> +			continue;
> +		}
> +
>  		snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns[i]);
>  		fd[i] = open(path, O_RDONLY);
>  		if (fd[i] < 0) {
> +			saved_errno = errno;
> +
> +			/* close all already opened file descriptors before
> +			 * we return an error, so we don't leak them
> +			 */
> +			for (j = 0; j < i; j++)
> +				close(fd[j]);
> +
> +			errno = saved_errno;
>  			SYSERROR("failed to open '%s'", path);
>  			return -1;
>  		}
>  	}
>  
>  	for (i = 0; i < size; i++) {
> -		if (setns(fd[i], 0)) {
> +		if (fd[i] >= 0 && setns(fd[i], 0) != 0) {
> +			saved_errno = errno;
> +
> +			for (j = i; j < size; j++)
> +				close(fd[j]);
> +
> +			errno = saved_errno;
>  			SYSERROR("failed to set namespace '%s'", ns[i]);
>  			return -1;
>  		}
> diff --git a/src/lxc/attach.h b/src/lxc/attach.h
> index 2d46c83..d96fdae 100644
> --- a/src/lxc/attach.h
> +++ b/src/lxc/attach.h
> @@ -33,7 +33,7 @@ struct lxc_proc_context_info {
>  
>  extern struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid);
>  
> -extern int lxc_attach_to_ns(pid_t other_pid);
> +extern int lxc_attach_to_ns(pid_t other_pid, int which);
>  extern int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx);
>  
>  #endif
> diff --git a/src/lxc/lxc_attach.c b/src/lxc/lxc_attach.c
> index e4f604b..10d4a64 100644
> --- a/src/lxc/lxc_attach.c
> +++ b/src/lxc/lxc_attach.c
> @@ -51,6 +51,7 @@ static const struct option my_longopts[] = {
>  
>  static int elevated_privileges = 0;
>  static signed long new_personality = -1;
> +static int namespace_flags = -1;
>  
>  static int my_parser(struct lxc_arguments* args, int c, char* arg)
>  {
> @@ -139,11 +140,24 @@ int main(int argc, char *argv[])
>  
>  	curdir = get_current_dir_name();
>  
> +	/* determine which namespaces the container was created with
> +	 * by asking lxc-start
> +	 */
> +	if (namespace_flags == -1) {
> +		namespace_flags = lxc_get_clone_flags(my_args.name);
> +		/* call failed */
> +		if (namespace_flags == -1) {
> +			ERROR("failed to automatically determine the "
> +			      "namespaces which the container unshared");
> +			return -1;
> +		}
> +	}
> +
>  	/* we need to attach before we fork since certain namespaces
>  	 * (such as pid namespaces) only really affect children of the
>  	 * current process and not the process itself
>  	 */
> -	ret = lxc_attach_to_ns(init_pid);
> +	ret = lxc_attach_to_ns(init_pid, namespace_flags);
>  	if (ret < 0) {
>  		ERROR("failed to enter the namespace");
>  		return -1;
> -- 
> 1.7.2.5
> 




More information about the lxc-devel mailing list