Merge tag 'gfs2-for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux...
[linux-2.6-microblaze.git] / kernel / bpf / net_namespace.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <linux/bpf.h>
4 #include <linux/filter.h>
5 #include <net/net_namespace.h>
6
7 /*
8  * Functions to manage BPF programs attached to netns
9  */
10
11 struct bpf_netns_link {
12         struct bpf_link link;
13         enum bpf_attach_type type;
14         enum netns_bpf_attach_type netns_type;
15
16         /* We don't hold a ref to net in order to auto-detach the link
17          * when netns is going away. Instead we rely on pernet
18          * pre_exit callback to clear this pointer. Must be accessed
19          * with netns_bpf_mutex held.
20          */
21         struct net *net;
22 };
23
24 /* Protects updates to netns_bpf */
25 DEFINE_MUTEX(netns_bpf_mutex);
26
27 /* Must be called with netns_bpf_mutex held. */
28 static void __net_exit bpf_netns_link_auto_detach(struct bpf_link *link)
29 {
30         struct bpf_netns_link *net_link =
31                 container_of(link, struct bpf_netns_link, link);
32
33         net_link->net = NULL;
34 }
35
36 static void bpf_netns_link_release(struct bpf_link *link)
37 {
38         struct bpf_netns_link *net_link =
39                 container_of(link, struct bpf_netns_link, link);
40         enum netns_bpf_attach_type type = net_link->netns_type;
41         struct net *net;
42
43         /* Link auto-detached by dying netns. */
44         if (!net_link->net)
45                 return;
46
47         mutex_lock(&netns_bpf_mutex);
48
49         /* Recheck after potential sleep. We can race with cleanup_net
50          * here, but if we see a non-NULL struct net pointer pre_exit
51          * has not happened yet and will block on netns_bpf_mutex.
52          */
53         net = net_link->net;
54         if (!net)
55                 goto out_unlock;
56
57         net->bpf.links[type] = NULL;
58         RCU_INIT_POINTER(net->bpf.progs[type], NULL);
59
60 out_unlock:
61         mutex_unlock(&netns_bpf_mutex);
62 }
63
64 static void bpf_netns_link_dealloc(struct bpf_link *link)
65 {
66         struct bpf_netns_link *net_link =
67                 container_of(link, struct bpf_netns_link, link);
68
69         kfree(net_link);
70 }
71
72 static int bpf_netns_link_update_prog(struct bpf_link *link,
73                                       struct bpf_prog *new_prog,
74                                       struct bpf_prog *old_prog)
75 {
76         struct bpf_netns_link *net_link =
77                 container_of(link, struct bpf_netns_link, link);
78         enum netns_bpf_attach_type type = net_link->netns_type;
79         struct net *net;
80         int ret = 0;
81
82         if (old_prog && old_prog != link->prog)
83                 return -EPERM;
84         if (new_prog->type != link->prog->type)
85                 return -EINVAL;
86
87         mutex_lock(&netns_bpf_mutex);
88
89         net = net_link->net;
90         if (!net || !check_net(net)) {
91                 /* Link auto-detached or netns dying */
92                 ret = -ENOLINK;
93                 goto out_unlock;
94         }
95
96         old_prog = xchg(&link->prog, new_prog);
97         rcu_assign_pointer(net->bpf.progs[type], new_prog);
98         bpf_prog_put(old_prog);
99
100 out_unlock:
101         mutex_unlock(&netns_bpf_mutex);
102         return ret;
103 }
104
105 static int bpf_netns_link_fill_info(const struct bpf_link *link,
106                                     struct bpf_link_info *info)
107 {
108         const struct bpf_netns_link *net_link =
109                 container_of(link, struct bpf_netns_link, link);
110         unsigned int inum = 0;
111         struct net *net;
112
113         mutex_lock(&netns_bpf_mutex);
114         net = net_link->net;
115         if (net && check_net(net))
116                 inum = net->ns.inum;
117         mutex_unlock(&netns_bpf_mutex);
118
119         info->netns.netns_ino = inum;
120         info->netns.attach_type = net_link->type;
121         return 0;
122 }
123
124 static void bpf_netns_link_show_fdinfo(const struct bpf_link *link,
125                                        struct seq_file *seq)
126 {
127         struct bpf_link_info info = {};
128
129         bpf_netns_link_fill_info(link, &info);
130         seq_printf(seq,
131                    "netns_ino:\t%u\n"
132                    "attach_type:\t%u\n",
133                    info.netns.netns_ino,
134                    info.netns.attach_type);
135 }
136
137 static const struct bpf_link_ops bpf_netns_link_ops = {
138         .release = bpf_netns_link_release,
139         .dealloc = bpf_netns_link_dealloc,
140         .update_prog = bpf_netns_link_update_prog,
141         .fill_link_info = bpf_netns_link_fill_info,
142         .show_fdinfo = bpf_netns_link_show_fdinfo,
143 };
144
145 int netns_bpf_prog_query(const union bpf_attr *attr,
146                          union bpf_attr __user *uattr)
147 {
148         __u32 __user *prog_ids = u64_to_user_ptr(attr->query.prog_ids);
149         u32 prog_id, prog_cnt = 0, flags = 0;
150         enum netns_bpf_attach_type type;
151         struct bpf_prog *attached;
152         struct net *net;
153
154         if (attr->query.query_flags)
155                 return -EINVAL;
156
157         type = to_netns_bpf_attach_type(attr->query.attach_type);
158         if (type < 0)
159                 return -EINVAL;
160
161         net = get_net_ns_by_fd(attr->query.target_fd);
162         if (IS_ERR(net))
163                 return PTR_ERR(net);
164
165         rcu_read_lock();
166         attached = rcu_dereference(net->bpf.progs[type]);
167         if (attached) {
168                 prog_cnt = 1;
169                 prog_id = attached->aux->id;
170         }
171         rcu_read_unlock();
172
173         put_net(net);
174
175         if (copy_to_user(&uattr->query.attach_flags, &flags, sizeof(flags)))
176                 return -EFAULT;
177         if (copy_to_user(&uattr->query.prog_cnt, &prog_cnt, sizeof(prog_cnt)))
178                 return -EFAULT;
179
180         if (!attr->query.prog_cnt || !prog_ids || !prog_cnt)
181                 return 0;
182
183         if (copy_to_user(prog_ids, &prog_id, sizeof(u32)))
184                 return -EFAULT;
185
186         return 0;
187 }
188
189 int netns_bpf_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog)
190 {
191         enum netns_bpf_attach_type type;
192         struct net *net;
193         int ret;
194
195         type = to_netns_bpf_attach_type(attr->attach_type);
196         if (type < 0)
197                 return -EINVAL;
198
199         net = current->nsproxy->net_ns;
200         mutex_lock(&netns_bpf_mutex);
201
202         /* Attaching prog directly is not compatible with links */
203         if (net->bpf.links[type]) {
204                 ret = -EEXIST;
205                 goto out_unlock;
206         }
207
208         switch (type) {
209         case NETNS_BPF_FLOW_DISSECTOR:
210                 ret = flow_dissector_bpf_prog_attach(net, prog);
211                 break;
212         default:
213                 ret = -EINVAL;
214                 break;
215         }
216 out_unlock:
217         mutex_unlock(&netns_bpf_mutex);
218
219         return ret;
220 }
221
222 /* Must be called with netns_bpf_mutex held. */
223 static int __netns_bpf_prog_detach(struct net *net,
224                                    enum netns_bpf_attach_type type)
225 {
226         struct bpf_prog *attached;
227
228         /* Progs attached via links cannot be detached */
229         if (net->bpf.links[type])
230                 return -EINVAL;
231
232         attached = rcu_dereference_protected(net->bpf.progs[type],
233                                              lockdep_is_held(&netns_bpf_mutex));
234         if (!attached)
235                 return -ENOENT;
236         RCU_INIT_POINTER(net->bpf.progs[type], NULL);
237         bpf_prog_put(attached);
238         return 0;
239 }
240
241 int netns_bpf_prog_detach(const union bpf_attr *attr)
242 {
243         enum netns_bpf_attach_type type;
244         int ret;
245
246         type = to_netns_bpf_attach_type(attr->attach_type);
247         if (type < 0)
248                 return -EINVAL;
249
250         mutex_lock(&netns_bpf_mutex);
251         ret = __netns_bpf_prog_detach(current->nsproxy->net_ns, type);
252         mutex_unlock(&netns_bpf_mutex);
253
254         return ret;
255 }
256
257 static int netns_bpf_link_attach(struct net *net, struct bpf_link *link,
258                                  enum netns_bpf_attach_type type)
259 {
260         struct bpf_prog *prog;
261         int err;
262
263         mutex_lock(&netns_bpf_mutex);
264
265         /* Allow attaching only one prog or link for now */
266         if (net->bpf.links[type]) {
267                 err = -E2BIG;
268                 goto out_unlock;
269         }
270         /* Links are not compatible with attaching prog directly */
271         prog = rcu_dereference_protected(net->bpf.progs[type],
272                                          lockdep_is_held(&netns_bpf_mutex));
273         if (prog) {
274                 err = -EEXIST;
275                 goto out_unlock;
276         }
277
278         switch (type) {
279         case NETNS_BPF_FLOW_DISSECTOR:
280                 err = flow_dissector_bpf_prog_attach(net, link->prog);
281                 break;
282         default:
283                 err = -EINVAL;
284                 break;
285         }
286         if (err)
287                 goto out_unlock;
288
289         net->bpf.links[type] = link;
290
291 out_unlock:
292         mutex_unlock(&netns_bpf_mutex);
293         return err;
294 }
295
296 int netns_bpf_link_create(const union bpf_attr *attr, struct bpf_prog *prog)
297 {
298         enum netns_bpf_attach_type netns_type;
299         struct bpf_link_primer link_primer;
300         struct bpf_netns_link *net_link;
301         enum bpf_attach_type type;
302         struct net *net;
303         int err;
304
305         if (attr->link_create.flags)
306                 return -EINVAL;
307
308         type = attr->link_create.attach_type;
309         netns_type = to_netns_bpf_attach_type(type);
310         if (netns_type < 0)
311                 return -EINVAL;
312
313         net = get_net_ns_by_fd(attr->link_create.target_fd);
314         if (IS_ERR(net))
315                 return PTR_ERR(net);
316
317         net_link = kzalloc(sizeof(*net_link), GFP_USER);
318         if (!net_link) {
319                 err = -ENOMEM;
320                 goto out_put_net;
321         }
322         bpf_link_init(&net_link->link, BPF_LINK_TYPE_NETNS,
323                       &bpf_netns_link_ops, prog);
324         net_link->net = net;
325         net_link->type = type;
326         net_link->netns_type = netns_type;
327
328         err = bpf_link_prime(&net_link->link, &link_primer);
329         if (err) {
330                 kfree(net_link);
331                 goto out_put_net;
332         }
333
334         err = netns_bpf_link_attach(net, &net_link->link, netns_type);
335         if (err) {
336                 bpf_link_cleanup(&link_primer);
337                 goto out_put_net;
338         }
339
340         put_net(net);
341         return bpf_link_settle(&link_primer);
342
343 out_put_net:
344         put_net(net);
345         return err;
346 }
347
348 static void __net_exit netns_bpf_pernet_pre_exit(struct net *net)
349 {
350         enum netns_bpf_attach_type type;
351         struct bpf_link *link;
352
353         mutex_lock(&netns_bpf_mutex);
354         for (type = 0; type < MAX_NETNS_BPF_ATTACH_TYPE; type++) {
355                 link = net->bpf.links[type];
356                 if (link)
357                         bpf_netns_link_auto_detach(link);
358                 else
359                         __netns_bpf_prog_detach(net, type);
360         }
361         mutex_unlock(&netns_bpf_mutex);
362 }
363
364 static struct pernet_operations netns_bpf_pernet_ops __net_initdata = {
365         .pre_exit = netns_bpf_pernet_pre_exit,
366 };
367
368 static int __init netns_bpf_init(void)
369 {
370         return register_pernet_subsys(&netns_bpf_pernet_ops);
371 }
372
373 subsys_initcall(netns_bpf_init);