summaryrefslogtreecommitdiffstats
path: root/kernel/ucount.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2016-08-08 15:41:52 -0400
committerEric W. Biederman <ebiederm@xmission.com>2016-08-08 15:41:52 -0400
commit25f9c0817c535a728c1088542230fa327c577c9e (patch)
tree50e60f8d962702d92b94392d536a1c71d77c851c /kernel/ucount.c
parentf6b2db1a3e8d141dd144df58900fb0444d5d7c53 (diff)
userns: Generalize the user namespace count into ucount
The same kind of recursive sane default limit and policy countrol that has been implemented for the user namespace is desirable for the other namespaces, so generalize the user namespace refernce count into a ucount. Acked-by: Kees Cook <keescook@chromium.org> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'kernel/ucount.c')
-rw-r--r--kernel/ucount.c39
1 files changed, 21 insertions, 18 deletions
diff --git a/kernel/ucount.c b/kernel/ucount.c
index 33c418718304..0f9ab3b26185 100644
--- a/kernel/ucount.c
+++ b/kernel/ucount.c
@@ -57,16 +57,17 @@ static struct ctl_table_root set_root = {
57 57
58static int zero = 0; 58static int zero = 0;
59static int int_max = INT_MAX; 59static int int_max = INT_MAX;
60#define UCOUNT_ENTRY(name) \
61 { \
62 .procname = name, \
63 .maxlen = sizeof(int), \
64 .mode = 0644, \
65 .proc_handler = proc_dointvec_minmax, \
66 .extra1 = &zero, \
67 .extra2 = &int_max, \
68 }
60static struct ctl_table user_table[] = { 69static struct ctl_table user_table[] = {
61 { 70 UCOUNT_ENTRY("max_user_namespaces"),
62 .procname = "max_user_namespaces",
63 .data = &init_user_ns.max_user_namespaces,
64 .maxlen = sizeof(init_user_ns.max_user_namespaces),
65 .mode = 0644,
66 .proc_handler = proc_dointvec_minmax,
67 .extra1 = &zero,
68 .extra2 = &int_max,
69 },
70 { } 71 { }
71}; 72};
72#endif /* CONFIG_SYSCTL */ 73#endif /* CONFIG_SYSCTL */
@@ -78,8 +79,10 @@ bool setup_userns_sysctls(struct user_namespace *ns)
78 setup_sysctl_set(&ns->set, &set_root, set_is_seen); 79 setup_sysctl_set(&ns->set, &set_root, set_is_seen);
79 tbl = kmemdup(user_table, sizeof(user_table), GFP_KERNEL); 80 tbl = kmemdup(user_table, sizeof(user_table), GFP_KERNEL);
80 if (tbl) { 81 if (tbl) {
81 tbl[0].data = &ns->max_user_namespaces; 82 int i;
82 83 for (i = 0; i < UCOUNT_COUNTS; i++) {
84 tbl[i].data = &ns->ucount_max[i];
85 }
83 ns->sysctls = __register_sysctl_table(&ns->set, "user", tbl); 86 ns->sysctls = __register_sysctl_table(&ns->set, "user", tbl);
84 } 87 }
85 if (!ns->sysctls) { 88 if (!ns->sysctls) {
@@ -172,7 +175,8 @@ static inline bool atomic_inc_below(atomic_t *v, int u)
172 } 175 }
173} 176}
174 177
175struct ucounts *inc_user_namespaces(struct user_namespace *ns, kuid_t uid) 178struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid,
179 enum ucount_type type)
176{ 180{
177 struct ucounts *ucounts, *iter, *bad; 181 struct ucounts *ucounts, *iter, *bad;
178 struct user_namespace *tns; 182 struct user_namespace *tns;
@@ -180,31 +184,30 @@ struct ucounts *inc_user_namespaces(struct user_namespace *ns, kuid_t uid)
180 for (iter = ucounts; iter; iter = tns->ucounts) { 184 for (iter = ucounts; iter; iter = tns->ucounts) {
181 int max; 185 int max;
182 tns = iter->ns; 186 tns = iter->ns;
183 max = READ_ONCE(tns->max_user_namespaces); 187 max = READ_ONCE(tns->ucount_max[type]);
184 if (!atomic_inc_below(&iter->user_namespaces, max)) 188 if (!atomic_inc_below(&iter->ucount[type], max))
185 goto fail; 189 goto fail;
186 } 190 }
187 return ucounts; 191 return ucounts;
188fail: 192fail:
189 bad = iter; 193 bad = iter;
190 for (iter = ucounts; iter != bad; iter = iter->ns->ucounts) 194 for (iter = ucounts; iter != bad; iter = iter->ns->ucounts)
191 atomic_dec(&iter->user_namespaces); 195 atomic_dec(&iter->ucount[type]);
192 196
193 put_ucounts(ucounts); 197 put_ucounts(ucounts);
194 return NULL; 198 return NULL;
195} 199}
196 200
197void dec_user_namespaces(struct ucounts *ucounts) 201void dec_ucount(struct ucounts *ucounts, enum ucount_type type)
198{ 202{
199 struct ucounts *iter; 203 struct ucounts *iter;
200 for (iter = ucounts; iter; iter = iter->ns->ucounts) { 204 for (iter = ucounts; iter; iter = iter->ns->ucounts) {
201 int dec = atomic_dec_if_positive(&iter->user_namespaces); 205 int dec = atomic_dec_if_positive(&iter->ucount[type]);
202 WARN_ON_ONCE(dec < 0); 206 WARN_ON_ONCE(dec < 0);
203 } 207 }
204 put_ucounts(ucounts); 208 put_ucounts(ucounts);
205} 209}
206 210
207
208static __init int user_namespace_sysctl_init(void) 211static __init int user_namespace_sysctl_init(void)
209{ 212{
210#ifdef CONFIG_SYSCTL 213#ifdef CONFIG_SYSCTL