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)) {
}
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;
}
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)
{
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;