aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2016-08-08 14:54:50 -0400
committerEric W. Biederman <ebiederm@xmission.com>2016-08-08 15:40:30 -0400
commitf6b2db1a3e8d141dd144df58900fb0444d5d7c53 (patch)
treeaba951303e8d0c07b3f0293e33cd0af230b813a5
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>
-rw-r--r--include/linux/user_namespace.h18
-rw-r--r--kernel/fork.c2
-rw-r--r--kernel/ucount.c116
-rw-r--r--kernel/user_namespace.c11
4 files changed, 117 insertions, 30 deletions
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index 6421cca2daa9..826de7a12a20 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -22,6 +22,7 @@ struct uid_gid_map { /* 64 bytes -- 1 cache line */
22 22
23#define USERNS_INIT_FLAGS USERNS_SETGROUPS_ALLOWED 23#define USERNS_INIT_FLAGS USERNS_SETGROUPS_ALLOWED
24 24
25struct ucounts;
25struct user_namespace { 26struct user_namespace {
26 struct uid_gid_map uid_map; 27 struct uid_gid_map uid_map;
27 struct uid_gid_map gid_map; 28 struct uid_gid_map gid_map;
@@ -44,15 +45,24 @@ struct user_namespace {
44 struct ctl_table_set set; 45 struct ctl_table_set set;
45 struct ctl_table_header *sysctls; 46 struct ctl_table_header *sysctls;
46#endif 47#endif
48 struct ucounts *ucounts;
47 int max_user_namespaces; 49 int max_user_namespaces;
50};
51
52struct ucounts {
53 struct hlist_node node;
54 struct user_namespace *ns;
55 kuid_t uid;
56 atomic_t count;
48 atomic_t user_namespaces; 57 atomic_t user_namespaces;
49}; 58};
50 59
51extern struct user_namespace init_user_ns; 60extern struct user_namespace init_user_ns;
52extern bool setup_userns_sysctls(struct user_namespace *ns); 61
53extern void retire_userns_sysctls(struct user_namespace *ns); 62bool setup_userns_sysctls(struct user_namespace *ns);
54extern bool inc_user_namespaces(struct user_namespace *ns); 63void retire_userns_sysctls(struct user_namespace *ns);
55extern void dec_user_namespaces(struct user_namespace *ns); 64struct ucounts *inc_user_namespaces(struct user_namespace *ns, kuid_t uid);
65void dec_user_namespaces(struct ucounts *ucounts);
56 66
57#ifdef CONFIG_USER_NS 67#ifdef CONFIG_USER_NS
58 68
diff --git a/kernel/fork.c b/kernel/fork.c
index daa6a82b4900..d8cde533ace3 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -322,7 +322,7 @@ void __init fork_init(void)
322 init_task.signal->rlim[RLIMIT_SIGPENDING] = 322 init_task.signal->rlim[RLIMIT_SIGPENDING] =
323 init_task.signal->rlim[RLIMIT_NPROC]; 323 init_task.signal->rlim[RLIMIT_NPROC];
324 324
325 init_user_ns.max_user_namespaces = max_threads; 325 init_user_ns.max_user_namespaces = max_threads/2;
326} 326}
327 327
328int __weak arch_dup_task_struct(struct task_struct *dst, 328int __weak arch_dup_task_struct(struct task_struct *dst,
diff --git a/kernel/ucount.c b/kernel/ucount.c
index 6c2205c0befd..33c418718304 100644
--- a/kernel/ucount.c
+++ b/kernel/ucount.c
@@ -8,8 +8,20 @@
8#include <linux/stat.h> 8#include <linux/stat.h>
9#include <linux/sysctl.h> 9#include <linux/sysctl.h>
10#include <linux/slab.h> 10#include <linux/slab.h>
11#include <linux/hash.h>
11#include <linux/user_namespace.h> 12#include <linux/user_namespace.h>
12 13
14#define UCOUNTS_HASHTABLE_BITS 10
15static struct hlist_head ucounts_hashtable[(1 << UCOUNTS_HASHTABLE_BITS)];
16static DEFINE_SPINLOCK(ucounts_lock);
17
18#define ucounts_hashfn(ns, uid) \
19 hash_long((unsigned long)__kuid_val(uid) + (unsigned long)(ns), \
20 UCOUNTS_HASHTABLE_BITS)
21#define ucounts_hashentry(ns, uid) \
22 (ucounts_hashtable + ucounts_hashfn(ns, uid))
23
24
13#ifdef CONFIG_SYSCTL 25#ifdef CONFIG_SYSCTL
14static struct ctl_table_set * 26static struct ctl_table_set *
15set_lookup(struct ctl_table_root *root) 27set_lookup(struct ctl_table_root *root)
@@ -45,7 +57,7 @@ static struct ctl_table_root set_root = {
45 57
46static int zero = 0; 58static int zero = 0;
47static int int_max = INT_MAX; 59static int int_max = INT_MAX;
48static struct ctl_table userns_table[] = { 60static struct ctl_table user_table[] = {
49 { 61 {
50 .procname = "max_user_namespaces", 62 .procname = "max_user_namespaces",
51 .data = &init_user_ns.max_user_namespaces, 63 .data = &init_user_ns.max_user_namespaces,
@@ -64,11 +76,11 @@ bool setup_userns_sysctls(struct user_namespace *ns)
64#ifdef CONFIG_SYSCTL 76#ifdef CONFIG_SYSCTL
65 struct ctl_table *tbl; 77 struct ctl_table *tbl;
66 setup_sysctl_set(&ns->set, &set_root, set_is_seen); 78 setup_sysctl_set(&ns->set, &set_root, set_is_seen);
67 tbl = kmemdup(userns_table, sizeof(userns_table), GFP_KERNEL); 79 tbl = kmemdup(user_table, sizeof(user_table), GFP_KERNEL);
68 if (tbl) { 80 if (tbl) {
69 tbl[0].data = &ns->max_user_namespaces; 81 tbl[0].data = &ns->max_user_namespaces;
70 82
71 ns->sysctls = __register_sysctl_table(&ns->set, "userns", tbl); 83 ns->sysctls = __register_sysctl_table(&ns->set, "user", tbl);
72 } 84 }
73 if (!ns->sysctls) { 85 if (!ns->sysctls) {
74 kfree(tbl); 86 kfree(tbl);
@@ -91,6 +103,61 @@ void retire_userns_sysctls(struct user_namespace *ns)
91#endif 103#endif
92} 104}
93 105
106static struct ucounts *find_ucounts(struct user_namespace *ns, kuid_t uid, struct hlist_head *hashent)
107{
108 struct ucounts *ucounts;
109
110 hlist_for_each_entry(ucounts, hashent, node) {
111 if (uid_eq(ucounts->uid, uid) && (ucounts->ns == ns))
112 return ucounts;
113 }
114 return NULL;
115}
116
117static struct ucounts *get_ucounts(struct user_namespace *ns, kuid_t uid)
118{
119 struct hlist_head *hashent = ucounts_hashentry(ns, uid);
120 struct ucounts *ucounts, *new;
121
122 spin_lock(&ucounts_lock);
123 ucounts = find_ucounts(ns, uid, hashent);
124 if (!ucounts) {
125 spin_unlock(&ucounts_lock);
126
127 new = kzalloc(sizeof(*new), GFP_KERNEL);
128 if (!new)
129 return NULL;
130
131 new->ns = ns;
132 new->uid = uid;
133 atomic_set(&new->count, 0);
134
135 spin_lock(&ucounts_lock);
136 ucounts = find_ucounts(ns, uid, hashent);
137 if (ucounts) {
138 kfree(new);
139 } else {
140 hlist_add_head(&new->node, hashent);
141 ucounts = new;
142 }
143 }
144 if (!atomic_add_unless(&ucounts->count, 1, INT_MAX))
145 ucounts = NULL;
146 spin_unlock(&ucounts_lock);
147 return ucounts;
148}
149
150static void put_ucounts(struct ucounts *ucounts)
151{
152 if (atomic_dec_and_test(&ucounts->count)) {
153 spin_lock(&ucounts_lock);
154 hlist_del_init(&ucounts->node);
155 spin_unlock(&ucounts_lock);
156
157 kfree(ucounts);
158 }
159}
160
94static inline bool atomic_inc_below(atomic_t *v, int u) 161static inline bool atomic_inc_below(atomic_t *v, int u)
95{ 162{
96 int c, old; 163 int c, old;
@@ -105,44 +172,51 @@ static inline bool atomic_inc_below(atomic_t *v, int u)
105 } 172 }
106} 173}
107 174
108bool inc_user_namespaces(struct user_namespace *ns) 175struct ucounts *inc_user_namespaces(struct user_namespace *ns, kuid_t uid)
109{ 176{
110 struct user_namespace *pos, *bad; 177 struct ucounts *ucounts, *iter, *bad;
111 for (pos = ns; pos; pos = pos->parent) { 178 struct user_namespace *tns;
112 int max = READ_ONCE(pos->max_user_namespaces); 179 ucounts = get_ucounts(ns, uid);
113 if (!atomic_inc_below(&pos->user_namespaces, max)) 180 for (iter = ucounts; iter; iter = tns->ucounts) {
181 int max;
182 tns = iter->ns;
183 max = READ_ONCE(tns->max_user_namespaces);
184 if (!atomic_inc_below(&iter->user_namespaces, max))
114 goto fail; 185 goto fail;
115 } 186 }
116 return true; 187 return ucounts;
117fail: 188fail:
118 bad = pos; 189 bad = iter;
119 for (pos = ns; pos != bad; pos = pos->parent) 190 for (iter = ucounts; iter != bad; iter = iter->ns->ucounts)
120 atomic_dec(&pos->user_namespaces); 191 atomic_dec(&iter->user_namespaces);
121 192
122 return false; 193 put_ucounts(ucounts);
194 return NULL;
123} 195}
124 196
125void dec_user_namespaces(struct user_namespace *ns) 197void dec_user_namespaces(struct ucounts *ucounts)
126{ 198{
127 struct user_namespace *pos; 199 struct ucounts *iter;
128 for (pos = ns; pos; pos = pos->parent) { 200 for (iter = ucounts; iter; iter = iter->ns->ucounts) {
129 int dec = atomic_dec_if_positive(&pos->user_namespaces); 201 int dec = atomic_dec_if_positive(&iter->user_namespaces);
130 WARN_ON_ONCE(dec < 0); 202 WARN_ON_ONCE(dec < 0);
131 } 203 }
204 put_ucounts(ucounts);
132} 205}
133 206
207
134static __init int user_namespace_sysctl_init(void) 208static __init int user_namespace_sysctl_init(void)
135{ 209{
136#ifdef CONFIG_SYSCTL 210#ifdef CONFIG_SYSCTL
137 static struct ctl_table_header *userns_header; 211 static struct ctl_table_header *user_header;
138 static struct ctl_table empty[1]; 212 static struct ctl_table empty[1];
139 /* 213 /*
140 * It is necessary to register the userns directory in the 214 * It is necessary to register the user directory in the
141 * default set so that registrations in the child sets work 215 * default set so that registrations in the child sets work
142 * properly. 216 * properly.
143 */ 217 */
144 userns_header = register_sysctl("userns", empty); 218 user_header = register_sysctl("user", empty);
145 BUG_ON(!userns_header); 219 BUG_ON(!user_header);
146 BUG_ON(!setup_userns_sysctls(&init_user_ns)); 220 BUG_ON(!setup_userns_sysctls(&init_user_ns));
147#endif 221#endif
148 return 0; 222 return 0;
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,
31 struct uid_gid_map *map); 31 struct uid_gid_map *map);
32static void free_user_ns(struct work_struct *work); 32static void free_user_ns(struct work_struct *work);
33 33
34
35static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns) 34static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
36{ 35{
37 /* Start with the same capabilities as init but useless for doing 36 /* Start with the same capabilities as init but useless for doing
@@ -64,13 +63,15 @@ int create_user_ns(struct cred *new)
64 struct user_namespace *ns, *parent_ns = new->user_ns; 63 struct user_namespace *ns, *parent_ns = new->user_ns;
65 kuid_t owner = new->euid; 64 kuid_t owner = new->euid;
66 kgid_t group = new->egid; 65 kgid_t group = new->egid;
66 struct ucounts *ucounts;
67 int ret; 67 int ret;
68 68
69 ret = -EUSERS; 69 ret = -EUSERS;
70 if (parent_ns->level > 32) 70 if (parent_ns->level > 32)
71 goto fail; 71 goto fail;
72 72
73 if (!inc_user_namespaces(parent_ns)) 73 ucounts = inc_user_namespaces(parent_ns, owner);
74 if (!ucounts)
74 goto fail; 75 goto fail;
75 76
76 /* 77 /*
@@ -110,6 +111,7 @@ int create_user_ns(struct cred *new)
110 ns->group = group; 111 ns->group = group;
111 INIT_WORK(&ns->work, free_user_ns); 112 INIT_WORK(&ns->work, free_user_ns);
112 ns->max_user_namespaces = INT_MAX; 113 ns->max_user_namespaces = INT_MAX;
114 ns->ucounts = ucounts;
113 115
114 /* Inherit USERNS_SETGROUPS_ALLOWED from our parent */ 116 /* Inherit USERNS_SETGROUPS_ALLOWED from our parent */
115 mutex_lock(&userns_state_mutex); 117 mutex_lock(&userns_state_mutex);
@@ -133,7 +135,7 @@ fail_keyring:
133fail_free: 135fail_free:
134 kmem_cache_free(user_ns_cachep, ns); 136 kmem_cache_free(user_ns_cachep, ns);
135fail_dec: 137fail_dec:
136 dec_user_namespaces(parent_ns); 138 dec_user_namespaces(ucounts);
137fail: 139fail:
138 return ret; 140 return ret;
139} 141}
@@ -164,6 +166,7 @@ static void free_user_ns(struct work_struct *work)
164 container_of(work, struct user_namespace, work); 166 container_of(work, struct user_namespace, work);
165 167
166 do { 168 do {
169 struct ucounts *ucounts = ns->ucounts;
167 parent = ns->parent; 170 parent = ns->parent;
168 retire_userns_sysctls(ns); 171 retire_userns_sysctls(ns);
169#ifdef CONFIG_PERSISTENT_KEYRINGS 172#ifdef CONFIG_PERSISTENT_KEYRINGS
@@ -171,7 +174,7 @@ static void free_user_ns(struct work_struct *work)
171#endif 174#endif
172 ns_free_inum(&ns->ns); 175 ns_free_inum(&ns->ns);
173 kmem_cache_free(user_ns_cachep, ns); 176 kmem_cache_free(user_ns_cachep, ns);
174 dec_user_namespaces(parent); 177 dec_user_namespaces(ucounts);
175 ns = parent; 178 ns = parent;
176 } while (atomic_dec_and_test(&parent->count)); 179 } while (atomic_dec_and_test(&parent->count));
177} 180}