diff options
Diffstat (limited to 'kernel/ucount.c')
-rw-r--r-- | kernel/ucount.c | 39 |
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 = { static int zero = 0; static int int_max = INT_MAX; +#define UCOUNT_ENTRY(name) \ + { \ + .procname = name, \ + .maxlen = sizeof(int), \ + .mode = 0644, \ + .proc_handler = proc_dointvec_minmax, \ + .extra1 = &zero, \ + .extra2 = &int_max, \ + } static struct ctl_table user_table[] = { - { - .procname = "max_user_namespaces", - .data = &init_user_ns.max_user_namespaces, - .maxlen = sizeof(init_user_ns.max_user_namespaces), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &int_max, - }, + UCOUNT_ENTRY("max_user_namespaces"), { } }; #endif /* CONFIG_SYSCTL */ @@ -78,8 +79,10 @@ bool setup_userns_sysctls(struct user_namespace *ns) setup_sysctl_set(&ns->set, &set_root, set_is_seen); tbl = kmemdup(user_table, sizeof(user_table), GFP_KERNEL); if (tbl) { - tbl[0].data = &ns->max_user_namespaces; - + int i; + for (i = 0; i < UCOUNT_COUNTS; i++) { + tbl[i].data = &ns->ucount_max[i]; + } ns->sysctls = __register_sysctl_table(&ns->set, "user", tbl); } if (!ns->sysctls) { @@ -172,7 +175,8 @@ static inline bool atomic_inc_below(atomic_t *v, int u) } } -struct ucounts *inc_user_namespaces(struct user_namespace *ns, kuid_t uid) +struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, + enum ucount_type type) { struct ucounts *ucounts, *iter, *bad; struct user_namespace *tns; @@ -180,31 +184,30 @@ struct ucounts *inc_user_namespaces(struct user_namespace *ns, kuid_t uid) for (iter = ucounts; iter; iter = tns->ucounts) { int max; tns = iter->ns; - max = READ_ONCE(tns->max_user_namespaces); - if (!atomic_inc_below(&iter->user_namespaces, max)) + max = READ_ONCE(tns->ucount_max[type]); + if (!atomic_inc_below(&iter->ucount[type], max)) goto fail; } return ucounts; fail: bad = iter; for (iter = ucounts; iter != bad; iter = iter->ns->ucounts) - atomic_dec(&iter->user_namespaces); + atomic_dec(&iter->ucount[type]); put_ucounts(ucounts); return NULL; } -void dec_user_namespaces(struct ucounts *ucounts) +void dec_ucount(struct ucounts *ucounts, enum ucount_type type) { struct ucounts *iter; for (iter = ucounts; iter; iter = iter->ns->ucounts) { - int dec = atomic_dec_if_positive(&iter->user_namespaces); + int dec = atomic_dec_if_positive(&iter->ucount[type]); WARN_ON_ONCE(dec < 0); } put_ucounts(ucounts); } - static __init int user_namespace_sysctl_init(void) { #ifdef CONFIG_SYSCTL |