#define USERNS_INIT_FLAGS USERNS_SETGROUPS_ALLOWED
struct ucounts;
+
+enum ucount_type {
+ UCOUNT_USER_NAMESPACES,
+ UCOUNT_COUNTS,
+};
+
struct user_namespace {
struct uid_gid_map uid_map;
struct uid_gid_map gid_map;
struct ctl_table_header *sysctls;
#endif
struct ucounts *ucounts;
- int max_user_namespaces;
+ int ucount_max[UCOUNT_COUNTS];
};
struct ucounts {
struct user_namespace *ns;
kuid_t uid;
atomic_t count;
- atomic_t user_namespaces;
+ atomic_t ucount[UCOUNT_COUNTS];
};
extern struct user_namespace init_user_ns;
bool setup_userns_sysctls(struct user_namespace *ns);
void retire_userns_sysctls(struct user_namespace *ns);
-struct ucounts *inc_user_namespaces(struct user_namespace *ns, kuid_t uid);
-void dec_user_namespaces(struct ucounts *ucounts);
+struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, enum ucount_type type);
+void dec_ucount(struct ucounts *ucounts, enum ucount_type type);
#ifdef CONFIG_USER_NS
void __init fork_init(void)
{
+ int i;
#ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR
#ifndef ARCH_MIN_TASKALIGN
#define ARCH_MIN_TASKALIGN L1_CACHE_BYTES
init_task.signal->rlim[RLIMIT_SIGPENDING] =
init_task.signal->rlim[RLIMIT_NPROC];
- init_user_ns.max_user_namespaces = max_threads/2;
+ for (i = 0; i < UCOUNT_COUNTS; i++) {
+ init_user_ns.ucount_max[i] = max_threads/2;
+ }
}
int __weak arch_dup_task_struct(struct task_struct *dst,
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 */
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) {
}
}
-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;
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
struct uid_gid_map *map);
static void free_user_ns(struct work_struct *work);
+static struct ucounts *inc_user_namespaces(struct user_namespace *ns, kuid_t uid)
+{
+ return inc_ucount(ns, uid, UCOUNT_USER_NAMESPACES);
+}
+
+static void dec_user_namespaces(struct ucounts *ucounts)
+{
+ return dec_ucount(ucounts, UCOUNT_USER_NAMESPACES);
+}
+
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
kuid_t owner = new->euid;
kgid_t group = new->egid;
struct ucounts *ucounts;
- int ret;
+ int ret, i;
ret = -EUSERS;
if (parent_ns->level > 32)
ns->owner = owner;
ns->group = group;
INIT_WORK(&ns->work, free_user_ns);
- ns->max_user_namespaces = INT_MAX;
+ for (i = 0; i < UCOUNT_COUNTS; i++) {
+ ns->ucount_max[i] = INT_MAX;
+ }
ns->ucounts = ucounts;
/* Inherit USERNS_SETGROUPS_ALLOWED from our parent */