summaryrefslogtreecommitdiff
path: root/kernel/user_namespace.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2016-08-08 13:54:50 -0500
committerEric W. Biederman <ebiederm@xmission.com>2016-08-08 14:40:30 -0500
commitf6b2db1a3e8d141dd144df58900fb0444d5d7c53 (patch)
treeaba951303e8d0c07b3f0293e33cd0af230b813a5 /kernel/user_namespace.c
parentb376c3e1b6770ddcb4f0782be16358095fcea0b6 (diff)
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>
Diffstat (limited to 'kernel/user_namespace.c')
-rw-r--r--kernel/user_namespace.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 7d87017a0040..58c67e5f851c 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -31,7 +31,6 @@ static bool new_idmap_permitted(const struct file *file,
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 @@ int create_user_ns(struct cred *new)
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 @@ int create_user_ns(struct cred *new)
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_keyring:
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 @@ static void free_user_ns(struct work_struct *work)
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 @@ static void free_user_ns(struct work_struct *work)
#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));
}