xref: /openbmc/linux/kernel/ucount.c (revision b376c3e1b6770ddcb4f0782be16358095fcea0b6)
1dbec2846SEric W. Biederman /*
2dbec2846SEric W. Biederman  *  This program is free software; you can redistribute it and/or
3dbec2846SEric W. Biederman  *  modify it under the terms of the GNU General Public License as
4dbec2846SEric W. Biederman  *  published by the Free Software Foundation, version 2 of the
5dbec2846SEric W. Biederman  *  License.
6dbec2846SEric W. Biederman  */
7dbec2846SEric W. Biederman 
8dbec2846SEric W. Biederman #include <linux/stat.h>
9dbec2846SEric W. Biederman #include <linux/sysctl.h>
10dbec2846SEric W. Biederman #include <linux/slab.h>
11dbec2846SEric W. Biederman #include <linux/user_namespace.h>
12dbec2846SEric W. Biederman 
13dbec2846SEric W. Biederman #ifdef CONFIG_SYSCTL
14dbec2846SEric W. Biederman static struct ctl_table_set *
15dbec2846SEric W. Biederman set_lookup(struct ctl_table_root *root)
16dbec2846SEric W. Biederman {
17dbec2846SEric W. Biederman 	return &current_user_ns()->set;
18dbec2846SEric W. Biederman }
19dbec2846SEric W. Biederman 
20dbec2846SEric W. Biederman static int set_is_seen(struct ctl_table_set *set)
21dbec2846SEric W. Biederman {
22dbec2846SEric W. Biederman 	return &current_user_ns()->set == set;
23dbec2846SEric W. Biederman }
24dbec2846SEric W. Biederman 
25dbec2846SEric W. Biederman static int set_permissions(struct ctl_table_header *head,
26dbec2846SEric W. Biederman 				  struct ctl_table *table)
27dbec2846SEric W. Biederman {
28dbec2846SEric W. Biederman 	struct user_namespace *user_ns =
29dbec2846SEric W. Biederman 		container_of(head->set, struct user_namespace, set);
30dbec2846SEric W. Biederman 	int mode;
31dbec2846SEric W. Biederman 
32dbec2846SEric W. Biederman 	/* Allow users with CAP_SYS_RESOURCE unrestrained access */
33dbec2846SEric W. Biederman 	if (ns_capable(user_ns, CAP_SYS_RESOURCE))
34dbec2846SEric W. Biederman 		mode = (table->mode & S_IRWXU) >> 6;
35dbec2846SEric W. Biederman 	else
36dbec2846SEric W. Biederman 	/* Allow all others at most read-only access */
37dbec2846SEric W. Biederman 		mode = table->mode & S_IROTH;
38dbec2846SEric W. Biederman 	return (mode << 6) | (mode << 3) | mode;
39dbec2846SEric W. Biederman }
40dbec2846SEric W. Biederman 
41dbec2846SEric W. Biederman static struct ctl_table_root set_root = {
42dbec2846SEric W. Biederman 	.lookup = set_lookup,
43dbec2846SEric W. Biederman 	.permissions = set_permissions,
44dbec2846SEric W. Biederman };
45dbec2846SEric W. Biederman 
46*b376c3e1SEric W. Biederman static int zero = 0;
47*b376c3e1SEric W. Biederman static int int_max = INT_MAX;
48dbec2846SEric W. Biederman static struct ctl_table userns_table[] = {
49*b376c3e1SEric W. Biederman 	{
50*b376c3e1SEric W. Biederman 		.procname	= "max_user_namespaces",
51*b376c3e1SEric W. Biederman 		.data		= &init_user_ns.max_user_namespaces,
52*b376c3e1SEric W. Biederman 		.maxlen		= sizeof(init_user_ns.max_user_namespaces),
53*b376c3e1SEric W. Biederman 		.mode		= 0644,
54*b376c3e1SEric W. Biederman 		.proc_handler	= proc_dointvec_minmax,
55*b376c3e1SEric W. Biederman 		.extra1		= &zero,
56*b376c3e1SEric W. Biederman 		.extra2		= &int_max,
57*b376c3e1SEric W. Biederman 	},
58dbec2846SEric W. Biederman 	{ }
59dbec2846SEric W. Biederman };
60dbec2846SEric W. Biederman #endif /* CONFIG_SYSCTL */
61dbec2846SEric W. Biederman 
62dbec2846SEric W. Biederman bool setup_userns_sysctls(struct user_namespace *ns)
63dbec2846SEric W. Biederman {
64dbec2846SEric W. Biederman #ifdef CONFIG_SYSCTL
65dbec2846SEric W. Biederman 	struct ctl_table *tbl;
66dbec2846SEric W. Biederman 	setup_sysctl_set(&ns->set, &set_root, set_is_seen);
67dbec2846SEric W. Biederman 	tbl = kmemdup(userns_table, sizeof(userns_table), GFP_KERNEL);
68dbec2846SEric W. Biederman 	if (tbl) {
69*b376c3e1SEric W. Biederman 		tbl[0].data = &ns->max_user_namespaces;
70*b376c3e1SEric W. Biederman 
71dbec2846SEric W. Biederman 		ns->sysctls = __register_sysctl_table(&ns->set, "userns", tbl);
72dbec2846SEric W. Biederman 	}
73dbec2846SEric W. Biederman 	if (!ns->sysctls) {
74dbec2846SEric W. Biederman 		kfree(tbl);
75dbec2846SEric W. Biederman 		retire_sysctl_set(&ns->set);
76dbec2846SEric W. Biederman 		return false;
77dbec2846SEric W. Biederman 	}
78dbec2846SEric W. Biederman #endif
79dbec2846SEric W. Biederman 	return true;
80dbec2846SEric W. Biederman }
81dbec2846SEric W. Biederman 
82dbec2846SEric W. Biederman void retire_userns_sysctls(struct user_namespace *ns)
83dbec2846SEric W. Biederman {
84dbec2846SEric W. Biederman #ifdef CONFIG_SYSCTL
85dbec2846SEric W. Biederman 	struct ctl_table *tbl;
86dbec2846SEric W. Biederman 
87dbec2846SEric W. Biederman 	tbl = ns->sysctls->ctl_table_arg;
88dbec2846SEric W. Biederman 	unregister_sysctl_table(ns->sysctls);
89dbec2846SEric W. Biederman 	retire_sysctl_set(&ns->set);
90dbec2846SEric W. Biederman 	kfree(tbl);
91dbec2846SEric W. Biederman #endif
92dbec2846SEric W. Biederman }
93dbec2846SEric W. Biederman 
94*b376c3e1SEric W. Biederman static inline bool atomic_inc_below(atomic_t *v, int u)
95*b376c3e1SEric W. Biederman {
96*b376c3e1SEric W. Biederman 	int c, old;
97*b376c3e1SEric W. Biederman 	c = atomic_read(v);
98*b376c3e1SEric W. Biederman 	for (;;) {
99*b376c3e1SEric W. Biederman 		if (unlikely(c >= u))
100*b376c3e1SEric W. Biederman 			return false;
101*b376c3e1SEric W. Biederman 		old = atomic_cmpxchg(v, c, c+1);
102*b376c3e1SEric W. Biederman 		if (likely(old == c))
103*b376c3e1SEric W. Biederman 			return true;
104*b376c3e1SEric W. Biederman 		c = old;
105*b376c3e1SEric W. Biederman 	}
106*b376c3e1SEric W. Biederman }
107*b376c3e1SEric W. Biederman 
108*b376c3e1SEric W. Biederman bool inc_user_namespaces(struct user_namespace *ns)
109*b376c3e1SEric W. Biederman {
110*b376c3e1SEric W. Biederman 	struct user_namespace *pos, *bad;
111*b376c3e1SEric W. Biederman 	for (pos = ns; pos; pos = pos->parent) {
112*b376c3e1SEric W. Biederman 		int max = READ_ONCE(pos->max_user_namespaces);
113*b376c3e1SEric W. Biederman 		if (!atomic_inc_below(&pos->user_namespaces, max))
114*b376c3e1SEric W. Biederman 			goto fail;
115*b376c3e1SEric W. Biederman 	}
116*b376c3e1SEric W. Biederman 	return true;
117*b376c3e1SEric W. Biederman fail:
118*b376c3e1SEric W. Biederman 	bad = pos;
119*b376c3e1SEric W. Biederman 	for (pos = ns; pos != bad; pos = pos->parent)
120*b376c3e1SEric W. Biederman 		atomic_dec(&pos->user_namespaces);
121*b376c3e1SEric W. Biederman 
122*b376c3e1SEric W. Biederman 	return false;
123*b376c3e1SEric W. Biederman }
124*b376c3e1SEric W. Biederman 
125*b376c3e1SEric W. Biederman void dec_user_namespaces(struct user_namespace *ns)
126*b376c3e1SEric W. Biederman {
127*b376c3e1SEric W. Biederman 	struct user_namespace *pos;
128*b376c3e1SEric W. Biederman 	for (pos = ns; pos; pos = pos->parent) {
129*b376c3e1SEric W. Biederman 		int dec = atomic_dec_if_positive(&pos->user_namespaces);
130*b376c3e1SEric W. Biederman 		WARN_ON_ONCE(dec < 0);
131*b376c3e1SEric W. Biederman 	}
132*b376c3e1SEric W. Biederman }
133*b376c3e1SEric W. Biederman 
134dbec2846SEric W. Biederman static __init int user_namespace_sysctl_init(void)
135dbec2846SEric W. Biederman {
136dbec2846SEric W. Biederman #ifdef CONFIG_SYSCTL
137dbec2846SEric W. Biederman 	static struct ctl_table_header *userns_header;
138dbec2846SEric W. Biederman 	static struct ctl_table empty[1];
139dbec2846SEric W. Biederman 	/*
140dbec2846SEric W. Biederman 	 * It is necessary to register the userns directory in the
141dbec2846SEric W. Biederman 	 * default set so that registrations in the child sets work
142dbec2846SEric W. Biederman 	 * properly.
143dbec2846SEric W. Biederman 	 */
144dbec2846SEric W. Biederman 	userns_header = register_sysctl("userns", empty);
145dbec2846SEric W. Biederman 	BUG_ON(!userns_header);
146dbec2846SEric W. Biederman 	BUG_ON(!setup_userns_sysctls(&init_user_ns));
147dbec2846SEric W. Biederman #endif
148dbec2846SEric W. Biederman 	return 0;
149dbec2846SEric W. Biederman }
150dbec2846SEric W. Biederman subsys_initcall(user_namespace_sysctl_init);
151dbec2846SEric W. Biederman 
152dbec2846SEric W. Biederman 
153