xref: /openbmc/linux/kernel/ucount.c (revision dbec28460a89aa7c02c3301e9e108d98272549d2)
1*dbec2846SEric W. Biederman /*
2*dbec2846SEric W. Biederman  *  This program is free software; you can redistribute it and/or
3*dbec2846SEric W. Biederman  *  modify it under the terms of the GNU General Public License as
4*dbec2846SEric W. Biederman  *  published by the Free Software Foundation, version 2 of the
5*dbec2846SEric W. Biederman  *  License.
6*dbec2846SEric W. Biederman  */
7*dbec2846SEric W. Biederman 
8*dbec2846SEric W. Biederman #include <linux/stat.h>
9*dbec2846SEric W. Biederman #include <linux/sysctl.h>
10*dbec2846SEric W. Biederman #include <linux/slab.h>
11*dbec2846SEric W. Biederman #include <linux/user_namespace.h>
12*dbec2846SEric W. Biederman 
13*dbec2846SEric W. Biederman #ifdef CONFIG_SYSCTL
14*dbec2846SEric W. Biederman static struct ctl_table_set *
15*dbec2846SEric W. Biederman set_lookup(struct ctl_table_root *root)
16*dbec2846SEric W. Biederman {
17*dbec2846SEric W. Biederman 	return &current_user_ns()->set;
18*dbec2846SEric W. Biederman }
19*dbec2846SEric W. Biederman 
20*dbec2846SEric W. Biederman static int set_is_seen(struct ctl_table_set *set)
21*dbec2846SEric W. Biederman {
22*dbec2846SEric W. Biederman 	return &current_user_ns()->set == set;
23*dbec2846SEric W. Biederman }
24*dbec2846SEric W. Biederman 
25*dbec2846SEric W. Biederman static int set_permissions(struct ctl_table_header *head,
26*dbec2846SEric W. Biederman 				  struct ctl_table *table)
27*dbec2846SEric W. Biederman {
28*dbec2846SEric W. Biederman 	struct user_namespace *user_ns =
29*dbec2846SEric W. Biederman 		container_of(head->set, struct user_namespace, set);
30*dbec2846SEric W. Biederman 	int mode;
31*dbec2846SEric W. Biederman 
32*dbec2846SEric W. Biederman 	/* Allow users with CAP_SYS_RESOURCE unrestrained access */
33*dbec2846SEric W. Biederman 	if (ns_capable(user_ns, CAP_SYS_RESOURCE))
34*dbec2846SEric W. Biederman 		mode = (table->mode & S_IRWXU) >> 6;
35*dbec2846SEric W. Biederman 	else
36*dbec2846SEric W. Biederman 	/* Allow all others at most read-only access */
37*dbec2846SEric W. Biederman 		mode = table->mode & S_IROTH;
38*dbec2846SEric W. Biederman 	return (mode << 6) | (mode << 3) | mode;
39*dbec2846SEric W. Biederman }
40*dbec2846SEric W. Biederman 
41*dbec2846SEric W. Biederman static struct ctl_table_root set_root = {
42*dbec2846SEric W. Biederman 	.lookup = set_lookup,
43*dbec2846SEric W. Biederman 	.permissions = set_permissions,
44*dbec2846SEric W. Biederman };
45*dbec2846SEric W. Biederman 
46*dbec2846SEric W. Biederman static struct ctl_table userns_table[] = {
47*dbec2846SEric W. Biederman 	{ }
48*dbec2846SEric W. Biederman };
49*dbec2846SEric W. Biederman #endif /* CONFIG_SYSCTL */
50*dbec2846SEric W. Biederman 
51*dbec2846SEric W. Biederman bool setup_userns_sysctls(struct user_namespace *ns)
52*dbec2846SEric W. Biederman {
53*dbec2846SEric W. Biederman #ifdef CONFIG_SYSCTL
54*dbec2846SEric W. Biederman 	struct ctl_table *tbl;
55*dbec2846SEric W. Biederman 	setup_sysctl_set(&ns->set, &set_root, set_is_seen);
56*dbec2846SEric W. Biederman 	tbl = kmemdup(userns_table, sizeof(userns_table), GFP_KERNEL);
57*dbec2846SEric W. Biederman 	if (tbl) {
58*dbec2846SEric W. Biederman 		ns->sysctls = __register_sysctl_table(&ns->set, "userns", tbl);
59*dbec2846SEric W. Biederman 	}
60*dbec2846SEric W. Biederman 	if (!ns->sysctls) {
61*dbec2846SEric W. Biederman 		kfree(tbl);
62*dbec2846SEric W. Biederman 		retire_sysctl_set(&ns->set);
63*dbec2846SEric W. Biederman 		return false;
64*dbec2846SEric W. Biederman 	}
65*dbec2846SEric W. Biederman #endif
66*dbec2846SEric W. Biederman 	return true;
67*dbec2846SEric W. Biederman }
68*dbec2846SEric W. Biederman 
69*dbec2846SEric W. Biederman void retire_userns_sysctls(struct user_namespace *ns)
70*dbec2846SEric W. Biederman {
71*dbec2846SEric W. Biederman #ifdef CONFIG_SYSCTL
72*dbec2846SEric W. Biederman 	struct ctl_table *tbl;
73*dbec2846SEric W. Biederman 
74*dbec2846SEric W. Biederman 	tbl = ns->sysctls->ctl_table_arg;
75*dbec2846SEric W. Biederman 	unregister_sysctl_table(ns->sysctls);
76*dbec2846SEric W. Biederman 	retire_sysctl_set(&ns->set);
77*dbec2846SEric W. Biederman 	kfree(tbl);
78*dbec2846SEric W. Biederman #endif
79*dbec2846SEric W. Biederman }
80*dbec2846SEric W. Biederman 
81*dbec2846SEric W. Biederman static __init int user_namespace_sysctl_init(void)
82*dbec2846SEric W. Biederman {
83*dbec2846SEric W. Biederman #ifdef CONFIG_SYSCTL
84*dbec2846SEric W. Biederman 	static struct ctl_table_header *userns_header;
85*dbec2846SEric W. Biederman 	static struct ctl_table empty[1];
86*dbec2846SEric W. Biederman 	/*
87*dbec2846SEric W. Biederman 	 * It is necessary to register the userns directory in the
88*dbec2846SEric W. Biederman 	 * default set so that registrations in the child sets work
89*dbec2846SEric W. Biederman 	 * properly.
90*dbec2846SEric W. Biederman 	 */
91*dbec2846SEric W. Biederman 	userns_header = register_sysctl("userns", empty);
92*dbec2846SEric W. Biederman 	BUG_ON(!userns_header);
93*dbec2846SEric W. Biederman 	BUG_ON(!setup_userns_sysctls(&init_user_ns));
94*dbec2846SEric W. Biederman #endif
95*dbec2846SEric W. Biederman 	return 0;
96*dbec2846SEric W. Biederman }
97*dbec2846SEric W. Biederman subsys_initcall(user_namespace_sysctl_init);
98*dbec2846SEric W. Biederman 
99*dbec2846SEric W. Biederman 
100