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