blob: 6394d9c5956e374f7ab3603e48a6de94e5408d75 [file] [log] [blame]
Alexei Starovoitov99c55f72014-09-26 00:16:57 -07001/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * General Public License for more details.
11 */
12#include <linux/bpf.h>
13#include <linux/syscalls.h>
14#include <linux/slab.h>
Daniel Borkmann251d00b2017-01-18 15:14:17 +010015#include <linux/vmalloc.h>
16#include <linux/mmzone.h>
Alexei Starovoitov99c55f72014-09-26 00:16:57 -070017#include <linux/anon_inodes.h>
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -070018#include <linux/file.h>
Alexei Starovoitov09756af2014-09-26 00:17:00 -070019#include <linux/license.h>
20#include <linux/filter.h>
Alexei Starovoitov25415172015-03-25 12:49:20 -070021#include <linux/version.h>
Alexei Starovoitov99c55f72014-09-26 00:16:57 -070022
Chenbo Feng4672ded2017-10-18 13:00:22 -070023#define BPF_OBJ_FLAG_MASK (BPF_F_RDONLY | BPF_F_WRONLY)
24
Alexei Starovoitovb121d1e2016-03-07 21:57:13 -080025DEFINE_PER_CPU(int, bpf_prog_active);
26
Alexei Starovoitov1be7f752015-10-07 22:23:21 -070027int sysctl_unprivileged_bpf_disabled __read_mostly;
28
Alexei Starovoitov99c55f72014-09-26 00:16:57 -070029static LIST_HEAD(bpf_map_types);
30
31static struct bpf_map *find_and_alloc_map(union bpf_attr *attr)
32{
33 struct bpf_map_type_list *tl;
34 struct bpf_map *map;
35
36 list_for_each_entry(tl, &bpf_map_types, list_node) {
37 if (tl->type == attr->map_type) {
38 map = tl->ops->map_alloc(attr);
39 if (IS_ERR(map))
40 return map;
41 map->ops = tl->ops;
42 map->map_type = attr->map_type;
43 return map;
44 }
45 }
46 return ERR_PTR(-EINVAL);
47}
48
49/* boot time registration of different map implementations */
50void bpf_register_map_type(struct bpf_map_type_list *tl)
51{
52 list_add(&tl->list_node, &bpf_map_types);
53}
54
Daniel Borkmann251d00b2017-01-18 15:14:17 +010055void *bpf_map_area_alloc(size_t size)
56{
57 /* We definitely need __GFP_NORETRY, so OOM killer doesn't
58 * trigger under memory pressure as we really just want to
59 * fail instead.
60 */
61 const gfp_t flags = __GFP_NOWARN | __GFP_NORETRY | __GFP_ZERO;
62 void *area;
63
64 if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
65 area = kmalloc(size, GFP_USER | flags);
66 if (area != NULL)
67 return area;
68 }
69
70 return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | flags,
71 PAGE_KERNEL);
72}
73
74void bpf_map_area_free(void *area)
75{
76 kvfree(area);
77}
78
Alexei Starovoitov6c905982016-03-07 21:57:15 -080079int bpf_map_precharge_memlock(u32 pages)
80{
81 struct user_struct *user = get_current_user();
82 unsigned long memlock_limit, cur;
83
84 memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
85 cur = atomic_long_read(&user->locked_vm);
86 free_uid(user);
87 if (cur + pages > memlock_limit)
88 return -EPERM;
89 return 0;
90}
91
Alexei Starovoitovaaac3ba2015-10-07 22:23:22 -070092static int bpf_map_charge_memlock(struct bpf_map *map)
93{
94 struct user_struct *user = get_current_user();
95 unsigned long memlock_limit;
96
97 memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
98
99 atomic_long_add(map->pages, &user->locked_vm);
100
101 if (atomic_long_read(&user->locked_vm) > memlock_limit) {
102 atomic_long_sub(map->pages, &user->locked_vm);
103 free_uid(user);
104 return -EPERM;
105 }
106 map->user = user;
107 return 0;
108}
109
110static void bpf_map_uncharge_memlock(struct bpf_map *map)
111{
112 struct user_struct *user = map->user;
113
114 atomic_long_sub(map->pages, &user->locked_vm);
115 free_uid(user);
116}
117
Alexei Starovoitov99c55f72014-09-26 00:16:57 -0700118/* called from workqueue */
119static void bpf_map_free_deferred(struct work_struct *work)
120{
121 struct bpf_map *map = container_of(work, struct bpf_map, work);
122
Alexei Starovoitovaaac3ba2015-10-07 22:23:22 -0700123 bpf_map_uncharge_memlock(map);
Alexei Starovoitov99c55f72014-09-26 00:16:57 -0700124 /* implementation dependent freeing */
125 map->ops->map_free(map);
126}
127
Daniel Borkmannc9da1612015-11-24 21:28:15 +0100128static void bpf_map_put_uref(struct bpf_map *map)
129{
130 if (atomic_dec_and_test(&map->usercnt)) {
131 if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY)
132 bpf_fd_array_map_clear(map);
133 }
134}
135
Alexei Starovoitov99c55f72014-09-26 00:16:57 -0700136/* decrement map refcnt and schedule it for freeing via workqueue
137 * (unrelying map implementation ops->map_free() might sleep)
138 */
139void bpf_map_put(struct bpf_map *map)
140{
141 if (atomic_dec_and_test(&map->refcnt)) {
142 INIT_WORK(&map->work, bpf_map_free_deferred);
143 schedule_work(&map->work);
144 }
145}
146
Daniel Borkmannc9da1612015-11-24 21:28:15 +0100147void bpf_map_put_with_uref(struct bpf_map *map)
148{
149 bpf_map_put_uref(map);
150 bpf_map_put(map);
151}
152
Alexei Starovoitov99c55f72014-09-26 00:16:57 -0700153static int bpf_map_release(struct inode *inode, struct file *filp)
154{
Daniel Borkmann61d1b6a2016-06-15 22:47:12 +0200155 struct bpf_map *map = filp->private_data;
156
157 if (map->ops->map_release)
158 map->ops->map_release(map, filp);
159
160 bpf_map_put_with_uref(map);
Alexei Starovoitov99c55f72014-09-26 00:16:57 -0700161 return 0;
162}
163
Daniel Borkmannf99bf202015-11-19 11:56:22 +0100164#ifdef CONFIG_PROC_FS
165static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)
166{
167 const struct bpf_map *map = filp->private_data;
168
169 seq_printf(m,
170 "map_type:\t%u\n"
171 "key_size:\t%u\n"
172 "value_size:\t%u\n"
Daniel Borkmann322cea22016-03-25 00:30:25 +0100173 "max_entries:\t%u\n"
174 "map_flags:\t%#x\n",
Daniel Borkmannf99bf202015-11-19 11:56:22 +0100175 map->map_type,
176 map->key_size,
177 map->value_size,
Daniel Borkmann322cea22016-03-25 00:30:25 +0100178 map->max_entries,
179 map->map_flags);
Daniel Borkmannf99bf202015-11-19 11:56:22 +0100180}
181#endif
182
Chenbo Feng4672ded2017-10-18 13:00:22 -0700183static ssize_t bpf_dummy_read(struct file *filp, char __user *buf, size_t siz,
184 loff_t *ppos)
185{
186 /* We need this handler such that alloc_file() enables
187 * f_mode with FMODE_CAN_READ.
188 */
189 return -EINVAL;
190}
191
192static ssize_t bpf_dummy_write(struct file *filp, const char __user *buf,
193 size_t siz, loff_t *ppos)
194{
195 /* We need this handler such that alloc_file() enables
196 * f_mode with FMODE_CAN_WRITE.
197 */
198 return -EINVAL;
199}
200
Alexei Starovoitov99c55f72014-09-26 00:16:57 -0700201static const struct file_operations bpf_map_fops = {
Daniel Borkmannf99bf202015-11-19 11:56:22 +0100202#ifdef CONFIG_PROC_FS
203 .show_fdinfo = bpf_map_show_fdinfo,
204#endif
205 .release = bpf_map_release,
Chenbo Feng4672ded2017-10-18 13:00:22 -0700206 .read = bpf_dummy_read,
207 .write = bpf_dummy_write,
Alexei Starovoitov99c55f72014-09-26 00:16:57 -0700208};
209
Chenbo Feng4672ded2017-10-18 13:00:22 -0700210int bpf_map_new_fd(struct bpf_map *map, int flags)
Daniel Borkmannaa797812015-10-29 14:58:06 +0100211{
212 return anon_inode_getfd("bpf-map", &bpf_map_fops, map,
Chenbo Feng4672ded2017-10-18 13:00:22 -0700213 flags | O_CLOEXEC);
214}
215
216int bpf_get_file_flag(int flags)
217{
218 if ((flags & BPF_F_RDONLY) && (flags & BPF_F_WRONLY))
219 return -EINVAL;
220 if (flags & BPF_F_RDONLY)
221 return O_RDONLY;
222 if (flags & BPF_F_WRONLY)
223 return O_WRONLY;
224 return O_RDWR;
Daniel Borkmannaa797812015-10-29 14:58:06 +0100225}
226
Alexei Starovoitov99c55f72014-09-26 00:16:57 -0700227/* helper macro to check that unused fields 'union bpf_attr' are zero */
228#define CHECK_ATTR(CMD) \
229 memchr_inv((void *) &attr->CMD##_LAST_FIELD + \
230 sizeof(attr->CMD##_LAST_FIELD), 0, \
231 sizeof(*attr) - \
232 offsetof(union bpf_attr, CMD##_LAST_FIELD) - \
233 sizeof(attr->CMD##_LAST_FIELD)) != NULL
234
Alexei Starovoitov6c905982016-03-07 21:57:15 -0800235#define BPF_MAP_CREATE_LAST_FIELD map_flags
Alexei Starovoitov99c55f72014-09-26 00:16:57 -0700236/* called via syscall */
237static int map_create(union bpf_attr *attr)
238{
239 struct bpf_map *map;
Chenbo Feng4672ded2017-10-18 13:00:22 -0700240 int f_flags;
Alexei Starovoitov99c55f72014-09-26 00:16:57 -0700241 int err;
242
243 err = CHECK_ATTR(BPF_MAP_CREATE);
244 if (err)
245 return -EINVAL;
246
Chenbo Feng4672ded2017-10-18 13:00:22 -0700247 f_flags = bpf_get_file_flag(attr->map_flags);
248 if (f_flags < 0)
249 return f_flags;
250
Alexei Starovoitov99c55f72014-09-26 00:16:57 -0700251 /* find map type and init map: hashtable vs rbtree vs bloom vs ... */
252 map = find_and_alloc_map(attr);
253 if (IS_ERR(map))
254 return PTR_ERR(map);
255
256 atomic_set(&map->refcnt, 1);
Daniel Borkmannc9da1612015-11-24 21:28:15 +0100257 atomic_set(&map->usercnt, 1);
Alexei Starovoitov99c55f72014-09-26 00:16:57 -0700258
Alexei Starovoitovaaac3ba2015-10-07 22:23:22 -0700259 err = bpf_map_charge_memlock(map);
260 if (err)
Daniel Borkmann20b2b242016-11-04 00:56:31 +0100261 goto free_map_nouncharge;
Alexei Starovoitovaaac3ba2015-10-07 22:23:22 -0700262
Chenbo Feng4672ded2017-10-18 13:00:22 -0700263 err = bpf_map_new_fd(map, f_flags);
Alexei Starovoitov99c55f72014-09-26 00:16:57 -0700264 if (err < 0)
265 /* failed to allocate fd */
266 goto free_map;
267
268 return err;
269
270free_map:
Daniel Borkmann20b2b242016-11-04 00:56:31 +0100271 bpf_map_uncharge_memlock(map);
272free_map_nouncharge:
Alexei Starovoitov99c55f72014-09-26 00:16:57 -0700273 map->ops->map_free(map);
274 return err;
275}
276
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700277/* if error is returned, fd is released.
278 * On success caller should complete fd access with matching fdput()
279 */
Daniel Borkmannc2101292015-10-29 14:58:07 +0100280struct bpf_map *__bpf_map_get(struct fd f)
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700281{
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700282 if (!f.file)
283 return ERR_PTR(-EBADF);
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700284 if (f.file->f_op != &bpf_map_fops) {
285 fdput(f);
286 return ERR_PTR(-EINVAL);
287 }
288
Daniel Borkmannc2101292015-10-29 14:58:07 +0100289 return f.file->private_data;
290}
291
Alexei Starovoitov92117d82016-04-27 18:56:20 -0700292/* prog's and map's refcnt limit */
293#define BPF_MAX_REFCNT 32768
294
295struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref)
Daniel Borkmannc9da1612015-11-24 21:28:15 +0100296{
Alexei Starovoitov92117d82016-04-27 18:56:20 -0700297 if (atomic_inc_return(&map->refcnt) > BPF_MAX_REFCNT) {
298 atomic_dec(&map->refcnt);
299 return ERR_PTR(-EBUSY);
300 }
Daniel Borkmannc9da1612015-11-24 21:28:15 +0100301 if (uref)
302 atomic_inc(&map->usercnt);
Alexei Starovoitov92117d82016-04-27 18:56:20 -0700303 return map;
Daniel Borkmannc9da1612015-11-24 21:28:15 +0100304}
305
306struct bpf_map *bpf_map_get_with_uref(u32 ufd)
Daniel Borkmannc2101292015-10-29 14:58:07 +0100307{
308 struct fd f = fdget(ufd);
309 struct bpf_map *map;
310
311 map = __bpf_map_get(f);
312 if (IS_ERR(map))
313 return map;
314
Alexei Starovoitov92117d82016-04-27 18:56:20 -0700315 map = bpf_map_inc(map, true);
Daniel Borkmannc2101292015-10-29 14:58:07 +0100316 fdput(f);
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700317
318 return map;
319}
320
321/* helper to convert user pointers passed inside __aligned_u64 fields */
322static void __user *u64_to_ptr(__u64 val)
323{
324 return (void __user *) (unsigned long) val;
325}
326
Alexei Starovoitovb8cdc052016-03-09 18:56:49 -0800327int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
328{
329 return -ENOTSUPP;
330}
331
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700332/* last field in 'union bpf_attr' used by this command */
333#define BPF_MAP_LOOKUP_ELEM_LAST_FIELD value
334
335static int map_lookup_elem(union bpf_attr *attr)
336{
337 void __user *ukey = u64_to_ptr(attr->key);
338 void __user *uvalue = u64_to_ptr(attr->value);
339 int ufd = attr->map_fd;
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700340 struct bpf_map *map;
Alexei Starovoitov8ebe6672015-01-22 17:11:08 -0800341 void *key, *value, *ptr;
Alexei Starovoitov15a07b32016-02-01 22:39:55 -0800342 u32 value_size;
Daniel Borkmann592867b2015-09-08 18:00:09 +0200343 struct fd f;
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700344 int err;
345
346 if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
347 return -EINVAL;
348
Daniel Borkmann592867b2015-09-08 18:00:09 +0200349 f = fdget(ufd);
Daniel Borkmannc2101292015-10-29 14:58:07 +0100350 map = __bpf_map_get(f);
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700351 if (IS_ERR(map))
352 return PTR_ERR(map);
353
Chenbo Feng4672ded2017-10-18 13:00:22 -0700354 if (!(f.file->f_mode & FMODE_CAN_READ)) {
355 err = -EPERM;
356 goto err_put;
357 }
358
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700359 err = -ENOMEM;
360 key = kmalloc(map->key_size, GFP_USER);
361 if (!key)
362 goto err_put;
363
364 err = -EFAULT;
365 if (copy_from_user(key, ukey, map->key_size) != 0)
366 goto free_key;
367
Alexei Starovoitov15a07b32016-02-01 22:39:55 -0800368 if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
369 map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
370 value_size = round_up(map->value_size, 8) * num_possible_cpus();
371 else
372 value_size = map->value_size;
373
Alexei Starovoitov8ebe6672015-01-22 17:11:08 -0800374 err = -ENOMEM;
Alexei Starovoitov15a07b32016-02-01 22:39:55 -0800375 value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700376 if (!value)
Alexei Starovoitov8ebe6672015-01-22 17:11:08 -0800377 goto free_key;
378
Alexei Starovoitov15a07b32016-02-01 22:39:55 -0800379 if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH) {
380 err = bpf_percpu_hash_copy(map, key, value);
381 } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
382 err = bpf_percpu_array_copy(map, key, value);
Alexei Starovoitov557c0c62016-03-07 21:57:17 -0800383 } else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) {
384 err = bpf_stackmap_copy(map, key, value);
Alexei Starovoitov15a07b32016-02-01 22:39:55 -0800385 } else {
386 rcu_read_lock();
387 ptr = map->ops->map_lookup_elem(map, key);
388 if (ptr)
389 memcpy(value, ptr, value_size);
390 rcu_read_unlock();
391 err = ptr ? 0 : -ENOENT;
392 }
Alexei Starovoitov8ebe6672015-01-22 17:11:08 -0800393
Alexei Starovoitov15a07b32016-02-01 22:39:55 -0800394 if (err)
Alexei Starovoitov8ebe6672015-01-22 17:11:08 -0800395 goto free_value;
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700396
397 err = -EFAULT;
Alexei Starovoitov15a07b32016-02-01 22:39:55 -0800398 if (copy_to_user(uvalue, value, value_size) != 0)
Alexei Starovoitov8ebe6672015-01-22 17:11:08 -0800399 goto free_value;
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700400
401 err = 0;
402
Alexei Starovoitov8ebe6672015-01-22 17:11:08 -0800403free_value:
404 kfree(value);
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700405free_key:
406 kfree(key);
407err_put:
408 fdput(f);
409 return err;
410}
411
Alexei Starovoitov3274f522014-11-13 17:36:44 -0800412#define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700413
414static int map_update_elem(union bpf_attr *attr)
415{
416 void __user *ukey = u64_to_ptr(attr->key);
417 void __user *uvalue = u64_to_ptr(attr->value);
418 int ufd = attr->map_fd;
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700419 struct bpf_map *map;
420 void *key, *value;
Alexei Starovoitov15a07b32016-02-01 22:39:55 -0800421 u32 value_size;
Daniel Borkmann592867b2015-09-08 18:00:09 +0200422 struct fd f;
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700423 int err;
424
425 if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM))
426 return -EINVAL;
427
Daniel Borkmann592867b2015-09-08 18:00:09 +0200428 f = fdget(ufd);
Daniel Borkmannc2101292015-10-29 14:58:07 +0100429 map = __bpf_map_get(f);
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700430 if (IS_ERR(map))
431 return PTR_ERR(map);
432
Chenbo Feng4672ded2017-10-18 13:00:22 -0700433 if (!(f.file->f_mode & FMODE_CAN_WRITE)) {
434 err = -EPERM;
435 goto err_put;
436 }
437
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700438 err = -ENOMEM;
439 key = kmalloc(map->key_size, GFP_USER);
440 if (!key)
441 goto err_put;
442
443 err = -EFAULT;
444 if (copy_from_user(key, ukey, map->key_size) != 0)
445 goto free_key;
446
Alexei Starovoitov15a07b32016-02-01 22:39:55 -0800447 if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
448 map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
449 value_size = round_up(map->value_size, 8) * num_possible_cpus();
450 else
451 value_size = map->value_size;
452
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700453 err = -ENOMEM;
Alexei Starovoitov15a07b32016-02-01 22:39:55 -0800454 value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700455 if (!value)
456 goto free_key;
457
458 err = -EFAULT;
Alexei Starovoitov15a07b32016-02-01 22:39:55 -0800459 if (copy_from_user(value, uvalue, value_size) != 0)
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700460 goto free_value;
461
Alexei Starovoitovb121d1e2016-03-07 21:57:13 -0800462 /* must increment bpf_prog_active to avoid kprobe+bpf triggering from
463 * inside bpf map update or delete otherwise deadlocks are possible
464 */
465 preempt_disable();
466 __this_cpu_inc(bpf_prog_active);
Alexei Starovoitov15a07b32016-02-01 22:39:55 -0800467 if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH) {
468 err = bpf_percpu_hash_update(map, key, value, attr->flags);
469 } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
470 err = bpf_percpu_array_update(map, key, value, attr->flags);
Daniel Borkmannd056a782016-06-15 22:47:13 +0200471 } else if (map->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY ||
Martin KaFai Lau4ed8ec52016-06-30 10:28:43 -0700472 map->map_type == BPF_MAP_TYPE_PROG_ARRAY ||
473 map->map_type == BPF_MAP_TYPE_CGROUP_ARRAY) {
Daniel Borkmannd056a782016-06-15 22:47:13 +0200474 rcu_read_lock();
475 err = bpf_fd_array_map_update_elem(map, f.file, key, value,
476 attr->flags);
477 rcu_read_unlock();
Alexei Starovoitov15a07b32016-02-01 22:39:55 -0800478 } else {
479 rcu_read_lock();
480 err = map->ops->map_update_elem(map, key, value, attr->flags);
481 rcu_read_unlock();
482 }
Alexei Starovoitovb121d1e2016-03-07 21:57:13 -0800483 __this_cpu_dec(bpf_prog_active);
484 preempt_enable();
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700485
486free_value:
487 kfree(value);
488free_key:
489 kfree(key);
490err_put:
491 fdput(f);
492 return err;
493}
494
495#define BPF_MAP_DELETE_ELEM_LAST_FIELD key
496
497static int map_delete_elem(union bpf_attr *attr)
498{
499 void __user *ukey = u64_to_ptr(attr->key);
500 int ufd = attr->map_fd;
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700501 struct bpf_map *map;
Daniel Borkmann592867b2015-09-08 18:00:09 +0200502 struct fd f;
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700503 void *key;
504 int err;
505
506 if (CHECK_ATTR(BPF_MAP_DELETE_ELEM))
507 return -EINVAL;
508
Daniel Borkmann592867b2015-09-08 18:00:09 +0200509 f = fdget(ufd);
Daniel Borkmannc2101292015-10-29 14:58:07 +0100510 map = __bpf_map_get(f);
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700511 if (IS_ERR(map))
512 return PTR_ERR(map);
513
Chenbo Feng4672ded2017-10-18 13:00:22 -0700514 if (!(f.file->f_mode & FMODE_CAN_WRITE)) {
515 err = -EPERM;
516 goto err_put;
517 }
518
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700519 err = -ENOMEM;
520 key = kmalloc(map->key_size, GFP_USER);
521 if (!key)
522 goto err_put;
523
524 err = -EFAULT;
525 if (copy_from_user(key, ukey, map->key_size) != 0)
526 goto free_key;
527
Alexei Starovoitovb121d1e2016-03-07 21:57:13 -0800528 preempt_disable();
529 __this_cpu_inc(bpf_prog_active);
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700530 rcu_read_lock();
531 err = map->ops->map_delete_elem(map, key);
532 rcu_read_unlock();
Alexei Starovoitovb121d1e2016-03-07 21:57:13 -0800533 __this_cpu_dec(bpf_prog_active);
534 preempt_enable();
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700535
536free_key:
537 kfree(key);
538err_put:
539 fdput(f);
540 return err;
541}
542
543/* last field in 'union bpf_attr' used by this command */
544#define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key
545
546static int map_get_next_key(union bpf_attr *attr)
547{
548 void __user *ukey = u64_to_ptr(attr->key);
549 void __user *unext_key = u64_to_ptr(attr->next_key);
550 int ufd = attr->map_fd;
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700551 struct bpf_map *map;
552 void *key, *next_key;
Daniel Borkmann592867b2015-09-08 18:00:09 +0200553 struct fd f;
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700554 int err;
555
556 if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY))
557 return -EINVAL;
558
Daniel Borkmann592867b2015-09-08 18:00:09 +0200559 f = fdget(ufd);
Daniel Borkmannc2101292015-10-29 14:58:07 +0100560 map = __bpf_map_get(f);
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700561 if (IS_ERR(map))
562 return PTR_ERR(map);
563
Chenbo Feng4672ded2017-10-18 13:00:22 -0700564 if (!(f.file->f_mode & FMODE_CAN_READ)) {
565 err = -EPERM;
566 goto err_put;
567 }
568
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -0700569 err = -ENOMEM;
570 key = kmalloc(map->key_size, GFP_USER);
571 if (!key)
572 goto err_put;
573
574 err = -EFAULT;
575 if (copy_from_user(key, ukey, map->key_size) != 0)
576 goto free_key;
577
578 err = -ENOMEM;
579 next_key = kmalloc(map->key_size, GFP_USER);
580 if (!next_key)
581 goto free_key;
582
583 rcu_read_lock();
584 err = map->ops->map_get_next_key(map, key, next_key);
585 rcu_read_unlock();
586 if (err)
587 goto free_next_key;
588
589 err = -EFAULT;
590 if (copy_to_user(unext_key, next_key, map->key_size) != 0)
591 goto free_next_key;
592
593 err = 0;
594
595free_next_key:
596 kfree(next_key);
597free_key:
598 kfree(key);
599err_put:
600 fdput(f);
601 return err;
602}
603
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700604static LIST_HEAD(bpf_prog_types);
605
606static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
607{
608 struct bpf_prog_type_list *tl;
609
610 list_for_each_entry(tl, &bpf_prog_types, list_node) {
611 if (tl->type == type) {
612 prog->aux->ops = tl->ops;
Daniel Borkmann24701ec2015-03-01 12:31:47 +0100613 prog->type = type;
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700614 return 0;
615 }
616 }
Daniel Borkmann24701ec2015-03-01 12:31:47 +0100617
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700618 return -EINVAL;
619}
620
621void bpf_register_prog_type(struct bpf_prog_type_list *tl)
622{
623 list_add(&tl->list_node, &bpf_prog_types);
624}
625
Alexei Starovoitov0a542a82014-09-26 00:17:01 -0700626/* fixup insn->imm field of bpf_call instructions:
627 * if (insn->imm == BPF_FUNC_map_lookup_elem)
628 * insn->imm = bpf_map_lookup_elem - __bpf_call_base;
629 * else if (insn->imm == BPF_FUNC_map_update_elem)
630 * insn->imm = bpf_map_update_elem - __bpf_call_base;
631 * else ...
632 *
633 * this function is called after eBPF program passed verification
634 */
635static void fixup_bpf_calls(struct bpf_prog *prog)
636{
637 const struct bpf_func_proto *fn;
638 int i;
639
640 for (i = 0; i < prog->len; i++) {
641 struct bpf_insn *insn = &prog->insnsi[i];
642
643 if (insn->code == (BPF_JMP | BPF_CALL)) {
644 /* we reach here when program has bpf_call instructions
645 * and it passed bpf_check(), means that
646 * ops->get_func_proto must have been supplied, check it
647 */
648 BUG_ON(!prog->aux->ops->get_func_proto);
649
Daniel Borkmannc46646d2015-09-30 01:41:51 +0200650 if (insn->imm == BPF_FUNC_get_route_realm)
651 prog->dst_needed = 1;
Daniel Borkmann3ad00402015-10-08 01:20:39 +0200652 if (insn->imm == BPF_FUNC_get_prandom_u32)
653 bpf_user_rnd_init_once();
Alexei Starovoitov04fd61a2015-05-19 16:59:03 -0700654 if (insn->imm == BPF_FUNC_tail_call) {
655 /* mark bpf_tail_call as different opcode
656 * to avoid conditional branch in
657 * interpeter for every normal call
658 * and to prevent accidental JITing by
659 * JIT compiler that doesn't support
660 * bpf_tail_call yet
661 */
662 insn->imm = 0;
663 insn->code |= BPF_X;
664 continue;
665 }
666
Alexei Starovoitov0a542a82014-09-26 00:17:01 -0700667 fn = prog->aux->ops->get_func_proto(insn->imm);
668 /* all functions that have prototype and verifier allowed
669 * programs to call them, must be real in-kernel functions
670 */
671 BUG_ON(!fn->func);
672 insn->imm = fn->func - __bpf_call_base;
673 }
674 }
675}
676
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700677/* drop refcnt on maps used by eBPF program and free auxilary data */
678static void free_used_maps(struct bpf_prog_aux *aux)
679{
680 int i;
681
682 for (i = 0; i < aux->used_map_cnt; i++)
683 bpf_map_put(aux->used_maps[i]);
684
685 kfree(aux->used_maps);
686}
687
Alexei Starovoitovaaac3ba2015-10-07 22:23:22 -0700688static int bpf_prog_charge_memlock(struct bpf_prog *prog)
689{
690 struct user_struct *user = get_current_user();
691 unsigned long memlock_limit;
692
693 memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
694
695 atomic_long_add(prog->pages, &user->locked_vm);
696 if (atomic_long_read(&user->locked_vm) > memlock_limit) {
697 atomic_long_sub(prog->pages, &user->locked_vm);
698 free_uid(user);
699 return -EPERM;
700 }
701 prog->aux->user = user;
702 return 0;
703}
704
705static void bpf_prog_uncharge_memlock(struct bpf_prog *prog)
706{
707 struct user_struct *user = prog->aux->user;
708
709 atomic_long_sub(prog->pages, &user->locked_vm);
710 free_uid(user);
711}
712
Daniel Borkmann1aacde32016-06-30 17:24:43 +0200713static void __bpf_prog_put_rcu(struct rcu_head *rcu)
Alexei Starovoitovabf2e7d2015-05-28 19:26:02 -0700714{
715 struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
716
717 free_used_maps(aux);
Alexei Starovoitovaaac3ba2015-10-07 22:23:22 -0700718 bpf_prog_uncharge_memlock(aux->prog);
Alexei Starovoitovabf2e7d2015-05-28 19:26:02 -0700719 bpf_prog_free(aux->prog);
720}
721
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700722void bpf_prog_put(struct bpf_prog *prog)
723{
Daniel Borkmanne9d8afa2015-10-29 14:58:08 +0100724 if (atomic_dec_and_test(&prog->aux->refcnt))
Daniel Borkmann1aacde32016-06-30 17:24:43 +0200725 call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700726}
Daniel Borkmanne2e9b652015-03-01 12:31:48 +0100727EXPORT_SYMBOL_GPL(bpf_prog_put);
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700728
729static int bpf_prog_release(struct inode *inode, struct file *filp)
730{
731 struct bpf_prog *prog = filp->private_data;
732
Daniel Borkmann1aacde32016-06-30 17:24:43 +0200733 bpf_prog_put(prog);
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700734 return 0;
735}
736
737static const struct file_operations bpf_prog_fops = {
738 .release = bpf_prog_release,
Chenbo Feng4672ded2017-10-18 13:00:22 -0700739 .read = bpf_dummy_read,
740 .write = bpf_dummy_write,
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700741};
742
Daniel Borkmannb2197752015-10-29 14:58:09 +0100743int bpf_prog_new_fd(struct bpf_prog *prog)
Daniel Borkmannaa797812015-10-29 14:58:06 +0100744{
745 return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog,
746 O_RDWR | O_CLOEXEC);
747}
748
Daniel Borkmann113214b2016-06-30 17:24:44 +0200749static struct bpf_prog *____bpf_prog_get(struct fd f)
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700750{
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700751 if (!f.file)
752 return ERR_PTR(-EBADF);
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700753 if (f.file->f_op != &bpf_prog_fops) {
754 fdput(f);
755 return ERR_PTR(-EINVAL);
756 }
757
Daniel Borkmannc2101292015-10-29 14:58:07 +0100758 return f.file->private_data;
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700759}
760
Brenden Blanco59d36562016-07-19 12:16:46 -0700761struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i)
Alexei Starovoitov92117d82016-04-27 18:56:20 -0700762{
Brenden Blanco59d36562016-07-19 12:16:46 -0700763 if (atomic_add_return(i, &prog->aux->refcnt) > BPF_MAX_REFCNT) {
764 atomic_sub(i, &prog->aux->refcnt);
Alexei Starovoitov92117d82016-04-27 18:56:20 -0700765 return ERR_PTR(-EBUSY);
766 }
767 return prog;
768}
Brenden Blanco59d36562016-07-19 12:16:46 -0700769EXPORT_SYMBOL_GPL(bpf_prog_add);
770
771struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog)
772{
773 return bpf_prog_add(prog, 1);
774}
Alexei Starovoitov92117d82016-04-27 18:56:20 -0700775
Daniel Borkmann113214b2016-06-30 17:24:44 +0200776static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *type)
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700777{
778 struct fd f = fdget(ufd);
779 struct bpf_prog *prog;
780
Daniel Borkmann113214b2016-06-30 17:24:44 +0200781 prog = ____bpf_prog_get(f);
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700782 if (IS_ERR(prog))
783 return prog;
Daniel Borkmann113214b2016-06-30 17:24:44 +0200784 if (type && prog->type != *type) {
785 prog = ERR_PTR(-EINVAL);
786 goto out;
787 }
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700788
Alexei Starovoitov92117d82016-04-27 18:56:20 -0700789 prog = bpf_prog_inc(prog);
Daniel Borkmann113214b2016-06-30 17:24:44 +0200790out:
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700791 fdput(f);
792 return prog;
793}
Daniel Borkmann113214b2016-06-30 17:24:44 +0200794
795struct bpf_prog *bpf_prog_get(u32 ufd)
796{
797 return __bpf_prog_get(ufd, NULL);
798}
799
800struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type)
801{
802 return __bpf_prog_get(ufd, &type);
803}
804EXPORT_SYMBOL_GPL(bpf_prog_get_type);
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700805
806/* last field in 'union bpf_attr' used by this command */
Alexei Starovoitov25415172015-03-25 12:49:20 -0700807#define BPF_PROG_LOAD_LAST_FIELD kern_version
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700808
809static int bpf_prog_load(union bpf_attr *attr)
810{
811 enum bpf_prog_type type = attr->prog_type;
812 struct bpf_prog *prog;
813 int err;
814 char license[128];
815 bool is_gpl;
816
817 if (CHECK_ATTR(BPF_PROG_LOAD))
818 return -EINVAL;
819
820 /* copy eBPF program license from user space */
821 if (strncpy_from_user(license, u64_to_ptr(attr->license),
822 sizeof(license) - 1) < 0)
823 return -EFAULT;
824 license[sizeof(license) - 1] = 0;
825
826 /* eBPF programs must be GPL compatible to use GPL-ed functions */
827 is_gpl = license_is_gpl_compatible(license);
828
829 if (attr->insn_cnt >= BPF_MAXINSNS)
830 return -EINVAL;
831
Alexei Starovoitov25415172015-03-25 12:49:20 -0700832 if (type == BPF_PROG_TYPE_KPROBE &&
833 attr->kern_version != LINUX_VERSION_CODE)
834 return -EINVAL;
835
Chenbo Fengb9aad972017-06-02 17:24:31 -0700836 if (type != BPF_PROG_TYPE_SOCKET_FILTER &&
837 type != BPF_PROG_TYPE_CGROUP_SKB &&
838 !capable(CAP_SYS_ADMIN))
Alexei Starovoitov1be7f752015-10-07 22:23:21 -0700839 return -EPERM;
840
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700841 /* plain bpf_prog allocation */
842 prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
843 if (!prog)
844 return -ENOMEM;
845
Alexei Starovoitovaaac3ba2015-10-07 22:23:22 -0700846 err = bpf_prog_charge_memlock(prog);
847 if (err)
848 goto free_prog_nouncharge;
849
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700850 prog->len = attr->insn_cnt;
851
852 err = -EFAULT;
853 if (copy_from_user(prog->insns, u64_to_ptr(attr->insns),
854 prog->len * sizeof(struct bpf_insn)) != 0)
855 goto free_prog;
856
857 prog->orig_prog = NULL;
Daniel Borkmanna91263d2015-09-30 01:41:50 +0200858 prog->jited = 0;
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700859
860 atomic_set(&prog->aux->refcnt, 1);
Daniel Borkmanna91263d2015-09-30 01:41:50 +0200861 prog->gpl_compatible = is_gpl ? 1 : 0;
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700862
863 /* find program type: socket_filter vs tracing_filter */
864 err = find_prog_type(type, prog);
865 if (err < 0)
866 goto free_prog;
867
868 /* run eBPF verifier */
Alexei Starovoitov9bac3d62015-03-13 11:57:42 -0700869 err = bpf_check(&prog, attr);
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700870 if (err < 0)
871 goto free_used_maps;
872
Alexei Starovoitov0a542a82014-09-26 00:17:01 -0700873 /* fixup BPF_CALL->imm field */
874 fixup_bpf_calls(prog);
875
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700876 /* eBPF program is ready to be JITed */
Daniel Borkmannd1c55ab2016-05-13 19:08:31 +0200877 prog = bpf_prog_select_runtime(prog, &err);
Alexei Starovoitov04fd61a2015-05-19 16:59:03 -0700878 if (err < 0)
879 goto free_used_maps;
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700880
Daniel Borkmannaa797812015-10-29 14:58:06 +0100881 err = bpf_prog_new_fd(prog);
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700882 if (err < 0)
883 /* failed to allocate fd */
884 goto free_used_maps;
885
886 return err;
887
888free_used_maps:
889 free_used_maps(prog->aux);
890free_prog:
Alexei Starovoitovaaac3ba2015-10-07 22:23:22 -0700891 bpf_prog_uncharge_memlock(prog);
892free_prog_nouncharge:
Alexei Starovoitov09756af2014-09-26 00:17:00 -0700893 bpf_prog_free(prog);
894 return err;
895}
896
Chenbo Feng4672ded2017-10-18 13:00:22 -0700897#define BPF_OBJ_LAST_FIELD file_flags
Daniel Borkmannb2197752015-10-29 14:58:09 +0100898
899static int bpf_obj_pin(const union bpf_attr *attr)
900{
Chenbo Feng4672ded2017-10-18 13:00:22 -0700901 if (CHECK_ATTR(BPF_OBJ) || attr->file_flags != 0)
Daniel Borkmannb2197752015-10-29 14:58:09 +0100902 return -EINVAL;
903
904 return bpf_obj_pin_user(attr->bpf_fd, u64_to_ptr(attr->pathname));
905}
906
907static int bpf_obj_get(const union bpf_attr *attr)
908{
Chenbo Feng4672ded2017-10-18 13:00:22 -0700909 if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0 ||
910 attr->file_flags & ~BPF_OBJ_FLAG_MASK)
Daniel Borkmannb2197752015-10-29 14:58:09 +0100911 return -EINVAL;
912
Chenbo Feng4672ded2017-10-18 13:00:22 -0700913 return bpf_obj_get_user(u64_to_ptr(attr->pathname),
914 attr->file_flags);
Daniel Borkmannb2197752015-10-29 14:58:09 +0100915}
916
Daniel Mack00615df2016-11-23 16:52:27 +0100917#ifdef CONFIG_CGROUP_BPF
918
Alexei Starovoitov1ee2b4b2017-02-10 20:28:24 -0800919#define BPF_PROG_ATTACH_LAST_FIELD attach_flags
Daniel Mack00615df2016-11-23 16:52:27 +0100920
921static int bpf_prog_attach(const union bpf_attr *attr)
922{
923 struct bpf_prog *prog;
924 struct cgroup *cgrp;
Alexei Starovoitov1ee2b4b2017-02-10 20:28:24 -0800925 int ret;
Daniel Mack00615df2016-11-23 16:52:27 +0100926
927 if (!capable(CAP_NET_ADMIN))
928 return -EPERM;
929
930 if (CHECK_ATTR(BPF_PROG_ATTACH))
931 return -EINVAL;
932
Alexei Starovoitov1ee2b4b2017-02-10 20:28:24 -0800933 if (attr->attach_flags & ~BPF_F_ALLOW_OVERRIDE)
934 return -EINVAL;
935
Daniel Mack00615df2016-11-23 16:52:27 +0100936 switch (attr->attach_type) {
937 case BPF_CGROUP_INET_INGRESS:
938 case BPF_CGROUP_INET_EGRESS:
939 prog = bpf_prog_get_type(attr->attach_bpf_fd,
940 BPF_PROG_TYPE_CGROUP_SKB);
941 if (IS_ERR(prog))
942 return PTR_ERR(prog);
943
944 cgrp = cgroup_get_from_fd(attr->target_fd);
945 if (IS_ERR(cgrp)) {
946 bpf_prog_put(prog);
947 return PTR_ERR(cgrp);
948 }
949
Alexei Starovoitov1ee2b4b2017-02-10 20:28:24 -0800950 ret = cgroup_bpf_update(cgrp, prog, attr->attach_type,
951 attr->attach_flags & BPF_F_ALLOW_OVERRIDE);
952 if (ret)
953 bpf_prog_put(prog);
Daniel Mack00615df2016-11-23 16:52:27 +0100954 cgroup_put(cgrp);
955 break;
956
957 default:
958 return -EINVAL;
959 }
960
Alexei Starovoitov1ee2b4b2017-02-10 20:28:24 -0800961 return ret;
Daniel Mack00615df2016-11-23 16:52:27 +0100962}
963
964#define BPF_PROG_DETACH_LAST_FIELD attach_type
965
966static int bpf_prog_detach(const union bpf_attr *attr)
967{
968 struct cgroup *cgrp;
Alexei Starovoitov1ee2b4b2017-02-10 20:28:24 -0800969 int ret;
Daniel Mack00615df2016-11-23 16:52:27 +0100970
971 if (!capable(CAP_NET_ADMIN))
972 return -EPERM;
973
974 if (CHECK_ATTR(BPF_PROG_DETACH))
975 return -EINVAL;
976
977 switch (attr->attach_type) {
978 case BPF_CGROUP_INET_INGRESS:
979 case BPF_CGROUP_INET_EGRESS:
980 cgrp = cgroup_get_from_fd(attr->target_fd);
981 if (IS_ERR(cgrp))
982 return PTR_ERR(cgrp);
983
Alexei Starovoitov1ee2b4b2017-02-10 20:28:24 -0800984 ret = cgroup_bpf_update(cgrp, NULL, attr->attach_type, false);
Daniel Mack00615df2016-11-23 16:52:27 +0100985 cgroup_put(cgrp);
986 break;
987
988 default:
989 return -EINVAL;
990 }
991
Alexei Starovoitov1ee2b4b2017-02-10 20:28:24 -0800992 return ret;
Daniel Mack00615df2016-11-23 16:52:27 +0100993}
994#endif /* CONFIG_CGROUP_BPF */
995
Alexei Starovoitov99c55f72014-09-26 00:16:57 -0700996SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
997{
998 union bpf_attr attr = {};
999 int err;
1000
Alexei Starovoitov1be7f752015-10-07 22:23:21 -07001001 if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled)
Alexei Starovoitov99c55f72014-09-26 00:16:57 -07001002 return -EPERM;
1003
1004 if (!access_ok(VERIFY_READ, uattr, 1))
1005 return -EFAULT;
1006
1007 if (size > PAGE_SIZE) /* silly large */
1008 return -E2BIG;
1009
1010 /* If we're handed a bigger struct than we know of,
1011 * ensure all the unknown bits are 0 - i.e. new
1012 * user-space does not rely on any kernel feature
1013 * extensions we dont know about yet.
1014 */
1015 if (size > sizeof(attr)) {
1016 unsigned char __user *addr;
1017 unsigned char __user *end;
1018 unsigned char val;
1019
1020 addr = (void __user *)uattr + sizeof(attr);
1021 end = (void __user *)uattr + size;
1022
1023 for (; addr < end; addr++) {
1024 err = get_user(val, addr);
1025 if (err)
1026 return err;
1027 if (val)
1028 return -E2BIG;
1029 }
1030 size = sizeof(attr);
1031 }
1032
1033 /* copy attributes from user space, may be less than sizeof(bpf_attr) */
1034 if (copy_from_user(&attr, uattr, size) != 0)
1035 return -EFAULT;
1036
1037 switch (cmd) {
1038 case BPF_MAP_CREATE:
1039 err = map_create(&attr);
1040 break;
Alexei Starovoitovdb20fd22014-09-26 00:16:59 -07001041 case BPF_MAP_LOOKUP_ELEM:
1042 err = map_lookup_elem(&attr);
1043 break;
1044 case BPF_MAP_UPDATE_ELEM:
1045 err = map_update_elem(&attr);
1046 break;
1047 case BPF_MAP_DELETE_ELEM:
1048 err = map_delete_elem(&attr);
1049 break;
1050 case BPF_MAP_GET_NEXT_KEY:
1051 err = map_get_next_key(&attr);
1052 break;
Alexei Starovoitov09756af2014-09-26 00:17:00 -07001053 case BPF_PROG_LOAD:
1054 err = bpf_prog_load(&attr);
1055 break;
Daniel Borkmannb2197752015-10-29 14:58:09 +01001056 case BPF_OBJ_PIN:
1057 err = bpf_obj_pin(&attr);
1058 break;
1059 case BPF_OBJ_GET:
1060 err = bpf_obj_get(&attr);
1061 break;
Daniel Mack00615df2016-11-23 16:52:27 +01001062
1063#ifdef CONFIG_CGROUP_BPF
1064 case BPF_PROG_ATTACH:
1065 err = bpf_prog_attach(&attr);
1066 break;
1067 case BPF_PROG_DETACH:
1068 err = bpf_prog_detach(&attr);
1069 break;
1070#endif
1071
Alexei Starovoitov99c55f72014-09-26 00:16:57 -07001072 default:
1073 err = -EINVAL;
1074 break;
1075 }
1076
1077 return err;
1078}