userns: Make the count of user namespaces per user

Add a structure that is per user and per user ns and use it to hold
the count of user namespaces.  This makes prevents one user from
creating denying service to another user by creating the maximum
number of user namespaces.

Rename the sysctl export of the maximum count from
/proc/sys/userns/max_user_namespaces to /proc/sys/user/max_user_namespaces
to reflect that the count is now per user.

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 7d87017..58c67e5 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -31,7 +31,6 @@
 				struct uid_gid_map *map);
 static void free_user_ns(struct work_struct *work);
 
-
 static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
 {
 	/* Start with the same capabilities as init but useless for doing
@@ -64,13 +63,15 @@
 	struct user_namespace *ns, *parent_ns = new->user_ns;
 	kuid_t owner = new->euid;
 	kgid_t group = new->egid;
+	struct ucounts *ucounts;
 	int ret;
 
 	ret = -EUSERS;
 	if (parent_ns->level > 32)
 		goto fail;
 
-	if (!inc_user_namespaces(parent_ns))
+	ucounts = inc_user_namespaces(parent_ns, owner);
+	if (!ucounts)
 		goto fail;
 
 	/*
@@ -110,6 +111,7 @@
 	ns->group = group;
 	INIT_WORK(&ns->work, free_user_ns);
 	ns->max_user_namespaces = INT_MAX;
+	ns->ucounts = ucounts;
 
 	/* Inherit USERNS_SETGROUPS_ALLOWED from our parent */
 	mutex_lock(&userns_state_mutex);
@@ -133,7 +135,7 @@
 fail_free:
 	kmem_cache_free(user_ns_cachep, ns);
 fail_dec:
-	dec_user_namespaces(parent_ns);
+	dec_user_namespaces(ucounts);
 fail:
 	return ret;
 }
@@ -164,6 +166,7 @@
 		container_of(work, struct user_namespace, work);
 
 	do {
+		struct ucounts *ucounts = ns->ucounts;
 		parent = ns->parent;
 		retire_userns_sysctls(ns);
 #ifdef CONFIG_PERSISTENT_KEYRINGS
@@ -171,7 +174,7 @@
 #endif
 		ns_free_inum(&ns->ns);
 		kmem_cache_free(user_ns_cachep, ns);
-		dec_user_namespaces(parent);
+		dec_user_namespaces(ucounts);
 		ns = parent;
 	} while (atomic_dec_and_test(&parent->count));
 }