xref: /linux/kernel/bpf/syscall.c (revision 557c0c6e7df8e14a46bd7560d193fa5bbc00a858)
199c55f7dSAlexei Starovoitov /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
299c55f7dSAlexei Starovoitov  *
399c55f7dSAlexei Starovoitov  * This program is free software; you can redistribute it and/or
499c55f7dSAlexei Starovoitov  * modify it under the terms of version 2 of the GNU General Public
599c55f7dSAlexei Starovoitov  * License as published by the Free Software Foundation.
699c55f7dSAlexei Starovoitov  *
799c55f7dSAlexei Starovoitov  * This program is distributed in the hope that it will be useful, but
899c55f7dSAlexei Starovoitov  * WITHOUT ANY WARRANTY; without even the implied warranty of
999c55f7dSAlexei Starovoitov  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1099c55f7dSAlexei Starovoitov  * General Public License for more details.
1199c55f7dSAlexei Starovoitov  */
1299c55f7dSAlexei Starovoitov #include <linux/bpf.h>
1399c55f7dSAlexei Starovoitov #include <linux/syscalls.h>
1499c55f7dSAlexei Starovoitov #include <linux/slab.h>
1599c55f7dSAlexei Starovoitov #include <linux/anon_inodes.h>
16db20fd2bSAlexei Starovoitov #include <linux/file.h>
1709756af4SAlexei Starovoitov #include <linux/license.h>
1809756af4SAlexei Starovoitov #include <linux/filter.h>
192541517cSAlexei Starovoitov #include <linux/version.h>
2099c55f7dSAlexei Starovoitov 
21b121d1e7SAlexei Starovoitov DEFINE_PER_CPU(int, bpf_prog_active);
22b121d1e7SAlexei Starovoitov 
231be7f75dSAlexei Starovoitov int sysctl_unprivileged_bpf_disabled __read_mostly;
241be7f75dSAlexei Starovoitov 
2599c55f7dSAlexei Starovoitov static LIST_HEAD(bpf_map_types);
2699c55f7dSAlexei Starovoitov 
2799c55f7dSAlexei Starovoitov static struct bpf_map *find_and_alloc_map(union bpf_attr *attr)
2899c55f7dSAlexei Starovoitov {
2999c55f7dSAlexei Starovoitov 	struct bpf_map_type_list *tl;
3099c55f7dSAlexei Starovoitov 	struct bpf_map *map;
3199c55f7dSAlexei Starovoitov 
3299c55f7dSAlexei Starovoitov 	list_for_each_entry(tl, &bpf_map_types, list_node) {
3399c55f7dSAlexei Starovoitov 		if (tl->type == attr->map_type) {
3499c55f7dSAlexei Starovoitov 			map = tl->ops->map_alloc(attr);
3599c55f7dSAlexei Starovoitov 			if (IS_ERR(map))
3699c55f7dSAlexei Starovoitov 				return map;
3799c55f7dSAlexei Starovoitov 			map->ops = tl->ops;
3899c55f7dSAlexei Starovoitov 			map->map_type = attr->map_type;
3999c55f7dSAlexei Starovoitov 			return map;
4099c55f7dSAlexei Starovoitov 		}
4199c55f7dSAlexei Starovoitov 	}
4299c55f7dSAlexei Starovoitov 	return ERR_PTR(-EINVAL);
4399c55f7dSAlexei Starovoitov }
4499c55f7dSAlexei Starovoitov 
4599c55f7dSAlexei Starovoitov /* boot time registration of different map implementations */
4699c55f7dSAlexei Starovoitov void bpf_register_map_type(struct bpf_map_type_list *tl)
4799c55f7dSAlexei Starovoitov {
4899c55f7dSAlexei Starovoitov 	list_add(&tl->list_node, &bpf_map_types);
4999c55f7dSAlexei Starovoitov }
5099c55f7dSAlexei Starovoitov 
516c905981SAlexei Starovoitov int bpf_map_precharge_memlock(u32 pages)
526c905981SAlexei Starovoitov {
536c905981SAlexei Starovoitov 	struct user_struct *user = get_current_user();
546c905981SAlexei Starovoitov 	unsigned long memlock_limit, cur;
556c905981SAlexei Starovoitov 
566c905981SAlexei Starovoitov 	memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
576c905981SAlexei Starovoitov 	cur = atomic_long_read(&user->locked_vm);
586c905981SAlexei Starovoitov 	free_uid(user);
596c905981SAlexei Starovoitov 	if (cur + pages > memlock_limit)
606c905981SAlexei Starovoitov 		return -EPERM;
616c905981SAlexei Starovoitov 	return 0;
626c905981SAlexei Starovoitov }
636c905981SAlexei Starovoitov 
64aaac3ba9SAlexei Starovoitov static int bpf_map_charge_memlock(struct bpf_map *map)
65aaac3ba9SAlexei Starovoitov {
66aaac3ba9SAlexei Starovoitov 	struct user_struct *user = get_current_user();
67aaac3ba9SAlexei Starovoitov 	unsigned long memlock_limit;
68aaac3ba9SAlexei Starovoitov 
69aaac3ba9SAlexei Starovoitov 	memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
70aaac3ba9SAlexei Starovoitov 
71aaac3ba9SAlexei Starovoitov 	atomic_long_add(map->pages, &user->locked_vm);
72aaac3ba9SAlexei Starovoitov 
73aaac3ba9SAlexei Starovoitov 	if (atomic_long_read(&user->locked_vm) > memlock_limit) {
74aaac3ba9SAlexei Starovoitov 		atomic_long_sub(map->pages, &user->locked_vm);
75aaac3ba9SAlexei Starovoitov 		free_uid(user);
76aaac3ba9SAlexei Starovoitov 		return -EPERM;
77aaac3ba9SAlexei Starovoitov 	}
78aaac3ba9SAlexei Starovoitov 	map->user = user;
79aaac3ba9SAlexei Starovoitov 	return 0;
80aaac3ba9SAlexei Starovoitov }
81aaac3ba9SAlexei Starovoitov 
82aaac3ba9SAlexei Starovoitov static void bpf_map_uncharge_memlock(struct bpf_map *map)
83aaac3ba9SAlexei Starovoitov {
84aaac3ba9SAlexei Starovoitov 	struct user_struct *user = map->user;
85aaac3ba9SAlexei Starovoitov 
86aaac3ba9SAlexei Starovoitov 	atomic_long_sub(map->pages, &user->locked_vm);
87aaac3ba9SAlexei Starovoitov 	free_uid(user);
88aaac3ba9SAlexei Starovoitov }
89aaac3ba9SAlexei Starovoitov 
9099c55f7dSAlexei Starovoitov /* called from workqueue */
9199c55f7dSAlexei Starovoitov static void bpf_map_free_deferred(struct work_struct *work)
9299c55f7dSAlexei Starovoitov {
9399c55f7dSAlexei Starovoitov 	struct bpf_map *map = container_of(work, struct bpf_map, work);
9499c55f7dSAlexei Starovoitov 
95aaac3ba9SAlexei Starovoitov 	bpf_map_uncharge_memlock(map);
9699c55f7dSAlexei Starovoitov 	/* implementation dependent freeing */
9799c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
9899c55f7dSAlexei Starovoitov }
9999c55f7dSAlexei Starovoitov 
100c9da161cSDaniel Borkmann static void bpf_map_put_uref(struct bpf_map *map)
101c9da161cSDaniel Borkmann {
102c9da161cSDaniel Borkmann 	if (atomic_dec_and_test(&map->usercnt)) {
103c9da161cSDaniel Borkmann 		if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY)
104c9da161cSDaniel Borkmann 			bpf_fd_array_map_clear(map);
105c9da161cSDaniel Borkmann 	}
106c9da161cSDaniel Borkmann }
107c9da161cSDaniel Borkmann 
10899c55f7dSAlexei Starovoitov /* decrement map refcnt and schedule it for freeing via workqueue
10999c55f7dSAlexei Starovoitov  * (unrelying map implementation ops->map_free() might sleep)
11099c55f7dSAlexei Starovoitov  */
11199c55f7dSAlexei Starovoitov void bpf_map_put(struct bpf_map *map)
11299c55f7dSAlexei Starovoitov {
11399c55f7dSAlexei Starovoitov 	if (atomic_dec_and_test(&map->refcnt)) {
11499c55f7dSAlexei Starovoitov 		INIT_WORK(&map->work, bpf_map_free_deferred);
11599c55f7dSAlexei Starovoitov 		schedule_work(&map->work);
11699c55f7dSAlexei Starovoitov 	}
11799c55f7dSAlexei Starovoitov }
11899c55f7dSAlexei Starovoitov 
119c9da161cSDaniel Borkmann void bpf_map_put_with_uref(struct bpf_map *map)
120c9da161cSDaniel Borkmann {
121c9da161cSDaniel Borkmann 	bpf_map_put_uref(map);
122c9da161cSDaniel Borkmann 	bpf_map_put(map);
123c9da161cSDaniel Borkmann }
124c9da161cSDaniel Borkmann 
12599c55f7dSAlexei Starovoitov static int bpf_map_release(struct inode *inode, struct file *filp)
12699c55f7dSAlexei Starovoitov {
127c9da161cSDaniel Borkmann 	bpf_map_put_with_uref(filp->private_data);
12899c55f7dSAlexei Starovoitov 	return 0;
12999c55f7dSAlexei Starovoitov }
13099c55f7dSAlexei Starovoitov 
131f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
132f99bf205SDaniel Borkmann static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)
133f99bf205SDaniel Borkmann {
134f99bf205SDaniel Borkmann 	const struct bpf_map *map = filp->private_data;
135f99bf205SDaniel Borkmann 
136f99bf205SDaniel Borkmann 	seq_printf(m,
137f99bf205SDaniel Borkmann 		   "map_type:\t%u\n"
138f99bf205SDaniel Borkmann 		   "key_size:\t%u\n"
139f99bf205SDaniel Borkmann 		   "value_size:\t%u\n"
140f99bf205SDaniel Borkmann 		   "max_entries:\t%u\n",
141f99bf205SDaniel Borkmann 		   map->map_type,
142f99bf205SDaniel Borkmann 		   map->key_size,
143f99bf205SDaniel Borkmann 		   map->value_size,
144f99bf205SDaniel Borkmann 		   map->max_entries);
145f99bf205SDaniel Borkmann }
146f99bf205SDaniel Borkmann #endif
147f99bf205SDaniel Borkmann 
14899c55f7dSAlexei Starovoitov static const struct file_operations bpf_map_fops = {
149f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
150f99bf205SDaniel Borkmann 	.show_fdinfo	= bpf_map_show_fdinfo,
151f99bf205SDaniel Borkmann #endif
15299c55f7dSAlexei Starovoitov 	.release	= bpf_map_release,
15399c55f7dSAlexei Starovoitov };
15499c55f7dSAlexei Starovoitov 
155b2197755SDaniel Borkmann int bpf_map_new_fd(struct bpf_map *map)
156aa79781bSDaniel Borkmann {
157aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-map", &bpf_map_fops, map,
158aa79781bSDaniel Borkmann 				O_RDWR | O_CLOEXEC);
159aa79781bSDaniel Borkmann }
160aa79781bSDaniel Borkmann 
16199c55f7dSAlexei Starovoitov /* helper macro to check that unused fields 'union bpf_attr' are zero */
16299c55f7dSAlexei Starovoitov #define CHECK_ATTR(CMD) \
16399c55f7dSAlexei Starovoitov 	memchr_inv((void *) &attr->CMD##_LAST_FIELD + \
16499c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD), 0, \
16599c55f7dSAlexei Starovoitov 		   sizeof(*attr) - \
16699c55f7dSAlexei Starovoitov 		   offsetof(union bpf_attr, CMD##_LAST_FIELD) - \
16799c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD)) != NULL
16899c55f7dSAlexei Starovoitov 
1696c905981SAlexei Starovoitov #define BPF_MAP_CREATE_LAST_FIELD map_flags
17099c55f7dSAlexei Starovoitov /* called via syscall */
17199c55f7dSAlexei Starovoitov static int map_create(union bpf_attr *attr)
17299c55f7dSAlexei Starovoitov {
17399c55f7dSAlexei Starovoitov 	struct bpf_map *map;
17499c55f7dSAlexei Starovoitov 	int err;
17599c55f7dSAlexei Starovoitov 
17699c55f7dSAlexei Starovoitov 	err = CHECK_ATTR(BPF_MAP_CREATE);
17799c55f7dSAlexei Starovoitov 	if (err)
17899c55f7dSAlexei Starovoitov 		return -EINVAL;
17999c55f7dSAlexei Starovoitov 
18099c55f7dSAlexei Starovoitov 	/* find map type and init map: hashtable vs rbtree vs bloom vs ... */
18199c55f7dSAlexei Starovoitov 	map = find_and_alloc_map(attr);
18299c55f7dSAlexei Starovoitov 	if (IS_ERR(map))
18399c55f7dSAlexei Starovoitov 		return PTR_ERR(map);
18499c55f7dSAlexei Starovoitov 
18599c55f7dSAlexei Starovoitov 	atomic_set(&map->refcnt, 1);
186c9da161cSDaniel Borkmann 	atomic_set(&map->usercnt, 1);
18799c55f7dSAlexei Starovoitov 
188aaac3ba9SAlexei Starovoitov 	err = bpf_map_charge_memlock(map);
189aaac3ba9SAlexei Starovoitov 	if (err)
190aaac3ba9SAlexei Starovoitov 		goto free_map;
191aaac3ba9SAlexei Starovoitov 
192aa79781bSDaniel Borkmann 	err = bpf_map_new_fd(map);
19399c55f7dSAlexei Starovoitov 	if (err < 0)
19499c55f7dSAlexei Starovoitov 		/* failed to allocate fd */
19599c55f7dSAlexei Starovoitov 		goto free_map;
19699c55f7dSAlexei Starovoitov 
19799c55f7dSAlexei Starovoitov 	return err;
19899c55f7dSAlexei Starovoitov 
19999c55f7dSAlexei Starovoitov free_map:
20099c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
20199c55f7dSAlexei Starovoitov 	return err;
20299c55f7dSAlexei Starovoitov }
20399c55f7dSAlexei Starovoitov 
204db20fd2bSAlexei Starovoitov /* if error is returned, fd is released.
205db20fd2bSAlexei Starovoitov  * On success caller should complete fd access with matching fdput()
206db20fd2bSAlexei Starovoitov  */
207c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f)
208db20fd2bSAlexei Starovoitov {
209db20fd2bSAlexei Starovoitov 	if (!f.file)
210db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EBADF);
211db20fd2bSAlexei Starovoitov 	if (f.file->f_op != &bpf_map_fops) {
212db20fd2bSAlexei Starovoitov 		fdput(f);
213db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EINVAL);
214db20fd2bSAlexei Starovoitov 	}
215db20fd2bSAlexei Starovoitov 
216c2101297SDaniel Borkmann 	return f.file->private_data;
217c2101297SDaniel Borkmann }
218c2101297SDaniel Borkmann 
219c9da161cSDaniel Borkmann void bpf_map_inc(struct bpf_map *map, bool uref)
220c9da161cSDaniel Borkmann {
221c9da161cSDaniel Borkmann 	atomic_inc(&map->refcnt);
222c9da161cSDaniel Borkmann 	if (uref)
223c9da161cSDaniel Borkmann 		atomic_inc(&map->usercnt);
224c9da161cSDaniel Borkmann }
225c9da161cSDaniel Borkmann 
226c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd)
227c2101297SDaniel Borkmann {
228c2101297SDaniel Borkmann 	struct fd f = fdget(ufd);
229c2101297SDaniel Borkmann 	struct bpf_map *map;
230c2101297SDaniel Borkmann 
231c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
232c2101297SDaniel Borkmann 	if (IS_ERR(map))
233c2101297SDaniel Borkmann 		return map;
234c2101297SDaniel Borkmann 
235c9da161cSDaniel Borkmann 	bpf_map_inc(map, true);
236c2101297SDaniel Borkmann 	fdput(f);
237db20fd2bSAlexei Starovoitov 
238db20fd2bSAlexei Starovoitov 	return map;
239db20fd2bSAlexei Starovoitov }
240db20fd2bSAlexei Starovoitov 
241db20fd2bSAlexei Starovoitov /* helper to convert user pointers passed inside __aligned_u64 fields */
242db20fd2bSAlexei Starovoitov static void __user *u64_to_ptr(__u64 val)
243db20fd2bSAlexei Starovoitov {
244db20fd2bSAlexei Starovoitov 	return (void __user *) (unsigned long) val;
245db20fd2bSAlexei Starovoitov }
246db20fd2bSAlexei Starovoitov 
247db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
248db20fd2bSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD value
249db20fd2bSAlexei Starovoitov 
250db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr)
251db20fd2bSAlexei Starovoitov {
252db20fd2bSAlexei Starovoitov 	void __user *ukey = u64_to_ptr(attr->key);
253db20fd2bSAlexei Starovoitov 	void __user *uvalue = u64_to_ptr(attr->value);
254db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
255db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
2568ebe667cSAlexei Starovoitov 	void *key, *value, *ptr;
25715a07b33SAlexei Starovoitov 	u32 value_size;
258592867bfSDaniel Borkmann 	struct fd f;
259db20fd2bSAlexei Starovoitov 	int err;
260db20fd2bSAlexei Starovoitov 
261db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
262db20fd2bSAlexei Starovoitov 		return -EINVAL;
263db20fd2bSAlexei Starovoitov 
264592867bfSDaniel Borkmann 	f = fdget(ufd);
265c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
266db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
267db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
268db20fd2bSAlexei Starovoitov 
269db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
270db20fd2bSAlexei Starovoitov 	key = kmalloc(map->key_size, GFP_USER);
271db20fd2bSAlexei Starovoitov 	if (!key)
272db20fd2bSAlexei Starovoitov 		goto err_put;
273db20fd2bSAlexei Starovoitov 
274db20fd2bSAlexei Starovoitov 	err = -EFAULT;
275db20fd2bSAlexei Starovoitov 	if (copy_from_user(key, ukey, map->key_size) != 0)
276db20fd2bSAlexei Starovoitov 		goto free_key;
277db20fd2bSAlexei Starovoitov 
27815a07b33SAlexei Starovoitov 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
27915a07b33SAlexei Starovoitov 	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
28015a07b33SAlexei Starovoitov 		value_size = round_up(map->value_size, 8) * num_possible_cpus();
28115a07b33SAlexei Starovoitov 	else
28215a07b33SAlexei Starovoitov 		value_size = map->value_size;
28315a07b33SAlexei Starovoitov 
2848ebe667cSAlexei Starovoitov 	err = -ENOMEM;
28515a07b33SAlexei Starovoitov 	value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
286db20fd2bSAlexei Starovoitov 	if (!value)
2878ebe667cSAlexei Starovoitov 		goto free_key;
2888ebe667cSAlexei Starovoitov 
28915a07b33SAlexei Starovoitov 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH) {
29015a07b33SAlexei Starovoitov 		err = bpf_percpu_hash_copy(map, key, value);
29115a07b33SAlexei Starovoitov 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
29215a07b33SAlexei Starovoitov 		err = bpf_percpu_array_copy(map, key, value);
293*557c0c6eSAlexei Starovoitov 	} else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) {
294*557c0c6eSAlexei Starovoitov 		err = bpf_stackmap_copy(map, key, value);
29515a07b33SAlexei Starovoitov 	} else {
2968ebe667cSAlexei Starovoitov 		rcu_read_lock();
2978ebe667cSAlexei Starovoitov 		ptr = map->ops->map_lookup_elem(map, key);
2988ebe667cSAlexei Starovoitov 		if (ptr)
29915a07b33SAlexei Starovoitov 			memcpy(value, ptr, value_size);
3008ebe667cSAlexei Starovoitov 		rcu_read_unlock();
30115a07b33SAlexei Starovoitov 		err = ptr ? 0 : -ENOENT;
30215a07b33SAlexei Starovoitov 	}
3038ebe667cSAlexei Starovoitov 
30415a07b33SAlexei Starovoitov 	if (err)
3058ebe667cSAlexei Starovoitov 		goto free_value;
306db20fd2bSAlexei Starovoitov 
307db20fd2bSAlexei Starovoitov 	err = -EFAULT;
30815a07b33SAlexei Starovoitov 	if (copy_to_user(uvalue, value, value_size) != 0)
3098ebe667cSAlexei Starovoitov 		goto free_value;
310db20fd2bSAlexei Starovoitov 
311db20fd2bSAlexei Starovoitov 	err = 0;
312db20fd2bSAlexei Starovoitov 
3138ebe667cSAlexei Starovoitov free_value:
3148ebe667cSAlexei Starovoitov 	kfree(value);
315db20fd2bSAlexei Starovoitov free_key:
316db20fd2bSAlexei Starovoitov 	kfree(key);
317db20fd2bSAlexei Starovoitov err_put:
318db20fd2bSAlexei Starovoitov 	fdput(f);
319db20fd2bSAlexei Starovoitov 	return err;
320db20fd2bSAlexei Starovoitov }
321db20fd2bSAlexei Starovoitov 
3223274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags
323db20fd2bSAlexei Starovoitov 
324db20fd2bSAlexei Starovoitov static int map_update_elem(union bpf_attr *attr)
325db20fd2bSAlexei Starovoitov {
326db20fd2bSAlexei Starovoitov 	void __user *ukey = u64_to_ptr(attr->key);
327db20fd2bSAlexei Starovoitov 	void __user *uvalue = u64_to_ptr(attr->value);
328db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
329db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
330db20fd2bSAlexei Starovoitov 	void *key, *value;
33115a07b33SAlexei Starovoitov 	u32 value_size;
332592867bfSDaniel Borkmann 	struct fd f;
333db20fd2bSAlexei Starovoitov 	int err;
334db20fd2bSAlexei Starovoitov 
335db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM))
336db20fd2bSAlexei Starovoitov 		return -EINVAL;
337db20fd2bSAlexei Starovoitov 
338592867bfSDaniel Borkmann 	f = fdget(ufd);
339c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
340db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
341db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
342db20fd2bSAlexei Starovoitov 
343db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
344db20fd2bSAlexei Starovoitov 	key = kmalloc(map->key_size, GFP_USER);
345db20fd2bSAlexei Starovoitov 	if (!key)
346db20fd2bSAlexei Starovoitov 		goto err_put;
347db20fd2bSAlexei Starovoitov 
348db20fd2bSAlexei Starovoitov 	err = -EFAULT;
349db20fd2bSAlexei Starovoitov 	if (copy_from_user(key, ukey, map->key_size) != 0)
350db20fd2bSAlexei Starovoitov 		goto free_key;
351db20fd2bSAlexei Starovoitov 
35215a07b33SAlexei Starovoitov 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
35315a07b33SAlexei Starovoitov 	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
35415a07b33SAlexei Starovoitov 		value_size = round_up(map->value_size, 8) * num_possible_cpus();
35515a07b33SAlexei Starovoitov 	else
35615a07b33SAlexei Starovoitov 		value_size = map->value_size;
35715a07b33SAlexei Starovoitov 
358db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
35915a07b33SAlexei Starovoitov 	value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
360db20fd2bSAlexei Starovoitov 	if (!value)
361db20fd2bSAlexei Starovoitov 		goto free_key;
362db20fd2bSAlexei Starovoitov 
363db20fd2bSAlexei Starovoitov 	err = -EFAULT;
36415a07b33SAlexei Starovoitov 	if (copy_from_user(value, uvalue, value_size) != 0)
365db20fd2bSAlexei Starovoitov 		goto free_value;
366db20fd2bSAlexei Starovoitov 
367b121d1e7SAlexei Starovoitov 	/* must increment bpf_prog_active to avoid kprobe+bpf triggering from
368b121d1e7SAlexei Starovoitov 	 * inside bpf map update or delete otherwise deadlocks are possible
369b121d1e7SAlexei Starovoitov 	 */
370b121d1e7SAlexei Starovoitov 	preempt_disable();
371b121d1e7SAlexei Starovoitov 	__this_cpu_inc(bpf_prog_active);
37215a07b33SAlexei Starovoitov 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH) {
37315a07b33SAlexei Starovoitov 		err = bpf_percpu_hash_update(map, key, value, attr->flags);
37415a07b33SAlexei Starovoitov 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
37515a07b33SAlexei Starovoitov 		err = bpf_percpu_array_update(map, key, value, attr->flags);
37615a07b33SAlexei Starovoitov 	} else {
377db20fd2bSAlexei Starovoitov 		rcu_read_lock();
3783274f520SAlexei Starovoitov 		err = map->ops->map_update_elem(map, key, value, attr->flags);
379db20fd2bSAlexei Starovoitov 		rcu_read_unlock();
38015a07b33SAlexei Starovoitov 	}
381b121d1e7SAlexei Starovoitov 	__this_cpu_dec(bpf_prog_active);
382b121d1e7SAlexei Starovoitov 	preempt_enable();
383db20fd2bSAlexei Starovoitov 
384db20fd2bSAlexei Starovoitov free_value:
385db20fd2bSAlexei Starovoitov 	kfree(value);
386db20fd2bSAlexei Starovoitov free_key:
387db20fd2bSAlexei Starovoitov 	kfree(key);
388db20fd2bSAlexei Starovoitov err_put:
389db20fd2bSAlexei Starovoitov 	fdput(f);
390db20fd2bSAlexei Starovoitov 	return err;
391db20fd2bSAlexei Starovoitov }
392db20fd2bSAlexei Starovoitov 
393db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key
394db20fd2bSAlexei Starovoitov 
395db20fd2bSAlexei Starovoitov static int map_delete_elem(union bpf_attr *attr)
396db20fd2bSAlexei Starovoitov {
397db20fd2bSAlexei Starovoitov 	void __user *ukey = u64_to_ptr(attr->key);
398db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
399db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
400592867bfSDaniel Borkmann 	struct fd f;
401db20fd2bSAlexei Starovoitov 	void *key;
402db20fd2bSAlexei Starovoitov 	int err;
403db20fd2bSAlexei Starovoitov 
404db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_DELETE_ELEM))
405db20fd2bSAlexei Starovoitov 		return -EINVAL;
406db20fd2bSAlexei Starovoitov 
407592867bfSDaniel Borkmann 	f = fdget(ufd);
408c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
409db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
410db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
411db20fd2bSAlexei Starovoitov 
412db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
413db20fd2bSAlexei Starovoitov 	key = kmalloc(map->key_size, GFP_USER);
414db20fd2bSAlexei Starovoitov 	if (!key)
415db20fd2bSAlexei Starovoitov 		goto err_put;
416db20fd2bSAlexei Starovoitov 
417db20fd2bSAlexei Starovoitov 	err = -EFAULT;
418db20fd2bSAlexei Starovoitov 	if (copy_from_user(key, ukey, map->key_size) != 0)
419db20fd2bSAlexei Starovoitov 		goto free_key;
420db20fd2bSAlexei Starovoitov 
421b121d1e7SAlexei Starovoitov 	preempt_disable();
422b121d1e7SAlexei Starovoitov 	__this_cpu_inc(bpf_prog_active);
423db20fd2bSAlexei Starovoitov 	rcu_read_lock();
424db20fd2bSAlexei Starovoitov 	err = map->ops->map_delete_elem(map, key);
425db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
426b121d1e7SAlexei Starovoitov 	__this_cpu_dec(bpf_prog_active);
427b121d1e7SAlexei Starovoitov 	preempt_enable();
428db20fd2bSAlexei Starovoitov 
429db20fd2bSAlexei Starovoitov free_key:
430db20fd2bSAlexei Starovoitov 	kfree(key);
431db20fd2bSAlexei Starovoitov err_put:
432db20fd2bSAlexei Starovoitov 	fdput(f);
433db20fd2bSAlexei Starovoitov 	return err;
434db20fd2bSAlexei Starovoitov }
435db20fd2bSAlexei Starovoitov 
436db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
437db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key
438db20fd2bSAlexei Starovoitov 
439db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr)
440db20fd2bSAlexei Starovoitov {
441db20fd2bSAlexei Starovoitov 	void __user *ukey = u64_to_ptr(attr->key);
442db20fd2bSAlexei Starovoitov 	void __user *unext_key = u64_to_ptr(attr->next_key);
443db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
444db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
445db20fd2bSAlexei Starovoitov 	void *key, *next_key;
446592867bfSDaniel Borkmann 	struct fd f;
447db20fd2bSAlexei Starovoitov 	int err;
448db20fd2bSAlexei Starovoitov 
449db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY))
450db20fd2bSAlexei Starovoitov 		return -EINVAL;
451db20fd2bSAlexei Starovoitov 
452592867bfSDaniel Borkmann 	f = fdget(ufd);
453c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
454db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
455db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
456db20fd2bSAlexei Starovoitov 
457db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
458db20fd2bSAlexei Starovoitov 	key = kmalloc(map->key_size, GFP_USER);
459db20fd2bSAlexei Starovoitov 	if (!key)
460db20fd2bSAlexei Starovoitov 		goto err_put;
461db20fd2bSAlexei Starovoitov 
462db20fd2bSAlexei Starovoitov 	err = -EFAULT;
463db20fd2bSAlexei Starovoitov 	if (copy_from_user(key, ukey, map->key_size) != 0)
464db20fd2bSAlexei Starovoitov 		goto free_key;
465db20fd2bSAlexei Starovoitov 
466db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
467db20fd2bSAlexei Starovoitov 	next_key = kmalloc(map->key_size, GFP_USER);
468db20fd2bSAlexei Starovoitov 	if (!next_key)
469db20fd2bSAlexei Starovoitov 		goto free_key;
470db20fd2bSAlexei Starovoitov 
471db20fd2bSAlexei Starovoitov 	rcu_read_lock();
472db20fd2bSAlexei Starovoitov 	err = map->ops->map_get_next_key(map, key, next_key);
473db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
474db20fd2bSAlexei Starovoitov 	if (err)
475db20fd2bSAlexei Starovoitov 		goto free_next_key;
476db20fd2bSAlexei Starovoitov 
477db20fd2bSAlexei Starovoitov 	err = -EFAULT;
478db20fd2bSAlexei Starovoitov 	if (copy_to_user(unext_key, next_key, map->key_size) != 0)
479db20fd2bSAlexei Starovoitov 		goto free_next_key;
480db20fd2bSAlexei Starovoitov 
481db20fd2bSAlexei Starovoitov 	err = 0;
482db20fd2bSAlexei Starovoitov 
483db20fd2bSAlexei Starovoitov free_next_key:
484db20fd2bSAlexei Starovoitov 	kfree(next_key);
485db20fd2bSAlexei Starovoitov free_key:
486db20fd2bSAlexei Starovoitov 	kfree(key);
487db20fd2bSAlexei Starovoitov err_put:
488db20fd2bSAlexei Starovoitov 	fdput(f);
489db20fd2bSAlexei Starovoitov 	return err;
490db20fd2bSAlexei Starovoitov }
491db20fd2bSAlexei Starovoitov 
49209756af4SAlexei Starovoitov static LIST_HEAD(bpf_prog_types);
49309756af4SAlexei Starovoitov 
49409756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
49509756af4SAlexei Starovoitov {
49609756af4SAlexei Starovoitov 	struct bpf_prog_type_list *tl;
49709756af4SAlexei Starovoitov 
49809756af4SAlexei Starovoitov 	list_for_each_entry(tl, &bpf_prog_types, list_node) {
49909756af4SAlexei Starovoitov 		if (tl->type == type) {
50009756af4SAlexei Starovoitov 			prog->aux->ops = tl->ops;
50124701eceSDaniel Borkmann 			prog->type = type;
50209756af4SAlexei Starovoitov 			return 0;
50309756af4SAlexei Starovoitov 		}
50409756af4SAlexei Starovoitov 	}
50524701eceSDaniel Borkmann 
50609756af4SAlexei Starovoitov 	return -EINVAL;
50709756af4SAlexei Starovoitov }
50809756af4SAlexei Starovoitov 
50909756af4SAlexei Starovoitov void bpf_register_prog_type(struct bpf_prog_type_list *tl)
51009756af4SAlexei Starovoitov {
51109756af4SAlexei Starovoitov 	list_add(&tl->list_node, &bpf_prog_types);
51209756af4SAlexei Starovoitov }
51309756af4SAlexei Starovoitov 
5140a542a86SAlexei Starovoitov /* fixup insn->imm field of bpf_call instructions:
5150a542a86SAlexei Starovoitov  * if (insn->imm == BPF_FUNC_map_lookup_elem)
5160a542a86SAlexei Starovoitov  *      insn->imm = bpf_map_lookup_elem - __bpf_call_base;
5170a542a86SAlexei Starovoitov  * else if (insn->imm == BPF_FUNC_map_update_elem)
5180a542a86SAlexei Starovoitov  *      insn->imm = bpf_map_update_elem - __bpf_call_base;
5190a542a86SAlexei Starovoitov  * else ...
5200a542a86SAlexei Starovoitov  *
5210a542a86SAlexei Starovoitov  * this function is called after eBPF program passed verification
5220a542a86SAlexei Starovoitov  */
5230a542a86SAlexei Starovoitov static void fixup_bpf_calls(struct bpf_prog *prog)
5240a542a86SAlexei Starovoitov {
5250a542a86SAlexei Starovoitov 	const struct bpf_func_proto *fn;
5260a542a86SAlexei Starovoitov 	int i;
5270a542a86SAlexei Starovoitov 
5280a542a86SAlexei Starovoitov 	for (i = 0; i < prog->len; i++) {
5290a542a86SAlexei Starovoitov 		struct bpf_insn *insn = &prog->insnsi[i];
5300a542a86SAlexei Starovoitov 
5310a542a86SAlexei Starovoitov 		if (insn->code == (BPF_JMP | BPF_CALL)) {
5320a542a86SAlexei Starovoitov 			/* we reach here when program has bpf_call instructions
5330a542a86SAlexei Starovoitov 			 * and it passed bpf_check(), means that
5340a542a86SAlexei Starovoitov 			 * ops->get_func_proto must have been supplied, check it
5350a542a86SAlexei Starovoitov 			 */
5360a542a86SAlexei Starovoitov 			BUG_ON(!prog->aux->ops->get_func_proto);
5370a542a86SAlexei Starovoitov 
538c46646d0SDaniel Borkmann 			if (insn->imm == BPF_FUNC_get_route_realm)
539c46646d0SDaniel Borkmann 				prog->dst_needed = 1;
5403ad00405SDaniel Borkmann 			if (insn->imm == BPF_FUNC_get_prandom_u32)
5413ad00405SDaniel Borkmann 				bpf_user_rnd_init_once();
54204fd61abSAlexei Starovoitov 			if (insn->imm == BPF_FUNC_tail_call) {
54304fd61abSAlexei Starovoitov 				/* mark bpf_tail_call as different opcode
54404fd61abSAlexei Starovoitov 				 * to avoid conditional branch in
54504fd61abSAlexei Starovoitov 				 * interpeter for every normal call
54604fd61abSAlexei Starovoitov 				 * and to prevent accidental JITing by
54704fd61abSAlexei Starovoitov 				 * JIT compiler that doesn't support
54804fd61abSAlexei Starovoitov 				 * bpf_tail_call yet
54904fd61abSAlexei Starovoitov 				 */
55004fd61abSAlexei Starovoitov 				insn->imm = 0;
55104fd61abSAlexei Starovoitov 				insn->code |= BPF_X;
55204fd61abSAlexei Starovoitov 				continue;
55304fd61abSAlexei Starovoitov 			}
55404fd61abSAlexei Starovoitov 
5550a542a86SAlexei Starovoitov 			fn = prog->aux->ops->get_func_proto(insn->imm);
5560a542a86SAlexei Starovoitov 			/* all functions that have prototype and verifier allowed
5570a542a86SAlexei Starovoitov 			 * programs to call them, must be real in-kernel functions
5580a542a86SAlexei Starovoitov 			 */
5590a542a86SAlexei Starovoitov 			BUG_ON(!fn->func);
5600a542a86SAlexei Starovoitov 			insn->imm = fn->func - __bpf_call_base;
5610a542a86SAlexei Starovoitov 		}
5620a542a86SAlexei Starovoitov 	}
5630a542a86SAlexei Starovoitov }
5640a542a86SAlexei Starovoitov 
56509756af4SAlexei Starovoitov /* drop refcnt on maps used by eBPF program and free auxilary data */
56609756af4SAlexei Starovoitov static void free_used_maps(struct bpf_prog_aux *aux)
56709756af4SAlexei Starovoitov {
56809756af4SAlexei Starovoitov 	int i;
56909756af4SAlexei Starovoitov 
57009756af4SAlexei Starovoitov 	for (i = 0; i < aux->used_map_cnt; i++)
57109756af4SAlexei Starovoitov 		bpf_map_put(aux->used_maps[i]);
57209756af4SAlexei Starovoitov 
57309756af4SAlexei Starovoitov 	kfree(aux->used_maps);
57409756af4SAlexei Starovoitov }
57509756af4SAlexei Starovoitov 
576aaac3ba9SAlexei Starovoitov static int bpf_prog_charge_memlock(struct bpf_prog *prog)
577aaac3ba9SAlexei Starovoitov {
578aaac3ba9SAlexei Starovoitov 	struct user_struct *user = get_current_user();
579aaac3ba9SAlexei Starovoitov 	unsigned long memlock_limit;
580aaac3ba9SAlexei Starovoitov 
581aaac3ba9SAlexei Starovoitov 	memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
582aaac3ba9SAlexei Starovoitov 
583aaac3ba9SAlexei Starovoitov 	atomic_long_add(prog->pages, &user->locked_vm);
584aaac3ba9SAlexei Starovoitov 	if (atomic_long_read(&user->locked_vm) > memlock_limit) {
585aaac3ba9SAlexei Starovoitov 		atomic_long_sub(prog->pages, &user->locked_vm);
586aaac3ba9SAlexei Starovoitov 		free_uid(user);
587aaac3ba9SAlexei Starovoitov 		return -EPERM;
588aaac3ba9SAlexei Starovoitov 	}
589aaac3ba9SAlexei Starovoitov 	prog->aux->user = user;
590aaac3ba9SAlexei Starovoitov 	return 0;
591aaac3ba9SAlexei Starovoitov }
592aaac3ba9SAlexei Starovoitov 
593aaac3ba9SAlexei Starovoitov static void bpf_prog_uncharge_memlock(struct bpf_prog *prog)
594aaac3ba9SAlexei Starovoitov {
595aaac3ba9SAlexei Starovoitov 	struct user_struct *user = prog->aux->user;
596aaac3ba9SAlexei Starovoitov 
597aaac3ba9SAlexei Starovoitov 	atomic_long_sub(prog->pages, &user->locked_vm);
598aaac3ba9SAlexei Starovoitov 	free_uid(user);
599aaac3ba9SAlexei Starovoitov }
600aaac3ba9SAlexei Starovoitov 
601e9d8afa9SDaniel Borkmann static void __prog_put_common(struct rcu_head *rcu)
602abf2e7d6SAlexei Starovoitov {
603abf2e7d6SAlexei Starovoitov 	struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
604abf2e7d6SAlexei Starovoitov 
605abf2e7d6SAlexei Starovoitov 	free_used_maps(aux);
606aaac3ba9SAlexei Starovoitov 	bpf_prog_uncharge_memlock(aux->prog);
607abf2e7d6SAlexei Starovoitov 	bpf_prog_free(aux->prog);
608abf2e7d6SAlexei Starovoitov }
609abf2e7d6SAlexei Starovoitov 
610abf2e7d6SAlexei Starovoitov /* version of bpf_prog_put() that is called after a grace period */
611abf2e7d6SAlexei Starovoitov void bpf_prog_put_rcu(struct bpf_prog *prog)
612abf2e7d6SAlexei Starovoitov {
613e9d8afa9SDaniel Borkmann 	if (atomic_dec_and_test(&prog->aux->refcnt))
614e9d8afa9SDaniel Borkmann 		call_rcu(&prog->aux->rcu, __prog_put_common);
615abf2e7d6SAlexei Starovoitov }
616abf2e7d6SAlexei Starovoitov 
61709756af4SAlexei Starovoitov void bpf_prog_put(struct bpf_prog *prog)
61809756af4SAlexei Starovoitov {
619e9d8afa9SDaniel Borkmann 	if (atomic_dec_and_test(&prog->aux->refcnt))
620e9d8afa9SDaniel Borkmann 		__prog_put_common(&prog->aux->rcu);
62109756af4SAlexei Starovoitov }
622e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put);
62309756af4SAlexei Starovoitov 
62409756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp)
62509756af4SAlexei Starovoitov {
62609756af4SAlexei Starovoitov 	struct bpf_prog *prog = filp->private_data;
62709756af4SAlexei Starovoitov 
628abf2e7d6SAlexei Starovoitov 	bpf_prog_put_rcu(prog);
62909756af4SAlexei Starovoitov 	return 0;
63009756af4SAlexei Starovoitov }
63109756af4SAlexei Starovoitov 
63209756af4SAlexei Starovoitov static const struct file_operations bpf_prog_fops = {
63309756af4SAlexei Starovoitov         .release = bpf_prog_release,
63409756af4SAlexei Starovoitov };
63509756af4SAlexei Starovoitov 
636b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog)
637aa79781bSDaniel Borkmann {
638aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog,
639aa79781bSDaniel Borkmann 				O_RDWR | O_CLOEXEC);
640aa79781bSDaniel Borkmann }
641aa79781bSDaniel Borkmann 
642c2101297SDaniel Borkmann static struct bpf_prog *__bpf_prog_get(struct fd f)
64309756af4SAlexei Starovoitov {
64409756af4SAlexei Starovoitov 	if (!f.file)
64509756af4SAlexei Starovoitov 		return ERR_PTR(-EBADF);
64609756af4SAlexei Starovoitov 	if (f.file->f_op != &bpf_prog_fops) {
64709756af4SAlexei Starovoitov 		fdput(f);
64809756af4SAlexei Starovoitov 		return ERR_PTR(-EINVAL);
64909756af4SAlexei Starovoitov 	}
65009756af4SAlexei Starovoitov 
651c2101297SDaniel Borkmann 	return f.file->private_data;
65209756af4SAlexei Starovoitov }
65309756af4SAlexei Starovoitov 
65409756af4SAlexei Starovoitov /* called by sockets/tracing/seccomp before attaching program to an event
65509756af4SAlexei Starovoitov  * pairs with bpf_prog_put()
65609756af4SAlexei Starovoitov  */
65709756af4SAlexei Starovoitov struct bpf_prog *bpf_prog_get(u32 ufd)
65809756af4SAlexei Starovoitov {
65909756af4SAlexei Starovoitov 	struct fd f = fdget(ufd);
66009756af4SAlexei Starovoitov 	struct bpf_prog *prog;
66109756af4SAlexei Starovoitov 
662c2101297SDaniel Borkmann 	prog = __bpf_prog_get(f);
66309756af4SAlexei Starovoitov 	if (IS_ERR(prog))
66409756af4SAlexei Starovoitov 		return prog;
66509756af4SAlexei Starovoitov 
66609756af4SAlexei Starovoitov 	atomic_inc(&prog->aux->refcnt);
66709756af4SAlexei Starovoitov 	fdput(f);
668c2101297SDaniel Borkmann 
66909756af4SAlexei Starovoitov 	return prog;
67009756af4SAlexei Starovoitov }
671e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_get);
67209756af4SAlexei Starovoitov 
67309756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
6742541517cSAlexei Starovoitov #define	BPF_PROG_LOAD_LAST_FIELD kern_version
67509756af4SAlexei Starovoitov 
67609756af4SAlexei Starovoitov static int bpf_prog_load(union bpf_attr *attr)
67709756af4SAlexei Starovoitov {
67809756af4SAlexei Starovoitov 	enum bpf_prog_type type = attr->prog_type;
67909756af4SAlexei Starovoitov 	struct bpf_prog *prog;
68009756af4SAlexei Starovoitov 	int err;
68109756af4SAlexei Starovoitov 	char license[128];
68209756af4SAlexei Starovoitov 	bool is_gpl;
68309756af4SAlexei Starovoitov 
68409756af4SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_LOAD))
68509756af4SAlexei Starovoitov 		return -EINVAL;
68609756af4SAlexei Starovoitov 
68709756af4SAlexei Starovoitov 	/* copy eBPF program license from user space */
68809756af4SAlexei Starovoitov 	if (strncpy_from_user(license, u64_to_ptr(attr->license),
68909756af4SAlexei Starovoitov 			      sizeof(license) - 1) < 0)
69009756af4SAlexei Starovoitov 		return -EFAULT;
69109756af4SAlexei Starovoitov 	license[sizeof(license) - 1] = 0;
69209756af4SAlexei Starovoitov 
69309756af4SAlexei Starovoitov 	/* eBPF programs must be GPL compatible to use GPL-ed functions */
69409756af4SAlexei Starovoitov 	is_gpl = license_is_gpl_compatible(license);
69509756af4SAlexei Starovoitov 
69609756af4SAlexei Starovoitov 	if (attr->insn_cnt >= BPF_MAXINSNS)
69709756af4SAlexei Starovoitov 		return -EINVAL;
69809756af4SAlexei Starovoitov 
6992541517cSAlexei Starovoitov 	if (type == BPF_PROG_TYPE_KPROBE &&
7002541517cSAlexei Starovoitov 	    attr->kern_version != LINUX_VERSION_CODE)
7012541517cSAlexei Starovoitov 		return -EINVAL;
7022541517cSAlexei Starovoitov 
7031be7f75dSAlexei Starovoitov 	if (type != BPF_PROG_TYPE_SOCKET_FILTER && !capable(CAP_SYS_ADMIN))
7041be7f75dSAlexei Starovoitov 		return -EPERM;
7051be7f75dSAlexei Starovoitov 
70609756af4SAlexei Starovoitov 	/* plain bpf_prog allocation */
70709756af4SAlexei Starovoitov 	prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
70809756af4SAlexei Starovoitov 	if (!prog)
70909756af4SAlexei Starovoitov 		return -ENOMEM;
71009756af4SAlexei Starovoitov 
711aaac3ba9SAlexei Starovoitov 	err = bpf_prog_charge_memlock(prog);
712aaac3ba9SAlexei Starovoitov 	if (err)
713aaac3ba9SAlexei Starovoitov 		goto free_prog_nouncharge;
714aaac3ba9SAlexei Starovoitov 
71509756af4SAlexei Starovoitov 	prog->len = attr->insn_cnt;
71609756af4SAlexei Starovoitov 
71709756af4SAlexei Starovoitov 	err = -EFAULT;
71809756af4SAlexei Starovoitov 	if (copy_from_user(prog->insns, u64_to_ptr(attr->insns),
71909756af4SAlexei Starovoitov 			   prog->len * sizeof(struct bpf_insn)) != 0)
72009756af4SAlexei Starovoitov 		goto free_prog;
72109756af4SAlexei Starovoitov 
72209756af4SAlexei Starovoitov 	prog->orig_prog = NULL;
723a91263d5SDaniel Borkmann 	prog->jited = 0;
72409756af4SAlexei Starovoitov 
72509756af4SAlexei Starovoitov 	atomic_set(&prog->aux->refcnt, 1);
726a91263d5SDaniel Borkmann 	prog->gpl_compatible = is_gpl ? 1 : 0;
72709756af4SAlexei Starovoitov 
72809756af4SAlexei Starovoitov 	/* find program type: socket_filter vs tracing_filter */
72909756af4SAlexei Starovoitov 	err = find_prog_type(type, prog);
73009756af4SAlexei Starovoitov 	if (err < 0)
73109756af4SAlexei Starovoitov 		goto free_prog;
73209756af4SAlexei Starovoitov 
73309756af4SAlexei Starovoitov 	/* run eBPF verifier */
7349bac3d6dSAlexei Starovoitov 	err = bpf_check(&prog, attr);
73509756af4SAlexei Starovoitov 	if (err < 0)
73609756af4SAlexei Starovoitov 		goto free_used_maps;
73709756af4SAlexei Starovoitov 
7380a542a86SAlexei Starovoitov 	/* fixup BPF_CALL->imm field */
7390a542a86SAlexei Starovoitov 	fixup_bpf_calls(prog);
7400a542a86SAlexei Starovoitov 
74109756af4SAlexei Starovoitov 	/* eBPF program is ready to be JITed */
74204fd61abSAlexei Starovoitov 	err = bpf_prog_select_runtime(prog);
74304fd61abSAlexei Starovoitov 	if (err < 0)
74404fd61abSAlexei Starovoitov 		goto free_used_maps;
74509756af4SAlexei Starovoitov 
746aa79781bSDaniel Borkmann 	err = bpf_prog_new_fd(prog);
74709756af4SAlexei Starovoitov 	if (err < 0)
74809756af4SAlexei Starovoitov 		/* failed to allocate fd */
74909756af4SAlexei Starovoitov 		goto free_used_maps;
75009756af4SAlexei Starovoitov 
75109756af4SAlexei Starovoitov 	return err;
75209756af4SAlexei Starovoitov 
75309756af4SAlexei Starovoitov free_used_maps:
75409756af4SAlexei Starovoitov 	free_used_maps(prog->aux);
75509756af4SAlexei Starovoitov free_prog:
756aaac3ba9SAlexei Starovoitov 	bpf_prog_uncharge_memlock(prog);
757aaac3ba9SAlexei Starovoitov free_prog_nouncharge:
75809756af4SAlexei Starovoitov 	bpf_prog_free(prog);
75909756af4SAlexei Starovoitov 	return err;
76009756af4SAlexei Starovoitov }
76109756af4SAlexei Starovoitov 
762b2197755SDaniel Borkmann #define BPF_OBJ_LAST_FIELD bpf_fd
763b2197755SDaniel Borkmann 
764b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr)
765b2197755SDaniel Borkmann {
766b2197755SDaniel Borkmann 	if (CHECK_ATTR(BPF_OBJ))
767b2197755SDaniel Borkmann 		return -EINVAL;
768b2197755SDaniel Borkmann 
769b2197755SDaniel Borkmann 	return bpf_obj_pin_user(attr->bpf_fd, u64_to_ptr(attr->pathname));
770b2197755SDaniel Borkmann }
771b2197755SDaniel Borkmann 
772b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr)
773b2197755SDaniel Borkmann {
774b2197755SDaniel Borkmann 	if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0)
775b2197755SDaniel Borkmann 		return -EINVAL;
776b2197755SDaniel Borkmann 
777b2197755SDaniel Borkmann 	return bpf_obj_get_user(u64_to_ptr(attr->pathname));
778b2197755SDaniel Borkmann }
779b2197755SDaniel Borkmann 
78099c55f7dSAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
78199c55f7dSAlexei Starovoitov {
78299c55f7dSAlexei Starovoitov 	union bpf_attr attr = {};
78399c55f7dSAlexei Starovoitov 	int err;
78499c55f7dSAlexei Starovoitov 
7851be7f75dSAlexei Starovoitov 	if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled)
78699c55f7dSAlexei Starovoitov 		return -EPERM;
78799c55f7dSAlexei Starovoitov 
78899c55f7dSAlexei Starovoitov 	if (!access_ok(VERIFY_READ, uattr, 1))
78999c55f7dSAlexei Starovoitov 		return -EFAULT;
79099c55f7dSAlexei Starovoitov 
79199c55f7dSAlexei Starovoitov 	if (size > PAGE_SIZE)	/* silly large */
79299c55f7dSAlexei Starovoitov 		return -E2BIG;
79399c55f7dSAlexei Starovoitov 
79499c55f7dSAlexei Starovoitov 	/* If we're handed a bigger struct than we know of,
79599c55f7dSAlexei Starovoitov 	 * ensure all the unknown bits are 0 - i.e. new
79699c55f7dSAlexei Starovoitov 	 * user-space does not rely on any kernel feature
79799c55f7dSAlexei Starovoitov 	 * extensions we dont know about yet.
79899c55f7dSAlexei Starovoitov 	 */
79999c55f7dSAlexei Starovoitov 	if (size > sizeof(attr)) {
80099c55f7dSAlexei Starovoitov 		unsigned char __user *addr;
80199c55f7dSAlexei Starovoitov 		unsigned char __user *end;
80299c55f7dSAlexei Starovoitov 		unsigned char val;
80399c55f7dSAlexei Starovoitov 
80499c55f7dSAlexei Starovoitov 		addr = (void __user *)uattr + sizeof(attr);
80599c55f7dSAlexei Starovoitov 		end  = (void __user *)uattr + size;
80699c55f7dSAlexei Starovoitov 
80799c55f7dSAlexei Starovoitov 		for (; addr < end; addr++) {
80899c55f7dSAlexei Starovoitov 			err = get_user(val, addr);
80999c55f7dSAlexei Starovoitov 			if (err)
81099c55f7dSAlexei Starovoitov 				return err;
81199c55f7dSAlexei Starovoitov 			if (val)
81299c55f7dSAlexei Starovoitov 				return -E2BIG;
81399c55f7dSAlexei Starovoitov 		}
81499c55f7dSAlexei Starovoitov 		size = sizeof(attr);
81599c55f7dSAlexei Starovoitov 	}
81699c55f7dSAlexei Starovoitov 
81799c55f7dSAlexei Starovoitov 	/* copy attributes from user space, may be less than sizeof(bpf_attr) */
81899c55f7dSAlexei Starovoitov 	if (copy_from_user(&attr, uattr, size) != 0)
81999c55f7dSAlexei Starovoitov 		return -EFAULT;
82099c55f7dSAlexei Starovoitov 
82199c55f7dSAlexei Starovoitov 	switch (cmd) {
82299c55f7dSAlexei Starovoitov 	case BPF_MAP_CREATE:
82399c55f7dSAlexei Starovoitov 		err = map_create(&attr);
82499c55f7dSAlexei Starovoitov 		break;
825db20fd2bSAlexei Starovoitov 	case BPF_MAP_LOOKUP_ELEM:
826db20fd2bSAlexei Starovoitov 		err = map_lookup_elem(&attr);
827db20fd2bSAlexei Starovoitov 		break;
828db20fd2bSAlexei Starovoitov 	case BPF_MAP_UPDATE_ELEM:
829db20fd2bSAlexei Starovoitov 		err = map_update_elem(&attr);
830db20fd2bSAlexei Starovoitov 		break;
831db20fd2bSAlexei Starovoitov 	case BPF_MAP_DELETE_ELEM:
832db20fd2bSAlexei Starovoitov 		err = map_delete_elem(&attr);
833db20fd2bSAlexei Starovoitov 		break;
834db20fd2bSAlexei Starovoitov 	case BPF_MAP_GET_NEXT_KEY:
835db20fd2bSAlexei Starovoitov 		err = map_get_next_key(&attr);
836db20fd2bSAlexei Starovoitov 		break;
83709756af4SAlexei Starovoitov 	case BPF_PROG_LOAD:
83809756af4SAlexei Starovoitov 		err = bpf_prog_load(&attr);
83909756af4SAlexei Starovoitov 		break;
840b2197755SDaniel Borkmann 	case BPF_OBJ_PIN:
841b2197755SDaniel Borkmann 		err = bpf_obj_pin(&attr);
842b2197755SDaniel Borkmann 		break;
843b2197755SDaniel Borkmann 	case BPF_OBJ_GET:
844b2197755SDaniel Borkmann 		err = bpf_obj_get(&attr);
845b2197755SDaniel Borkmann 		break;
84699c55f7dSAlexei Starovoitov 	default:
84799c55f7dSAlexei Starovoitov 		err = -EINVAL;
84899c55f7dSAlexei Starovoitov 		break;
84999c55f7dSAlexei Starovoitov 	}
85099c55f7dSAlexei Starovoitov 
85199c55f7dSAlexei Starovoitov 	return err;
85299c55f7dSAlexei Starovoitov }
853