summaryrefslogtreecommitdiffstats
path: root/kernel/ucount.c
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 /kernel/ucount.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/ucount.c')
-rw-r--r--kernel/ucount.c116
1 files changed, 95 insertions, 21 deletions
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;