userns: Don't let unprivileged users trick privileged users into setting the id_map
authorEric W. Biederman <ebiederm@xmission.com>
Sun, 14 Apr 2013 20:47:02 +0000 (13:47 -0700)
committerAndy Lutomirski <luto@amacapital.net>
Mon, 15 Apr 2013 01:11:14 +0000 (18:11 -0700)
When we require privilege for setting /proc/<pid>/uid_map or
/proc/<pid>/gid_map no longer allow an unprivileged user to
open the file and pass it to a privileged program to write
to the file.

Instead when privilege is required require both the opener and the
writer to have the necessary capabilities.

I have tested this code and verified that setting /proc/<pid>/uid_map
fails when an unprivileged user opens the file and a privielged user
attempts to set the mapping, that unprivileged users can still map
their own id, and that a privileged users can still setup an arbitrary
mapping.

Reported-by: Andy Lutomirski <luto@amacapital.net>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
kernel/user_namespace.c

index a54f26f82eb250a60c7f24ecc651c6c1bbf8cc88..e2d4ace4481bb0a277d45d1789082b28b74c3bae 100644 (file)
@@ -25,7 +25,8 @@
 
 static struct kmem_cache *user_ns_cachep __read_mostly;
 
-static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
+static bool new_idmap_permitted(const struct file *file,
+                               struct user_namespace *ns, int cap_setid,
                                struct uid_gid_map *map);
 
 static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
@@ -700,7 +701,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,
 
        ret = -EPERM;
        /* Validate the user is allowed to use user id's mapped to. */
-       if (!new_idmap_permitted(ns, cap_setid, &new_map))
+       if (!new_idmap_permitted(file, ns, cap_setid, &new_map))
                goto out;
 
        /* Map the lower ids from the parent user namespace to the
@@ -787,7 +788,8 @@ ssize_t proc_projid_map_write(struct file *file, const char __user *buf, size_t
                         &ns->projid_map, &ns->parent->projid_map);
 }
 
-static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
+static bool new_idmap_permitted(const struct file *file, 
+                               struct user_namespace *ns, int cap_setid,
                                struct uid_gid_map *new_map)
 {
        /* Allow mapping to your own filesystem ids */
@@ -811,8 +813,10 @@ static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
 
        /* Allow the specified ids if we have the appropriate capability
         * (CAP_SETUID or CAP_SETGID) over the parent user namespace.
+        * And the opener of the id file also had the approprpiate capability.
         */
-       if (ns_capable(ns->parent, cap_setid))
+       if (ns_capable(ns->parent, cap_setid) &&
+           file_ns_capable(file, ns->parent, cap_setid))
                return true;
 
        return false;