26223f6
From: "Eric W. Biederman" <ebiederm@xmission.com>
26223f6
Date: Fri, 5 Dec 2014 18:01:11 -0600
26223f6
Subject: [PATCH] userns: Don't allow setgroups until a gid mapping has been
26223f6
 setablished
26223f6
26223f6
setgroups is unique in not needing a valid mapping before it can be called,
26223f6
in the case of setgroups(0, NULL) which drops all supplemental groups.
26223f6
26223f6
The design of the user namespace assumes that CAP_SETGID can not actually
26223f6
be used until a gid mapping is established.  Therefore add a helper function
26223f6
to see if the user namespace gid mapping has been established and call
26223f6
that function in the setgroups permission check.
26223f6
26223f6
This is part of the fix for CVE-2014-8989, being able to drop groups
26223f6
without privilege using user namespaces.
26223f6
26223f6
Cc: stable@vger.kernel.org
26223f6
Reviewed-by: Andy Lutomirski <luto@amacapital.net>
26223f6
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
26223f6
---
26223f6
 include/linux/user_namespace.h |  5 +++++
26223f6
 kernel/groups.c                |  4 +++-
26223f6
 kernel/user_namespace.c        | 14 ++++++++++++++
26223f6
 3 files changed, 22 insertions(+), 1 deletion(-)
26223f6
26223f6
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
26223f6
index e95372654f09..8d493083486a 100644
26223f6
--- a/include/linux/user_namespace.h
26223f6
+++ b/include/linux/user_namespace.h
26223f6
@@ -63,6 +63,7 @@ extern const struct seq_operations proc_projid_seq_operations;
26223f6
 extern ssize_t proc_uid_map_write(struct file *, const char __user *, size_t, loff_t *);
26223f6
 extern ssize_t proc_gid_map_write(struct file *, const char __user *, size_t, loff_t *);
26223f6
 extern ssize_t proc_projid_map_write(struct file *, const char __user *, size_t, loff_t *);
26223f6
+extern bool userns_may_setgroups(const struct user_namespace *ns);
26223f6
 #else
26223f6
 
26223f6
 static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
26223f6
@@ -87,6 +88,10 @@ static inline void put_user_ns(struct user_namespace *ns)
26223f6
 {
26223f6
 }
26223f6
 
26223f6
+static inline bool userns_may_setgroups(const struct user_namespace *ns)
26223f6
+{
26223f6
+	return true;
26223f6
+}
26223f6
 #endif
26223f6
 
26223f6
 #endif /* _LINUX_USER_H */
26223f6
diff --git a/kernel/groups.c b/kernel/groups.c
26223f6
index 02d8a251c476..664411f171b5 100644
26223f6
--- a/kernel/groups.c
26223f6
+++ b/kernel/groups.c
26223f6
@@ -6,6 +6,7 @@
26223f6
 #include <linux/slab.h>
26223f6
 #include <linux/security.h>
26223f6
 #include <linux/syscalls.h>
26223f6
+#include <linux/user_namespace.h>
26223f6
 #include <asm/uaccess.h>
26223f6
 
26223f6
 /* init to 2 - one for init_task, one to ensure it is never freed */
26223f6
@@ -217,7 +218,8 @@ bool may_setgroups(void)
26223f6
 {
26223f6
 	struct user_namespace *user_ns = current_user_ns();
26223f6
 
26223f6
-	return ns_capable(user_ns, CAP_SETGID);
26223f6
+	return ns_capable(user_ns, CAP_SETGID) &&
26223f6
+		userns_may_setgroups(user_ns);
26223f6
 }
26223f6
 
26223f6
 /*
26223f6
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
26223f6
index b99c862a2e3f..27c8dab48c07 100644
26223f6
--- a/kernel/user_namespace.c
26223f6
+++ b/kernel/user_namespace.c
26223f6
@@ -843,6 +843,20 @@ static bool new_idmap_permitted(const struct file *file,
26223f6
 	return false;
26223f6
 }
26223f6
 
26223f6
+bool userns_may_setgroups(const struct user_namespace *ns)
26223f6
+{
26223f6
+	bool allowed;
26223f6
+
26223f6
+	mutex_lock(&id_map_mutex);
26223f6
+	/* It is not safe to use setgroups until a gid mapping in
26223f6
+	 * the user namespace has been established.
26223f6
+	 */
26223f6
+	allowed = ns->gid_map.nr_extents != 0;
26223f6
+	mutex_unlock(&id_map_mutex);
26223f6
+
26223f6
+	return allowed;
26223f6
+}
26223f6
+
26223f6
 static void *userns_get(struct task_struct *task)
26223f6
 {
26223f6
 	struct user_namespace *user_ns;
26223f6
-- 
26223f6
2.1.0
26223f6