diff --git a/src/lxc/attach.c b/src/lxc/attach.c index a95b3d3cc..37e667fe1 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 , + * 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 2d46c83dc..d96fdae42 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 e4f604ba3..10d4a64ad 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;