userns: Require CAP_SYS_ADMIN for most uses of setns.
authorEric W. Biederman <ebiederm@xmission.com>
Fri, 14 Dec 2012 15:55:36 +0000 (07:55 -0800)
committerEric W. Biederman <ebiederm@xmission.com>
Sat, 15 Dec 2012 00:12:03 +0000 (16:12 -0800)
Andy Lutomirski <luto@amacapital.net> found a nasty little bug in
the permissions of setns.  With unprivileged user namespaces it
became possible to create new namespaces without privilege.

However the setns calls were relaxed to only require CAP_SYS_ADMIN in
the user nameapce of the targed namespace.

Which made the following nasty sequence possible.

pid = clone(CLONE_NEWUSER | CLONE_NEWNS);
if (pid == 0) { /* child */
system("mount --bind /home/me/passwd /etc/passwd");
}
else if (pid != 0) { /* parent */
char path[PATH_MAX];
snprintf(path, sizeof(path), "/proc/%u/ns/mnt");
fd = open(path, O_RDONLY);
setns(fd, 0);
system("su -");
}

Prevent this possibility by requiring CAP_SYS_ADMIN
in the current user namespace when joing all but the user namespace.

Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
fs/namespace.c
ipc/namespace.c
kernel/pid_namespace.c
kernel/utsname.c
net/core/net_namespace.c

index c1bbe86f4920057d0cee12b70512d318740ad08d..398a50ff243848fae1145c695d6decc801d80f7d 100644 (file)
@@ -2781,7 +2781,8 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns)
        struct path root;
 
        if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) ||
-           !nsown_capable(CAP_SYS_CHROOT))
+           !nsown_capable(CAP_SYS_CHROOT) ||
+           !nsown_capable(CAP_SYS_ADMIN))
                return -EPERM;
 
        if (fs->users != 1)
index cf3386a51de25509f15c85871d447e95feee07fe..7c1fa451b0b0d75ae5265fea8fbe1193cb865223 100644 (file)
@@ -170,7 +170,8 @@ static void ipcns_put(void *ns)
 static int ipcns_install(struct nsproxy *nsproxy, void *new)
 {
        struct ipc_namespace *ns = new;
-       if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
+       if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
+           !nsown_capable(CAP_SYS_ADMIN))
                return -EPERM;
 
        /* Ditch state from the old ipc namespace */
index 560da0dab230aab631dab7003597815fc4d21c6b..fdbd0cdf271ae4ce6ad016f8b826510865fe3600 100644 (file)
@@ -325,7 +325,8 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns)
        struct pid_namespace *active = task_active_pid_ns(current);
        struct pid_namespace *ancestor, *new = ns;
 
-       if (!ns_capable(new->user_ns, CAP_SYS_ADMIN))
+       if (!ns_capable(new->user_ns, CAP_SYS_ADMIN) ||
+           !nsown_capable(CAP_SYS_ADMIN))
                return -EPERM;
 
        /*
index f6336d51d64c40a1759519ae0561c9ba07438ea8..08b197e8c485e4cb79dcee37a1b578f45566ad68 100644 (file)
@@ -113,7 +113,8 @@ static int utsns_install(struct nsproxy *nsproxy, void *new)
 {
        struct uts_namespace *ns = new;
 
-       if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
+       if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
+           !nsown_capable(CAP_SYS_ADMIN))
                return -EPERM;
 
        get_uts_ns(ns);
index 2e9a3132b8dd11ac8a9851e8042d8982af9c20ef..8acce01b6dab90dede80bfb4bed6b4ce4a965108 100644 (file)
@@ -649,7 +649,8 @@ static int netns_install(struct nsproxy *nsproxy, void *ns)
 {
        struct net *net = ns;
 
-       if (!ns_capable(net->user_ns, CAP_SYS_ADMIN))
+       if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) ||
+           !nsown_capable(CAP_SYS_ADMIN))
                return -EPERM;
 
        put_net(nsproxy->net_ns);
This page took 0.031952 seconds and 5 git commands to generate.