xref: /linux/kernel/bpf/syscall.c (revision 9975a54b3c9ecf029cbf5dd7a8c9701b1d74029e)
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>
13a67edbf4SDaniel Borkmann #include <linux/bpf_trace.h>
1499c55f7dSAlexei Starovoitov #include <linux/syscalls.h>
1599c55f7dSAlexei Starovoitov #include <linux/slab.h>
163f07c014SIngo Molnar #include <linux/sched/signal.h>
17d407bd25SDaniel Borkmann #include <linux/vmalloc.h>
18d407bd25SDaniel Borkmann #include <linux/mmzone.h>
1999c55f7dSAlexei Starovoitov #include <linux/anon_inodes.h>
20db20fd2bSAlexei Starovoitov #include <linux/file.h>
2109756af4SAlexei Starovoitov #include <linux/license.h>
2209756af4SAlexei Starovoitov #include <linux/filter.h>
232541517cSAlexei Starovoitov #include <linux/version.h>
24535e7b4bSMickaël Salaün #include <linux/kernel.h>
25dc4bb0e2SMartin KaFai Lau #include <linux/idr.h>
2699c55f7dSAlexei Starovoitov 
2714dc6f04SMartin KaFai Lau #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY || \
2814dc6f04SMartin KaFai Lau 			   (map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \
2914dc6f04SMartin KaFai Lau 			   (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \
3014dc6f04SMartin KaFai Lau 			   (map)->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS)
3114dc6f04SMartin KaFai Lau #define IS_FD_HASH(map) ((map)->map_type == BPF_MAP_TYPE_HASH_OF_MAPS)
3214dc6f04SMartin KaFai Lau #define IS_FD_MAP(map) (IS_FD_ARRAY(map) || IS_FD_HASH(map))
3314dc6f04SMartin KaFai Lau 
34b121d1e7SAlexei Starovoitov DEFINE_PER_CPU(int, bpf_prog_active);
35dc4bb0e2SMartin KaFai Lau static DEFINE_IDR(prog_idr);
36dc4bb0e2SMartin KaFai Lau static DEFINE_SPINLOCK(prog_idr_lock);
37f3f1c054SMartin KaFai Lau static DEFINE_IDR(map_idr);
38f3f1c054SMartin KaFai Lau static DEFINE_SPINLOCK(map_idr_lock);
39b121d1e7SAlexei Starovoitov 
401be7f75dSAlexei Starovoitov int sysctl_unprivileged_bpf_disabled __read_mostly;
411be7f75dSAlexei Starovoitov 
4240077e0cSJohannes Berg static const struct bpf_map_ops * const bpf_map_types[] = {
4340077e0cSJohannes Berg #define BPF_PROG_TYPE(_id, _ops)
4440077e0cSJohannes Berg #define BPF_MAP_TYPE(_id, _ops) \
4540077e0cSJohannes Berg 	[_id] = &_ops,
4640077e0cSJohannes Berg #include <linux/bpf_types.h>
4740077e0cSJohannes Berg #undef BPF_PROG_TYPE
4840077e0cSJohannes Berg #undef BPF_MAP_TYPE
4940077e0cSJohannes Berg };
5099c55f7dSAlexei Starovoitov 
5199c55f7dSAlexei Starovoitov static struct bpf_map *find_and_alloc_map(union bpf_attr *attr)
5299c55f7dSAlexei Starovoitov {
5399c55f7dSAlexei Starovoitov 	struct bpf_map *map;
5499c55f7dSAlexei Starovoitov 
5540077e0cSJohannes Berg 	if (attr->map_type >= ARRAY_SIZE(bpf_map_types) ||
5640077e0cSJohannes Berg 	    !bpf_map_types[attr->map_type])
5740077e0cSJohannes Berg 		return ERR_PTR(-EINVAL);
5840077e0cSJohannes Berg 
5940077e0cSJohannes Berg 	map = bpf_map_types[attr->map_type]->map_alloc(attr);
6099c55f7dSAlexei Starovoitov 	if (IS_ERR(map))
6199c55f7dSAlexei Starovoitov 		return map;
6240077e0cSJohannes Berg 	map->ops = bpf_map_types[attr->map_type];
6399c55f7dSAlexei Starovoitov 	map->map_type = attr->map_type;
6499c55f7dSAlexei Starovoitov 	return map;
6599c55f7dSAlexei Starovoitov }
6699c55f7dSAlexei Starovoitov 
67d407bd25SDaniel Borkmann void *bpf_map_area_alloc(size_t size)
68d407bd25SDaniel Borkmann {
69d407bd25SDaniel Borkmann 	/* We definitely need __GFP_NORETRY, so OOM killer doesn't
70d407bd25SDaniel Borkmann 	 * trigger under memory pressure as we really just want to
71d407bd25SDaniel Borkmann 	 * fail instead.
72d407bd25SDaniel Borkmann 	 */
73d407bd25SDaniel Borkmann 	const gfp_t flags = __GFP_NOWARN | __GFP_NORETRY | __GFP_ZERO;
74d407bd25SDaniel Borkmann 	void *area;
75d407bd25SDaniel Borkmann 
76d407bd25SDaniel Borkmann 	if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
77d407bd25SDaniel Borkmann 		area = kmalloc(size, GFP_USER | flags);
78d407bd25SDaniel Borkmann 		if (area != NULL)
79d407bd25SDaniel Borkmann 			return area;
80d407bd25SDaniel Borkmann 	}
81d407bd25SDaniel Borkmann 
8219809c2dSMichal Hocko 	return __vmalloc(size, GFP_KERNEL | flags, PAGE_KERNEL);
83d407bd25SDaniel Borkmann }
84d407bd25SDaniel Borkmann 
85d407bd25SDaniel Borkmann void bpf_map_area_free(void *area)
86d407bd25SDaniel Borkmann {
87d407bd25SDaniel Borkmann 	kvfree(area);
88d407bd25SDaniel Borkmann }
89d407bd25SDaniel Borkmann 
906c905981SAlexei Starovoitov int bpf_map_precharge_memlock(u32 pages)
916c905981SAlexei Starovoitov {
926c905981SAlexei Starovoitov 	struct user_struct *user = get_current_user();
936c905981SAlexei Starovoitov 	unsigned long memlock_limit, cur;
946c905981SAlexei Starovoitov 
956c905981SAlexei Starovoitov 	memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
966c905981SAlexei Starovoitov 	cur = atomic_long_read(&user->locked_vm);
976c905981SAlexei Starovoitov 	free_uid(user);
986c905981SAlexei Starovoitov 	if (cur + pages > memlock_limit)
996c905981SAlexei Starovoitov 		return -EPERM;
1006c905981SAlexei Starovoitov 	return 0;
1016c905981SAlexei Starovoitov }
1026c905981SAlexei Starovoitov 
103aaac3ba9SAlexei Starovoitov static int bpf_map_charge_memlock(struct bpf_map *map)
104aaac3ba9SAlexei Starovoitov {
105aaac3ba9SAlexei Starovoitov 	struct user_struct *user = get_current_user();
106aaac3ba9SAlexei Starovoitov 	unsigned long memlock_limit;
107aaac3ba9SAlexei Starovoitov 
108aaac3ba9SAlexei Starovoitov 	memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
109aaac3ba9SAlexei Starovoitov 
110aaac3ba9SAlexei Starovoitov 	atomic_long_add(map->pages, &user->locked_vm);
111aaac3ba9SAlexei Starovoitov 
112aaac3ba9SAlexei Starovoitov 	if (atomic_long_read(&user->locked_vm) > memlock_limit) {
113aaac3ba9SAlexei Starovoitov 		atomic_long_sub(map->pages, &user->locked_vm);
114aaac3ba9SAlexei Starovoitov 		free_uid(user);
115aaac3ba9SAlexei Starovoitov 		return -EPERM;
116aaac3ba9SAlexei Starovoitov 	}
117aaac3ba9SAlexei Starovoitov 	map->user = user;
118aaac3ba9SAlexei Starovoitov 	return 0;
119aaac3ba9SAlexei Starovoitov }
120aaac3ba9SAlexei Starovoitov 
121aaac3ba9SAlexei Starovoitov static void bpf_map_uncharge_memlock(struct bpf_map *map)
122aaac3ba9SAlexei Starovoitov {
123aaac3ba9SAlexei Starovoitov 	struct user_struct *user = map->user;
124aaac3ba9SAlexei Starovoitov 
125aaac3ba9SAlexei Starovoitov 	atomic_long_sub(map->pages, &user->locked_vm);
126aaac3ba9SAlexei Starovoitov 	free_uid(user);
127aaac3ba9SAlexei Starovoitov }
128aaac3ba9SAlexei Starovoitov 
129f3f1c054SMartin KaFai Lau static int bpf_map_alloc_id(struct bpf_map *map)
130f3f1c054SMartin KaFai Lau {
131f3f1c054SMartin KaFai Lau 	int id;
132f3f1c054SMartin KaFai Lau 
133f3f1c054SMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
134f3f1c054SMartin KaFai Lau 	id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC);
135f3f1c054SMartin KaFai Lau 	if (id > 0)
136f3f1c054SMartin KaFai Lau 		map->id = id;
137f3f1c054SMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
138f3f1c054SMartin KaFai Lau 
139f3f1c054SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
140f3f1c054SMartin KaFai Lau 		return -ENOSPC;
141f3f1c054SMartin KaFai Lau 
142f3f1c054SMartin KaFai Lau 	return id > 0 ? 0 : id;
143f3f1c054SMartin KaFai Lau }
144f3f1c054SMartin KaFai Lau 
145bd5f5f4eSMartin KaFai Lau static void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock)
146f3f1c054SMartin KaFai Lau {
147bd5f5f4eSMartin KaFai Lau 	if (do_idr_lock)
148f3f1c054SMartin KaFai Lau 		spin_lock_bh(&map_idr_lock);
149bd5f5f4eSMartin KaFai Lau 	else
150bd5f5f4eSMartin KaFai Lau 		__acquire(&map_idr_lock);
151bd5f5f4eSMartin KaFai Lau 
152f3f1c054SMartin KaFai Lau 	idr_remove(&map_idr, map->id);
153bd5f5f4eSMartin KaFai Lau 
154bd5f5f4eSMartin KaFai Lau 	if (do_idr_lock)
155f3f1c054SMartin KaFai Lau 		spin_unlock_bh(&map_idr_lock);
156bd5f5f4eSMartin KaFai Lau 	else
157bd5f5f4eSMartin KaFai Lau 		__release(&map_idr_lock);
158f3f1c054SMartin KaFai Lau }
159f3f1c054SMartin KaFai Lau 
16099c55f7dSAlexei Starovoitov /* called from workqueue */
16199c55f7dSAlexei Starovoitov static void bpf_map_free_deferred(struct work_struct *work)
16299c55f7dSAlexei Starovoitov {
16399c55f7dSAlexei Starovoitov 	struct bpf_map *map = container_of(work, struct bpf_map, work);
16499c55f7dSAlexei Starovoitov 
165aaac3ba9SAlexei Starovoitov 	bpf_map_uncharge_memlock(map);
16699c55f7dSAlexei Starovoitov 	/* implementation dependent freeing */
16799c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
16899c55f7dSAlexei Starovoitov }
16999c55f7dSAlexei Starovoitov 
170c9da161cSDaniel Borkmann static void bpf_map_put_uref(struct bpf_map *map)
171c9da161cSDaniel Borkmann {
172c9da161cSDaniel Borkmann 	if (atomic_dec_and_test(&map->usercnt)) {
173c9da161cSDaniel Borkmann 		if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY)
174c9da161cSDaniel Borkmann 			bpf_fd_array_map_clear(map);
175c9da161cSDaniel Borkmann 	}
176c9da161cSDaniel Borkmann }
177c9da161cSDaniel Borkmann 
17899c55f7dSAlexei Starovoitov /* decrement map refcnt and schedule it for freeing via workqueue
17999c55f7dSAlexei Starovoitov  * (unrelying map implementation ops->map_free() might sleep)
18099c55f7dSAlexei Starovoitov  */
181bd5f5f4eSMartin KaFai Lau static void __bpf_map_put(struct bpf_map *map, bool do_idr_lock)
18299c55f7dSAlexei Starovoitov {
18399c55f7dSAlexei Starovoitov 	if (atomic_dec_and_test(&map->refcnt)) {
18434ad5580SMartin KaFai Lau 		/* bpf_map_free_id() must be called first */
185bd5f5f4eSMartin KaFai Lau 		bpf_map_free_id(map, do_idr_lock);
18699c55f7dSAlexei Starovoitov 		INIT_WORK(&map->work, bpf_map_free_deferred);
18799c55f7dSAlexei Starovoitov 		schedule_work(&map->work);
18899c55f7dSAlexei Starovoitov 	}
18999c55f7dSAlexei Starovoitov }
19099c55f7dSAlexei Starovoitov 
191bd5f5f4eSMartin KaFai Lau void bpf_map_put(struct bpf_map *map)
192bd5f5f4eSMartin KaFai Lau {
193bd5f5f4eSMartin KaFai Lau 	__bpf_map_put(map, true);
194bd5f5f4eSMartin KaFai Lau }
195bd5f5f4eSMartin KaFai Lau 
196c9da161cSDaniel Borkmann void bpf_map_put_with_uref(struct bpf_map *map)
197c9da161cSDaniel Borkmann {
198c9da161cSDaniel Borkmann 	bpf_map_put_uref(map);
199c9da161cSDaniel Borkmann 	bpf_map_put(map);
200c9da161cSDaniel Borkmann }
201c9da161cSDaniel Borkmann 
20299c55f7dSAlexei Starovoitov static int bpf_map_release(struct inode *inode, struct file *filp)
20399c55f7dSAlexei Starovoitov {
20461d1b6a4SDaniel Borkmann 	struct bpf_map *map = filp->private_data;
20561d1b6a4SDaniel Borkmann 
20661d1b6a4SDaniel Borkmann 	if (map->ops->map_release)
20761d1b6a4SDaniel Borkmann 		map->ops->map_release(map, filp);
20861d1b6a4SDaniel Borkmann 
20961d1b6a4SDaniel Borkmann 	bpf_map_put_with_uref(map);
21099c55f7dSAlexei Starovoitov 	return 0;
21199c55f7dSAlexei Starovoitov }
21299c55f7dSAlexei Starovoitov 
213f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
214f99bf205SDaniel Borkmann static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)
215f99bf205SDaniel Borkmann {
216f99bf205SDaniel Borkmann 	const struct bpf_map *map = filp->private_data;
21721116b70SDaniel Borkmann 	const struct bpf_array *array;
21821116b70SDaniel Borkmann 	u32 owner_prog_type = 0;
2199780c0abSDaniel Borkmann 	u32 owner_jited = 0;
22021116b70SDaniel Borkmann 
22121116b70SDaniel Borkmann 	if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) {
22221116b70SDaniel Borkmann 		array = container_of(map, struct bpf_array, map);
22321116b70SDaniel Borkmann 		owner_prog_type = array->owner_prog_type;
2249780c0abSDaniel Borkmann 		owner_jited = array->owner_jited;
22521116b70SDaniel Borkmann 	}
226f99bf205SDaniel Borkmann 
227f99bf205SDaniel Borkmann 	seq_printf(m,
228f99bf205SDaniel Borkmann 		   "map_type:\t%u\n"
229f99bf205SDaniel Borkmann 		   "key_size:\t%u\n"
230f99bf205SDaniel Borkmann 		   "value_size:\t%u\n"
231322cea2fSDaniel Borkmann 		   "max_entries:\t%u\n"
23221116b70SDaniel Borkmann 		   "map_flags:\t%#x\n"
23321116b70SDaniel Borkmann 		   "memlock:\t%llu\n",
234f99bf205SDaniel Borkmann 		   map->map_type,
235f99bf205SDaniel Borkmann 		   map->key_size,
236f99bf205SDaniel Borkmann 		   map->value_size,
237322cea2fSDaniel Borkmann 		   map->max_entries,
23821116b70SDaniel Borkmann 		   map->map_flags,
23921116b70SDaniel Borkmann 		   map->pages * 1ULL << PAGE_SHIFT);
24021116b70SDaniel Borkmann 
2419780c0abSDaniel Borkmann 	if (owner_prog_type) {
24221116b70SDaniel Borkmann 		seq_printf(m, "owner_prog_type:\t%u\n",
24321116b70SDaniel Borkmann 			   owner_prog_type);
2449780c0abSDaniel Borkmann 		seq_printf(m, "owner_jited:\t%u\n",
2459780c0abSDaniel Borkmann 			   owner_jited);
2469780c0abSDaniel Borkmann 	}
247f99bf205SDaniel Borkmann }
248f99bf205SDaniel Borkmann #endif
249f99bf205SDaniel Borkmann 
25099c55f7dSAlexei Starovoitov static const struct file_operations bpf_map_fops = {
251f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
252f99bf205SDaniel Borkmann 	.show_fdinfo	= bpf_map_show_fdinfo,
253f99bf205SDaniel Borkmann #endif
25499c55f7dSAlexei Starovoitov 	.release	= bpf_map_release,
25599c55f7dSAlexei Starovoitov };
25699c55f7dSAlexei Starovoitov 
257b2197755SDaniel Borkmann int bpf_map_new_fd(struct bpf_map *map)
258aa79781bSDaniel Borkmann {
259aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-map", &bpf_map_fops, map,
260aa79781bSDaniel Borkmann 				O_RDWR | O_CLOEXEC);
261aa79781bSDaniel Borkmann }
262aa79781bSDaniel Borkmann 
26399c55f7dSAlexei Starovoitov /* helper macro to check that unused fields 'union bpf_attr' are zero */
26499c55f7dSAlexei Starovoitov #define CHECK_ATTR(CMD) \
26599c55f7dSAlexei Starovoitov 	memchr_inv((void *) &attr->CMD##_LAST_FIELD + \
26699c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD), 0, \
26799c55f7dSAlexei Starovoitov 		   sizeof(*attr) - \
26899c55f7dSAlexei Starovoitov 		   offsetof(union bpf_attr, CMD##_LAST_FIELD) - \
26999c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD)) != NULL
27099c55f7dSAlexei Starovoitov 
27156f668dfSMartin KaFai Lau #define BPF_MAP_CREATE_LAST_FIELD inner_map_fd
27299c55f7dSAlexei Starovoitov /* called via syscall */
27399c55f7dSAlexei Starovoitov static int map_create(union bpf_attr *attr)
27499c55f7dSAlexei Starovoitov {
27599c55f7dSAlexei Starovoitov 	struct bpf_map *map;
27699c55f7dSAlexei Starovoitov 	int err;
27799c55f7dSAlexei Starovoitov 
27899c55f7dSAlexei Starovoitov 	err = CHECK_ATTR(BPF_MAP_CREATE);
27999c55f7dSAlexei Starovoitov 	if (err)
28099c55f7dSAlexei Starovoitov 		return -EINVAL;
28199c55f7dSAlexei Starovoitov 
28299c55f7dSAlexei Starovoitov 	/* find map type and init map: hashtable vs rbtree vs bloom vs ... */
28399c55f7dSAlexei Starovoitov 	map = find_and_alloc_map(attr);
28499c55f7dSAlexei Starovoitov 	if (IS_ERR(map))
28599c55f7dSAlexei Starovoitov 		return PTR_ERR(map);
28699c55f7dSAlexei Starovoitov 
28799c55f7dSAlexei Starovoitov 	atomic_set(&map->refcnt, 1);
288c9da161cSDaniel Borkmann 	atomic_set(&map->usercnt, 1);
28999c55f7dSAlexei Starovoitov 
290aaac3ba9SAlexei Starovoitov 	err = bpf_map_charge_memlock(map);
291aaac3ba9SAlexei Starovoitov 	if (err)
29220b2b24fSDaniel Borkmann 		goto free_map_nouncharge;
293aaac3ba9SAlexei Starovoitov 
294f3f1c054SMartin KaFai Lau 	err = bpf_map_alloc_id(map);
295f3f1c054SMartin KaFai Lau 	if (err)
296f3f1c054SMartin KaFai Lau 		goto free_map;
297f3f1c054SMartin KaFai Lau 
298aa79781bSDaniel Borkmann 	err = bpf_map_new_fd(map);
299bd5f5f4eSMartin KaFai Lau 	if (err < 0) {
300bd5f5f4eSMartin KaFai Lau 		/* failed to allocate fd.
301bd5f5f4eSMartin KaFai Lau 		 * bpf_map_put() is needed because the above
302bd5f5f4eSMartin KaFai Lau 		 * bpf_map_alloc_id() has published the map
303bd5f5f4eSMartin KaFai Lau 		 * to the userspace and the userspace may
304bd5f5f4eSMartin KaFai Lau 		 * have refcnt-ed it through BPF_MAP_GET_FD_BY_ID.
305bd5f5f4eSMartin KaFai Lau 		 */
306bd5f5f4eSMartin KaFai Lau 		bpf_map_put(map);
307bd5f5f4eSMartin KaFai Lau 		return err;
308bd5f5f4eSMartin KaFai Lau 	}
30999c55f7dSAlexei Starovoitov 
310a67edbf4SDaniel Borkmann 	trace_bpf_map_create(map, err);
31199c55f7dSAlexei Starovoitov 	return err;
31299c55f7dSAlexei Starovoitov 
31399c55f7dSAlexei Starovoitov free_map:
31420b2b24fSDaniel Borkmann 	bpf_map_uncharge_memlock(map);
31520b2b24fSDaniel Borkmann free_map_nouncharge:
31699c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
31799c55f7dSAlexei Starovoitov 	return err;
31899c55f7dSAlexei Starovoitov }
31999c55f7dSAlexei Starovoitov 
320db20fd2bSAlexei Starovoitov /* if error is returned, fd is released.
321db20fd2bSAlexei Starovoitov  * On success caller should complete fd access with matching fdput()
322db20fd2bSAlexei Starovoitov  */
323c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f)
324db20fd2bSAlexei Starovoitov {
325db20fd2bSAlexei Starovoitov 	if (!f.file)
326db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EBADF);
327db20fd2bSAlexei Starovoitov 	if (f.file->f_op != &bpf_map_fops) {
328db20fd2bSAlexei Starovoitov 		fdput(f);
329db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EINVAL);
330db20fd2bSAlexei Starovoitov 	}
331db20fd2bSAlexei Starovoitov 
332c2101297SDaniel Borkmann 	return f.file->private_data;
333c2101297SDaniel Borkmann }
334c2101297SDaniel Borkmann 
33592117d84SAlexei Starovoitov /* prog's and map's refcnt limit */
33692117d84SAlexei Starovoitov #define BPF_MAX_REFCNT 32768
33792117d84SAlexei Starovoitov 
33892117d84SAlexei Starovoitov struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref)
339c9da161cSDaniel Borkmann {
34092117d84SAlexei Starovoitov 	if (atomic_inc_return(&map->refcnt) > BPF_MAX_REFCNT) {
34192117d84SAlexei Starovoitov 		atomic_dec(&map->refcnt);
34292117d84SAlexei Starovoitov 		return ERR_PTR(-EBUSY);
34392117d84SAlexei Starovoitov 	}
344c9da161cSDaniel Borkmann 	if (uref)
345c9da161cSDaniel Borkmann 		atomic_inc(&map->usercnt);
34692117d84SAlexei Starovoitov 	return map;
347c9da161cSDaniel Borkmann }
348c9da161cSDaniel Borkmann 
349c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd)
350c2101297SDaniel Borkmann {
351c2101297SDaniel Borkmann 	struct fd f = fdget(ufd);
352c2101297SDaniel Borkmann 	struct bpf_map *map;
353c2101297SDaniel Borkmann 
354c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
355c2101297SDaniel Borkmann 	if (IS_ERR(map))
356c2101297SDaniel Borkmann 		return map;
357c2101297SDaniel Borkmann 
35892117d84SAlexei Starovoitov 	map = bpf_map_inc(map, true);
359c2101297SDaniel Borkmann 	fdput(f);
360db20fd2bSAlexei Starovoitov 
361db20fd2bSAlexei Starovoitov 	return map;
362db20fd2bSAlexei Starovoitov }
363db20fd2bSAlexei Starovoitov 
364bd5f5f4eSMartin KaFai Lau /* map_idr_lock should have been held */
365bd5f5f4eSMartin KaFai Lau static struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map,
366bd5f5f4eSMartin KaFai Lau 					    bool uref)
367bd5f5f4eSMartin KaFai Lau {
368bd5f5f4eSMartin KaFai Lau 	int refold;
369bd5f5f4eSMartin KaFai Lau 
370bd5f5f4eSMartin KaFai Lau 	refold = __atomic_add_unless(&map->refcnt, 1, 0);
371bd5f5f4eSMartin KaFai Lau 
372bd5f5f4eSMartin KaFai Lau 	if (refold >= BPF_MAX_REFCNT) {
373bd5f5f4eSMartin KaFai Lau 		__bpf_map_put(map, false);
374bd5f5f4eSMartin KaFai Lau 		return ERR_PTR(-EBUSY);
375bd5f5f4eSMartin KaFai Lau 	}
376bd5f5f4eSMartin KaFai Lau 
377bd5f5f4eSMartin KaFai Lau 	if (!refold)
378bd5f5f4eSMartin KaFai Lau 		return ERR_PTR(-ENOENT);
379bd5f5f4eSMartin KaFai Lau 
380bd5f5f4eSMartin KaFai Lau 	if (uref)
381bd5f5f4eSMartin KaFai Lau 		atomic_inc(&map->usercnt);
382bd5f5f4eSMartin KaFai Lau 
383bd5f5f4eSMartin KaFai Lau 	return map;
384bd5f5f4eSMartin KaFai Lau }
385bd5f5f4eSMartin KaFai Lau 
386b8cdc051SAlexei Starovoitov int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
387b8cdc051SAlexei Starovoitov {
388b8cdc051SAlexei Starovoitov 	return -ENOTSUPP;
389b8cdc051SAlexei Starovoitov }
390b8cdc051SAlexei Starovoitov 
391db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
392db20fd2bSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD value
393db20fd2bSAlexei Starovoitov 
394db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr)
395db20fd2bSAlexei Starovoitov {
396535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
397535e7b4bSMickaël Salaün 	void __user *uvalue = u64_to_user_ptr(attr->value);
398db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
399db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
4008ebe667cSAlexei Starovoitov 	void *key, *value, *ptr;
40115a07b33SAlexei Starovoitov 	u32 value_size;
402592867bfSDaniel Borkmann 	struct fd f;
403db20fd2bSAlexei Starovoitov 	int err;
404db20fd2bSAlexei Starovoitov 
405db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
406db20fd2bSAlexei Starovoitov 		return -EINVAL;
407db20fd2bSAlexei Starovoitov 
408592867bfSDaniel Borkmann 	f = fdget(ufd);
409c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
410db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
411db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
412db20fd2bSAlexei Starovoitov 
413e4448ed8SAl Viro 	key = memdup_user(ukey, map->key_size);
414e4448ed8SAl Viro 	if (IS_ERR(key)) {
415e4448ed8SAl Viro 		err = PTR_ERR(key);
416db20fd2bSAlexei Starovoitov 		goto err_put;
417e4448ed8SAl Viro 	}
418db20fd2bSAlexei Starovoitov 
41915a07b33SAlexei Starovoitov 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
4208f844938SMartin KaFai Lau 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
42115a07b33SAlexei Starovoitov 	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
42215a07b33SAlexei Starovoitov 		value_size = round_up(map->value_size, 8) * num_possible_cpus();
42314dc6f04SMartin KaFai Lau 	else if (IS_FD_MAP(map))
42414dc6f04SMartin KaFai Lau 		value_size = sizeof(u32);
42515a07b33SAlexei Starovoitov 	else
42615a07b33SAlexei Starovoitov 		value_size = map->value_size;
42715a07b33SAlexei Starovoitov 
4288ebe667cSAlexei Starovoitov 	err = -ENOMEM;
42915a07b33SAlexei Starovoitov 	value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
430db20fd2bSAlexei Starovoitov 	if (!value)
4318ebe667cSAlexei Starovoitov 		goto free_key;
4328ebe667cSAlexei Starovoitov 
4338f844938SMartin KaFai Lau 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
4348f844938SMartin KaFai Lau 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
43515a07b33SAlexei Starovoitov 		err = bpf_percpu_hash_copy(map, key, value);
43615a07b33SAlexei Starovoitov 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
43715a07b33SAlexei Starovoitov 		err = bpf_percpu_array_copy(map, key, value);
438557c0c6eSAlexei Starovoitov 	} else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) {
439557c0c6eSAlexei Starovoitov 		err = bpf_stackmap_copy(map, key, value);
44014dc6f04SMartin KaFai Lau 	} else if (IS_FD_ARRAY(map)) {
44114dc6f04SMartin KaFai Lau 		err = bpf_fd_array_map_lookup_elem(map, key, value);
44214dc6f04SMartin KaFai Lau 	} else if (IS_FD_HASH(map)) {
44314dc6f04SMartin KaFai Lau 		err = bpf_fd_htab_map_lookup_elem(map, key, value);
44415a07b33SAlexei Starovoitov 	} else {
4458ebe667cSAlexei Starovoitov 		rcu_read_lock();
4468ebe667cSAlexei Starovoitov 		ptr = map->ops->map_lookup_elem(map, key);
4478ebe667cSAlexei Starovoitov 		if (ptr)
44815a07b33SAlexei Starovoitov 			memcpy(value, ptr, value_size);
4498ebe667cSAlexei Starovoitov 		rcu_read_unlock();
45015a07b33SAlexei Starovoitov 		err = ptr ? 0 : -ENOENT;
45115a07b33SAlexei Starovoitov 	}
4528ebe667cSAlexei Starovoitov 
45315a07b33SAlexei Starovoitov 	if (err)
4548ebe667cSAlexei Starovoitov 		goto free_value;
455db20fd2bSAlexei Starovoitov 
456db20fd2bSAlexei Starovoitov 	err = -EFAULT;
45715a07b33SAlexei Starovoitov 	if (copy_to_user(uvalue, value, value_size) != 0)
4588ebe667cSAlexei Starovoitov 		goto free_value;
459db20fd2bSAlexei Starovoitov 
460a67edbf4SDaniel Borkmann 	trace_bpf_map_lookup_elem(map, ufd, key, value);
461db20fd2bSAlexei Starovoitov 	err = 0;
462db20fd2bSAlexei Starovoitov 
4638ebe667cSAlexei Starovoitov free_value:
4648ebe667cSAlexei Starovoitov 	kfree(value);
465db20fd2bSAlexei Starovoitov free_key:
466db20fd2bSAlexei Starovoitov 	kfree(key);
467db20fd2bSAlexei Starovoitov err_put:
468db20fd2bSAlexei Starovoitov 	fdput(f);
469db20fd2bSAlexei Starovoitov 	return err;
470db20fd2bSAlexei Starovoitov }
471db20fd2bSAlexei Starovoitov 
4723274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags
473db20fd2bSAlexei Starovoitov 
474db20fd2bSAlexei Starovoitov static int map_update_elem(union bpf_attr *attr)
475db20fd2bSAlexei Starovoitov {
476535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
477535e7b4bSMickaël Salaün 	void __user *uvalue = u64_to_user_ptr(attr->value);
478db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
479db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
480db20fd2bSAlexei Starovoitov 	void *key, *value;
48115a07b33SAlexei Starovoitov 	u32 value_size;
482592867bfSDaniel Borkmann 	struct fd f;
483db20fd2bSAlexei Starovoitov 	int err;
484db20fd2bSAlexei Starovoitov 
485db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM))
486db20fd2bSAlexei Starovoitov 		return -EINVAL;
487db20fd2bSAlexei Starovoitov 
488592867bfSDaniel Borkmann 	f = fdget(ufd);
489c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
490db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
491db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
492db20fd2bSAlexei Starovoitov 
493e4448ed8SAl Viro 	key = memdup_user(ukey, map->key_size);
494e4448ed8SAl Viro 	if (IS_ERR(key)) {
495e4448ed8SAl Viro 		err = PTR_ERR(key);
496db20fd2bSAlexei Starovoitov 		goto err_put;
497e4448ed8SAl Viro 	}
498db20fd2bSAlexei Starovoitov 
49915a07b33SAlexei Starovoitov 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
5008f844938SMartin KaFai Lau 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
50115a07b33SAlexei Starovoitov 	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
50215a07b33SAlexei Starovoitov 		value_size = round_up(map->value_size, 8) * num_possible_cpus();
50315a07b33SAlexei Starovoitov 	else
50415a07b33SAlexei Starovoitov 		value_size = map->value_size;
50515a07b33SAlexei Starovoitov 
506db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
50715a07b33SAlexei Starovoitov 	value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
508db20fd2bSAlexei Starovoitov 	if (!value)
509db20fd2bSAlexei Starovoitov 		goto free_key;
510db20fd2bSAlexei Starovoitov 
511db20fd2bSAlexei Starovoitov 	err = -EFAULT;
51215a07b33SAlexei Starovoitov 	if (copy_from_user(value, uvalue, value_size) != 0)
513db20fd2bSAlexei Starovoitov 		goto free_value;
514db20fd2bSAlexei Starovoitov 
515b121d1e7SAlexei Starovoitov 	/* must increment bpf_prog_active to avoid kprobe+bpf triggering from
516b121d1e7SAlexei Starovoitov 	 * inside bpf map update or delete otherwise deadlocks are possible
517b121d1e7SAlexei Starovoitov 	 */
518b121d1e7SAlexei Starovoitov 	preempt_disable();
519b121d1e7SAlexei Starovoitov 	__this_cpu_inc(bpf_prog_active);
5208f844938SMartin KaFai Lau 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
5218f844938SMartin KaFai Lau 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
52215a07b33SAlexei Starovoitov 		err = bpf_percpu_hash_update(map, key, value, attr->flags);
52315a07b33SAlexei Starovoitov 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
52415a07b33SAlexei Starovoitov 		err = bpf_percpu_array_update(map, key, value, attr->flags);
525d056a788SDaniel Borkmann 	} else if (map->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY ||
5264ed8ec52SMartin KaFai Lau 		   map->map_type == BPF_MAP_TYPE_PROG_ARRAY ||
52756f668dfSMartin KaFai Lau 		   map->map_type == BPF_MAP_TYPE_CGROUP_ARRAY ||
52856f668dfSMartin KaFai Lau 		   map->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) {
529d056a788SDaniel Borkmann 		rcu_read_lock();
530d056a788SDaniel Borkmann 		err = bpf_fd_array_map_update_elem(map, f.file, key, value,
531d056a788SDaniel Borkmann 						   attr->flags);
532d056a788SDaniel Borkmann 		rcu_read_unlock();
533bcc6b1b7SMartin KaFai Lau 	} else if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) {
534bcc6b1b7SMartin KaFai Lau 		rcu_read_lock();
535bcc6b1b7SMartin KaFai Lau 		err = bpf_fd_htab_map_update_elem(map, f.file, key, value,
536bcc6b1b7SMartin KaFai Lau 						  attr->flags);
537bcc6b1b7SMartin KaFai Lau 		rcu_read_unlock();
53815a07b33SAlexei Starovoitov 	} else {
539db20fd2bSAlexei Starovoitov 		rcu_read_lock();
5403274f520SAlexei Starovoitov 		err = map->ops->map_update_elem(map, key, value, attr->flags);
541db20fd2bSAlexei Starovoitov 		rcu_read_unlock();
54215a07b33SAlexei Starovoitov 	}
543b121d1e7SAlexei Starovoitov 	__this_cpu_dec(bpf_prog_active);
544b121d1e7SAlexei Starovoitov 	preempt_enable();
545db20fd2bSAlexei Starovoitov 
546a67edbf4SDaniel Borkmann 	if (!err)
547a67edbf4SDaniel Borkmann 		trace_bpf_map_update_elem(map, ufd, key, value);
548db20fd2bSAlexei Starovoitov free_value:
549db20fd2bSAlexei Starovoitov 	kfree(value);
550db20fd2bSAlexei Starovoitov free_key:
551db20fd2bSAlexei Starovoitov 	kfree(key);
552db20fd2bSAlexei Starovoitov err_put:
553db20fd2bSAlexei Starovoitov 	fdput(f);
554db20fd2bSAlexei Starovoitov 	return err;
555db20fd2bSAlexei Starovoitov }
556db20fd2bSAlexei Starovoitov 
557db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key
558db20fd2bSAlexei Starovoitov 
559db20fd2bSAlexei Starovoitov static int map_delete_elem(union bpf_attr *attr)
560db20fd2bSAlexei Starovoitov {
561535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
562db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
563db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
564592867bfSDaniel Borkmann 	struct fd f;
565db20fd2bSAlexei Starovoitov 	void *key;
566db20fd2bSAlexei Starovoitov 	int err;
567db20fd2bSAlexei Starovoitov 
568db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_DELETE_ELEM))
569db20fd2bSAlexei Starovoitov 		return -EINVAL;
570db20fd2bSAlexei Starovoitov 
571592867bfSDaniel Borkmann 	f = fdget(ufd);
572c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
573db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
574db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
575db20fd2bSAlexei Starovoitov 
576e4448ed8SAl Viro 	key = memdup_user(ukey, map->key_size);
577e4448ed8SAl Viro 	if (IS_ERR(key)) {
578e4448ed8SAl Viro 		err = PTR_ERR(key);
579db20fd2bSAlexei Starovoitov 		goto err_put;
580e4448ed8SAl Viro 	}
581db20fd2bSAlexei Starovoitov 
582b121d1e7SAlexei Starovoitov 	preempt_disable();
583b121d1e7SAlexei Starovoitov 	__this_cpu_inc(bpf_prog_active);
584db20fd2bSAlexei Starovoitov 	rcu_read_lock();
585db20fd2bSAlexei Starovoitov 	err = map->ops->map_delete_elem(map, key);
586db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
587b121d1e7SAlexei Starovoitov 	__this_cpu_dec(bpf_prog_active);
588b121d1e7SAlexei Starovoitov 	preempt_enable();
589db20fd2bSAlexei Starovoitov 
590a67edbf4SDaniel Borkmann 	if (!err)
591a67edbf4SDaniel Borkmann 		trace_bpf_map_delete_elem(map, ufd, key);
592db20fd2bSAlexei Starovoitov 	kfree(key);
593db20fd2bSAlexei Starovoitov err_put:
594db20fd2bSAlexei Starovoitov 	fdput(f);
595db20fd2bSAlexei Starovoitov 	return err;
596db20fd2bSAlexei Starovoitov }
597db20fd2bSAlexei Starovoitov 
598db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
599db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key
600db20fd2bSAlexei Starovoitov 
601db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr)
602db20fd2bSAlexei Starovoitov {
603535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
604535e7b4bSMickaël Salaün 	void __user *unext_key = u64_to_user_ptr(attr->next_key);
605db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
606db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
607db20fd2bSAlexei Starovoitov 	void *key, *next_key;
608592867bfSDaniel Borkmann 	struct fd f;
609db20fd2bSAlexei Starovoitov 	int err;
610db20fd2bSAlexei Starovoitov 
611db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY))
612db20fd2bSAlexei Starovoitov 		return -EINVAL;
613db20fd2bSAlexei Starovoitov 
614592867bfSDaniel Borkmann 	f = fdget(ufd);
615c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
616db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
617db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
618db20fd2bSAlexei Starovoitov 
6198fe45924STeng Qin 	if (ukey) {
620e4448ed8SAl Viro 		key = memdup_user(ukey, map->key_size);
621e4448ed8SAl Viro 		if (IS_ERR(key)) {
622e4448ed8SAl Viro 			err = PTR_ERR(key);
623db20fd2bSAlexei Starovoitov 			goto err_put;
624e4448ed8SAl Viro 		}
6258fe45924STeng Qin 	} else {
6268fe45924STeng Qin 		key = NULL;
6278fe45924STeng Qin 	}
628db20fd2bSAlexei Starovoitov 
629db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
630db20fd2bSAlexei Starovoitov 	next_key = kmalloc(map->key_size, GFP_USER);
631db20fd2bSAlexei Starovoitov 	if (!next_key)
632db20fd2bSAlexei Starovoitov 		goto free_key;
633db20fd2bSAlexei Starovoitov 
634db20fd2bSAlexei Starovoitov 	rcu_read_lock();
635db20fd2bSAlexei Starovoitov 	err = map->ops->map_get_next_key(map, key, next_key);
636db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
637db20fd2bSAlexei Starovoitov 	if (err)
638db20fd2bSAlexei Starovoitov 		goto free_next_key;
639db20fd2bSAlexei Starovoitov 
640db20fd2bSAlexei Starovoitov 	err = -EFAULT;
641db20fd2bSAlexei Starovoitov 	if (copy_to_user(unext_key, next_key, map->key_size) != 0)
642db20fd2bSAlexei Starovoitov 		goto free_next_key;
643db20fd2bSAlexei Starovoitov 
644a67edbf4SDaniel Borkmann 	trace_bpf_map_next_key(map, ufd, key, next_key);
645db20fd2bSAlexei Starovoitov 	err = 0;
646db20fd2bSAlexei Starovoitov 
647db20fd2bSAlexei Starovoitov free_next_key:
648db20fd2bSAlexei Starovoitov 	kfree(next_key);
649db20fd2bSAlexei Starovoitov free_key:
650db20fd2bSAlexei Starovoitov 	kfree(key);
651db20fd2bSAlexei Starovoitov err_put:
652db20fd2bSAlexei Starovoitov 	fdput(f);
653db20fd2bSAlexei Starovoitov 	return err;
654db20fd2bSAlexei Starovoitov }
655db20fd2bSAlexei Starovoitov 
656be9370a7SJohannes Berg static const struct bpf_verifier_ops * const bpf_prog_types[] = {
657be9370a7SJohannes Berg #define BPF_PROG_TYPE(_id, _ops) \
658be9370a7SJohannes Berg 	[_id] = &_ops,
65940077e0cSJohannes Berg #define BPF_MAP_TYPE(_id, _ops)
660be9370a7SJohannes Berg #include <linux/bpf_types.h>
661be9370a7SJohannes Berg #undef BPF_PROG_TYPE
66240077e0cSJohannes Berg #undef BPF_MAP_TYPE
663be9370a7SJohannes Berg };
66409756af4SAlexei Starovoitov 
66509756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
66609756af4SAlexei Starovoitov {
667be9370a7SJohannes Berg 	if (type >= ARRAY_SIZE(bpf_prog_types) || !bpf_prog_types[type])
668be9370a7SJohannes Berg 		return -EINVAL;
66909756af4SAlexei Starovoitov 
670be9370a7SJohannes Berg 	prog->aux->ops = bpf_prog_types[type];
67124701eceSDaniel Borkmann 	prog->type = type;
67209756af4SAlexei Starovoitov 	return 0;
67309756af4SAlexei Starovoitov }
67409756af4SAlexei Starovoitov 
67509756af4SAlexei Starovoitov /* drop refcnt on maps used by eBPF program and free auxilary data */
67609756af4SAlexei Starovoitov static void free_used_maps(struct bpf_prog_aux *aux)
67709756af4SAlexei Starovoitov {
67809756af4SAlexei Starovoitov 	int i;
67909756af4SAlexei Starovoitov 
68009756af4SAlexei Starovoitov 	for (i = 0; i < aux->used_map_cnt; i++)
68109756af4SAlexei Starovoitov 		bpf_map_put(aux->used_maps[i]);
68209756af4SAlexei Starovoitov 
68309756af4SAlexei Starovoitov 	kfree(aux->used_maps);
68409756af4SAlexei Starovoitov }
68509756af4SAlexei Starovoitov 
6865ccb071eSDaniel Borkmann int __bpf_prog_charge(struct user_struct *user, u32 pages)
6875ccb071eSDaniel Borkmann {
6885ccb071eSDaniel Borkmann 	unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
6895ccb071eSDaniel Borkmann 	unsigned long user_bufs;
6905ccb071eSDaniel Borkmann 
6915ccb071eSDaniel Borkmann 	if (user) {
6925ccb071eSDaniel Borkmann 		user_bufs = atomic_long_add_return(pages, &user->locked_vm);
6935ccb071eSDaniel Borkmann 		if (user_bufs > memlock_limit) {
6945ccb071eSDaniel Borkmann 			atomic_long_sub(pages, &user->locked_vm);
6955ccb071eSDaniel Borkmann 			return -EPERM;
6965ccb071eSDaniel Borkmann 		}
6975ccb071eSDaniel Borkmann 	}
6985ccb071eSDaniel Borkmann 
6995ccb071eSDaniel Borkmann 	return 0;
7005ccb071eSDaniel Borkmann }
7015ccb071eSDaniel Borkmann 
7025ccb071eSDaniel Borkmann void __bpf_prog_uncharge(struct user_struct *user, u32 pages)
7035ccb071eSDaniel Borkmann {
7045ccb071eSDaniel Borkmann 	if (user)
7055ccb071eSDaniel Borkmann 		atomic_long_sub(pages, &user->locked_vm);
7065ccb071eSDaniel Borkmann }
7075ccb071eSDaniel Borkmann 
708aaac3ba9SAlexei Starovoitov static int bpf_prog_charge_memlock(struct bpf_prog *prog)
709aaac3ba9SAlexei Starovoitov {
710aaac3ba9SAlexei Starovoitov 	struct user_struct *user = get_current_user();
7115ccb071eSDaniel Borkmann 	int ret;
712aaac3ba9SAlexei Starovoitov 
7135ccb071eSDaniel Borkmann 	ret = __bpf_prog_charge(user, prog->pages);
7145ccb071eSDaniel Borkmann 	if (ret) {
715aaac3ba9SAlexei Starovoitov 		free_uid(user);
7165ccb071eSDaniel Borkmann 		return ret;
717aaac3ba9SAlexei Starovoitov 	}
7185ccb071eSDaniel Borkmann 
719aaac3ba9SAlexei Starovoitov 	prog->aux->user = user;
720aaac3ba9SAlexei Starovoitov 	return 0;
721aaac3ba9SAlexei Starovoitov }
722aaac3ba9SAlexei Starovoitov 
723aaac3ba9SAlexei Starovoitov static void bpf_prog_uncharge_memlock(struct bpf_prog *prog)
724aaac3ba9SAlexei Starovoitov {
725aaac3ba9SAlexei Starovoitov 	struct user_struct *user = prog->aux->user;
726aaac3ba9SAlexei Starovoitov 
7275ccb071eSDaniel Borkmann 	__bpf_prog_uncharge(user, prog->pages);
728aaac3ba9SAlexei Starovoitov 	free_uid(user);
729aaac3ba9SAlexei Starovoitov }
730aaac3ba9SAlexei Starovoitov 
731dc4bb0e2SMartin KaFai Lau static int bpf_prog_alloc_id(struct bpf_prog *prog)
732dc4bb0e2SMartin KaFai Lau {
733dc4bb0e2SMartin KaFai Lau 	int id;
734dc4bb0e2SMartin KaFai Lau 
735dc4bb0e2SMartin KaFai Lau 	spin_lock_bh(&prog_idr_lock);
736dc4bb0e2SMartin KaFai Lau 	id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC);
737dc4bb0e2SMartin KaFai Lau 	if (id > 0)
738dc4bb0e2SMartin KaFai Lau 		prog->aux->id = id;
739dc4bb0e2SMartin KaFai Lau 	spin_unlock_bh(&prog_idr_lock);
740dc4bb0e2SMartin KaFai Lau 
741dc4bb0e2SMartin KaFai Lau 	/* id is in [1, INT_MAX) */
742dc4bb0e2SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
743dc4bb0e2SMartin KaFai Lau 		return -ENOSPC;
744dc4bb0e2SMartin KaFai Lau 
745dc4bb0e2SMartin KaFai Lau 	return id > 0 ? 0 : id;
746dc4bb0e2SMartin KaFai Lau }
747dc4bb0e2SMartin KaFai Lau 
748b16d9aa4SMartin KaFai Lau static void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
749dc4bb0e2SMartin KaFai Lau {
750dc4bb0e2SMartin KaFai Lau 	/* cBPF to eBPF migrations are currently not in the idr store. */
751dc4bb0e2SMartin KaFai Lau 	if (!prog->aux->id)
752dc4bb0e2SMartin KaFai Lau 		return;
753dc4bb0e2SMartin KaFai Lau 
754b16d9aa4SMartin KaFai Lau 	if (do_idr_lock)
755dc4bb0e2SMartin KaFai Lau 		spin_lock_bh(&prog_idr_lock);
756b16d9aa4SMartin KaFai Lau 	else
757b16d9aa4SMartin KaFai Lau 		__acquire(&prog_idr_lock);
758b16d9aa4SMartin KaFai Lau 
759dc4bb0e2SMartin KaFai Lau 	idr_remove(&prog_idr, prog->aux->id);
760b16d9aa4SMartin KaFai Lau 
761b16d9aa4SMartin KaFai Lau 	if (do_idr_lock)
762dc4bb0e2SMartin KaFai Lau 		spin_unlock_bh(&prog_idr_lock);
763b16d9aa4SMartin KaFai Lau 	else
764b16d9aa4SMartin KaFai Lau 		__release(&prog_idr_lock);
765dc4bb0e2SMartin KaFai Lau }
766dc4bb0e2SMartin KaFai Lau 
7671aacde3dSDaniel Borkmann static void __bpf_prog_put_rcu(struct rcu_head *rcu)
768abf2e7d6SAlexei Starovoitov {
769abf2e7d6SAlexei Starovoitov 	struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
770abf2e7d6SAlexei Starovoitov 
771abf2e7d6SAlexei Starovoitov 	free_used_maps(aux);
772aaac3ba9SAlexei Starovoitov 	bpf_prog_uncharge_memlock(aux->prog);
773abf2e7d6SAlexei Starovoitov 	bpf_prog_free(aux->prog);
774abf2e7d6SAlexei Starovoitov }
775abf2e7d6SAlexei Starovoitov 
776b16d9aa4SMartin KaFai Lau static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock)
77709756af4SAlexei Starovoitov {
778a67edbf4SDaniel Borkmann 	if (atomic_dec_and_test(&prog->aux->refcnt)) {
779a67edbf4SDaniel Borkmann 		trace_bpf_prog_put_rcu(prog);
78034ad5580SMartin KaFai Lau 		/* bpf_prog_free_id() must be called first */
781b16d9aa4SMartin KaFai Lau 		bpf_prog_free_id(prog, do_idr_lock);
78274451e66SDaniel Borkmann 		bpf_prog_kallsyms_del(prog);
7831aacde3dSDaniel Borkmann 		call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
78409756af4SAlexei Starovoitov 	}
785a67edbf4SDaniel Borkmann }
786b16d9aa4SMartin KaFai Lau 
787b16d9aa4SMartin KaFai Lau void bpf_prog_put(struct bpf_prog *prog)
788b16d9aa4SMartin KaFai Lau {
789b16d9aa4SMartin KaFai Lau 	__bpf_prog_put(prog, true);
790b16d9aa4SMartin KaFai Lau }
791e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put);
79209756af4SAlexei Starovoitov 
79309756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp)
79409756af4SAlexei Starovoitov {
79509756af4SAlexei Starovoitov 	struct bpf_prog *prog = filp->private_data;
79609756af4SAlexei Starovoitov 
7971aacde3dSDaniel Borkmann 	bpf_prog_put(prog);
79809756af4SAlexei Starovoitov 	return 0;
79909756af4SAlexei Starovoitov }
80009756af4SAlexei Starovoitov 
8017bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
8027bd509e3SDaniel Borkmann static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp)
8037bd509e3SDaniel Borkmann {
8047bd509e3SDaniel Borkmann 	const struct bpf_prog *prog = filp->private_data;
805f1f7714eSDaniel Borkmann 	char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
8067bd509e3SDaniel Borkmann 
807f1f7714eSDaniel Borkmann 	bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
8087bd509e3SDaniel Borkmann 	seq_printf(m,
8097bd509e3SDaniel Borkmann 		   "prog_type:\t%u\n"
8107bd509e3SDaniel Borkmann 		   "prog_jited:\t%u\n"
811f1f7714eSDaniel Borkmann 		   "prog_tag:\t%s\n"
8127bd509e3SDaniel Borkmann 		   "memlock:\t%llu\n",
8137bd509e3SDaniel Borkmann 		   prog->type,
8147bd509e3SDaniel Borkmann 		   prog->jited,
815f1f7714eSDaniel Borkmann 		   prog_tag,
8167bd509e3SDaniel Borkmann 		   prog->pages * 1ULL << PAGE_SHIFT);
8177bd509e3SDaniel Borkmann }
8187bd509e3SDaniel Borkmann #endif
8197bd509e3SDaniel Borkmann 
82009756af4SAlexei Starovoitov static const struct file_operations bpf_prog_fops = {
8217bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
8227bd509e3SDaniel Borkmann 	.show_fdinfo	= bpf_prog_show_fdinfo,
8237bd509e3SDaniel Borkmann #endif
82409756af4SAlexei Starovoitov 	.release	= bpf_prog_release,
82509756af4SAlexei Starovoitov };
82609756af4SAlexei Starovoitov 
827b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog)
828aa79781bSDaniel Borkmann {
829aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog,
830aa79781bSDaniel Borkmann 				O_RDWR | O_CLOEXEC);
831aa79781bSDaniel Borkmann }
832aa79781bSDaniel Borkmann 
833113214beSDaniel Borkmann static struct bpf_prog *____bpf_prog_get(struct fd f)
83409756af4SAlexei Starovoitov {
83509756af4SAlexei Starovoitov 	if (!f.file)
83609756af4SAlexei Starovoitov 		return ERR_PTR(-EBADF);
83709756af4SAlexei Starovoitov 	if (f.file->f_op != &bpf_prog_fops) {
83809756af4SAlexei Starovoitov 		fdput(f);
83909756af4SAlexei Starovoitov 		return ERR_PTR(-EINVAL);
84009756af4SAlexei Starovoitov 	}
84109756af4SAlexei Starovoitov 
842c2101297SDaniel Borkmann 	return f.file->private_data;
84309756af4SAlexei Starovoitov }
84409756af4SAlexei Starovoitov 
84559d3656dSBrenden Blanco struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i)
84692117d84SAlexei Starovoitov {
84759d3656dSBrenden Blanco 	if (atomic_add_return(i, &prog->aux->refcnt) > BPF_MAX_REFCNT) {
84859d3656dSBrenden Blanco 		atomic_sub(i, &prog->aux->refcnt);
84992117d84SAlexei Starovoitov 		return ERR_PTR(-EBUSY);
85092117d84SAlexei Starovoitov 	}
85192117d84SAlexei Starovoitov 	return prog;
85292117d84SAlexei Starovoitov }
85359d3656dSBrenden Blanco EXPORT_SYMBOL_GPL(bpf_prog_add);
85459d3656dSBrenden Blanco 
855c540594fSDaniel Borkmann void bpf_prog_sub(struct bpf_prog *prog, int i)
856c540594fSDaniel Borkmann {
857c540594fSDaniel Borkmann 	/* Only to be used for undoing previous bpf_prog_add() in some
858c540594fSDaniel Borkmann 	 * error path. We still know that another entity in our call
859c540594fSDaniel Borkmann 	 * path holds a reference to the program, thus atomic_sub() can
860c540594fSDaniel Borkmann 	 * be safely used in such cases!
861c540594fSDaniel Borkmann 	 */
862c540594fSDaniel Borkmann 	WARN_ON(atomic_sub_return(i, &prog->aux->refcnt) == 0);
863c540594fSDaniel Borkmann }
864c540594fSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_sub);
865c540594fSDaniel Borkmann 
86659d3656dSBrenden Blanco struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog)
86759d3656dSBrenden Blanco {
86859d3656dSBrenden Blanco 	return bpf_prog_add(prog, 1);
86959d3656dSBrenden Blanco }
87097bc402dSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_inc);
87192117d84SAlexei Starovoitov 
872b16d9aa4SMartin KaFai Lau /* prog_idr_lock should have been held */
873b16d9aa4SMartin KaFai Lau static struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog)
874b16d9aa4SMartin KaFai Lau {
875b16d9aa4SMartin KaFai Lau 	int refold;
876b16d9aa4SMartin KaFai Lau 
877b16d9aa4SMartin KaFai Lau 	refold = __atomic_add_unless(&prog->aux->refcnt, 1, 0);
878b16d9aa4SMartin KaFai Lau 
879b16d9aa4SMartin KaFai Lau 	if (refold >= BPF_MAX_REFCNT) {
880b16d9aa4SMartin KaFai Lau 		__bpf_prog_put(prog, false);
881b16d9aa4SMartin KaFai Lau 		return ERR_PTR(-EBUSY);
882b16d9aa4SMartin KaFai Lau 	}
883b16d9aa4SMartin KaFai Lau 
884b16d9aa4SMartin KaFai Lau 	if (!refold)
885b16d9aa4SMartin KaFai Lau 		return ERR_PTR(-ENOENT);
886b16d9aa4SMartin KaFai Lau 
887b16d9aa4SMartin KaFai Lau 	return prog;
888b16d9aa4SMartin KaFai Lau }
889b16d9aa4SMartin KaFai Lau 
890113214beSDaniel Borkmann static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *type)
89109756af4SAlexei Starovoitov {
89209756af4SAlexei Starovoitov 	struct fd f = fdget(ufd);
89309756af4SAlexei Starovoitov 	struct bpf_prog *prog;
89409756af4SAlexei Starovoitov 
895113214beSDaniel Borkmann 	prog = ____bpf_prog_get(f);
89609756af4SAlexei Starovoitov 	if (IS_ERR(prog))
89709756af4SAlexei Starovoitov 		return prog;
898113214beSDaniel Borkmann 	if (type && prog->type != *type) {
899113214beSDaniel Borkmann 		prog = ERR_PTR(-EINVAL);
900113214beSDaniel Borkmann 		goto out;
901113214beSDaniel Borkmann 	}
90209756af4SAlexei Starovoitov 
90392117d84SAlexei Starovoitov 	prog = bpf_prog_inc(prog);
904113214beSDaniel Borkmann out:
90509756af4SAlexei Starovoitov 	fdput(f);
90609756af4SAlexei Starovoitov 	return prog;
90709756af4SAlexei Starovoitov }
908113214beSDaniel Borkmann 
909113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get(u32 ufd)
910113214beSDaniel Borkmann {
911113214beSDaniel Borkmann 	return __bpf_prog_get(ufd, NULL);
912113214beSDaniel Borkmann }
913113214beSDaniel Borkmann 
914113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type)
915113214beSDaniel Borkmann {
916a67edbf4SDaniel Borkmann 	struct bpf_prog *prog = __bpf_prog_get(ufd, &type);
917a67edbf4SDaniel Borkmann 
918a67edbf4SDaniel Borkmann 	if (!IS_ERR(prog))
919a67edbf4SDaniel Borkmann 		trace_bpf_prog_get_type(prog);
920a67edbf4SDaniel Borkmann 	return prog;
921113214beSDaniel Borkmann }
922113214beSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_get_type);
92309756af4SAlexei Starovoitov 
92409756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
925e07b98d9SDavid S. Miller #define	BPF_PROG_LOAD_LAST_FIELD prog_flags
92609756af4SAlexei Starovoitov 
92709756af4SAlexei Starovoitov static int bpf_prog_load(union bpf_attr *attr)
92809756af4SAlexei Starovoitov {
92909756af4SAlexei Starovoitov 	enum bpf_prog_type type = attr->prog_type;
93009756af4SAlexei Starovoitov 	struct bpf_prog *prog;
93109756af4SAlexei Starovoitov 	int err;
93209756af4SAlexei Starovoitov 	char license[128];
93309756af4SAlexei Starovoitov 	bool is_gpl;
93409756af4SAlexei Starovoitov 
93509756af4SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_LOAD))
93609756af4SAlexei Starovoitov 		return -EINVAL;
93709756af4SAlexei Starovoitov 
938e07b98d9SDavid S. Miller 	if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT)
939e07b98d9SDavid S. Miller 		return -EINVAL;
940e07b98d9SDavid S. Miller 
94109756af4SAlexei Starovoitov 	/* copy eBPF program license from user space */
942535e7b4bSMickaël Salaün 	if (strncpy_from_user(license, u64_to_user_ptr(attr->license),
94309756af4SAlexei Starovoitov 			      sizeof(license) - 1) < 0)
94409756af4SAlexei Starovoitov 		return -EFAULT;
94509756af4SAlexei Starovoitov 	license[sizeof(license) - 1] = 0;
94609756af4SAlexei Starovoitov 
94709756af4SAlexei Starovoitov 	/* eBPF programs must be GPL compatible to use GPL-ed functions */
94809756af4SAlexei Starovoitov 	is_gpl = license_is_gpl_compatible(license);
94909756af4SAlexei Starovoitov 
950ef0915caSDaniel Borkmann 	if (attr->insn_cnt == 0 || attr->insn_cnt > BPF_MAXINSNS)
951ef0915caSDaniel Borkmann 		return -E2BIG;
95209756af4SAlexei Starovoitov 
9532541517cSAlexei Starovoitov 	if (type == BPF_PROG_TYPE_KPROBE &&
9542541517cSAlexei Starovoitov 	    attr->kern_version != LINUX_VERSION_CODE)
9552541517cSAlexei Starovoitov 		return -EINVAL;
9562541517cSAlexei Starovoitov 
95780b7d819SChenbo Feng 	if (type != BPF_PROG_TYPE_SOCKET_FILTER &&
95880b7d819SChenbo Feng 	    type != BPF_PROG_TYPE_CGROUP_SKB &&
95980b7d819SChenbo Feng 	    !capable(CAP_SYS_ADMIN))
9601be7f75dSAlexei Starovoitov 		return -EPERM;
9611be7f75dSAlexei Starovoitov 
96209756af4SAlexei Starovoitov 	/* plain bpf_prog allocation */
96309756af4SAlexei Starovoitov 	prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
96409756af4SAlexei Starovoitov 	if (!prog)
96509756af4SAlexei Starovoitov 		return -ENOMEM;
96609756af4SAlexei Starovoitov 
967aaac3ba9SAlexei Starovoitov 	err = bpf_prog_charge_memlock(prog);
968aaac3ba9SAlexei Starovoitov 	if (err)
969aaac3ba9SAlexei Starovoitov 		goto free_prog_nouncharge;
970aaac3ba9SAlexei Starovoitov 
97109756af4SAlexei Starovoitov 	prog->len = attr->insn_cnt;
97209756af4SAlexei Starovoitov 
97309756af4SAlexei Starovoitov 	err = -EFAULT;
974535e7b4bSMickaël Salaün 	if (copy_from_user(prog->insns, u64_to_user_ptr(attr->insns),
975aafe6ae9SDaniel Borkmann 			   bpf_prog_insn_size(prog)) != 0)
97609756af4SAlexei Starovoitov 		goto free_prog;
97709756af4SAlexei Starovoitov 
97809756af4SAlexei Starovoitov 	prog->orig_prog = NULL;
979a91263d5SDaniel Borkmann 	prog->jited = 0;
98009756af4SAlexei Starovoitov 
98109756af4SAlexei Starovoitov 	atomic_set(&prog->aux->refcnt, 1);
982a91263d5SDaniel Borkmann 	prog->gpl_compatible = is_gpl ? 1 : 0;
98309756af4SAlexei Starovoitov 
98409756af4SAlexei Starovoitov 	/* find program type: socket_filter vs tracing_filter */
98509756af4SAlexei Starovoitov 	err = find_prog_type(type, prog);
98609756af4SAlexei Starovoitov 	if (err < 0)
98709756af4SAlexei Starovoitov 		goto free_prog;
98809756af4SAlexei Starovoitov 
98909756af4SAlexei Starovoitov 	/* run eBPF verifier */
9909bac3d6dSAlexei Starovoitov 	err = bpf_check(&prog, attr);
99109756af4SAlexei Starovoitov 	if (err < 0)
99209756af4SAlexei Starovoitov 		goto free_used_maps;
99309756af4SAlexei Starovoitov 
99409756af4SAlexei Starovoitov 	/* eBPF program is ready to be JITed */
995d1c55ab5SDaniel Borkmann 	prog = bpf_prog_select_runtime(prog, &err);
99604fd61abSAlexei Starovoitov 	if (err < 0)
99704fd61abSAlexei Starovoitov 		goto free_used_maps;
99809756af4SAlexei Starovoitov 
999dc4bb0e2SMartin KaFai Lau 	err = bpf_prog_alloc_id(prog);
1000dc4bb0e2SMartin KaFai Lau 	if (err)
1001dc4bb0e2SMartin KaFai Lau 		goto free_used_maps;
1002dc4bb0e2SMartin KaFai Lau 
1003aa79781bSDaniel Borkmann 	err = bpf_prog_new_fd(prog);
1004b16d9aa4SMartin KaFai Lau 	if (err < 0) {
1005b16d9aa4SMartin KaFai Lau 		/* failed to allocate fd.
1006b16d9aa4SMartin KaFai Lau 		 * bpf_prog_put() is needed because the above
1007b16d9aa4SMartin KaFai Lau 		 * bpf_prog_alloc_id() has published the prog
1008b16d9aa4SMartin KaFai Lau 		 * to the userspace and the userspace may
1009b16d9aa4SMartin KaFai Lau 		 * have refcnt-ed it through BPF_PROG_GET_FD_BY_ID.
1010b16d9aa4SMartin KaFai Lau 		 */
1011b16d9aa4SMartin KaFai Lau 		bpf_prog_put(prog);
1012b16d9aa4SMartin KaFai Lau 		return err;
1013b16d9aa4SMartin KaFai Lau 	}
101409756af4SAlexei Starovoitov 
101574451e66SDaniel Borkmann 	bpf_prog_kallsyms_add(prog);
1016a67edbf4SDaniel Borkmann 	trace_bpf_prog_load(prog, err);
101709756af4SAlexei Starovoitov 	return err;
101809756af4SAlexei Starovoitov 
101909756af4SAlexei Starovoitov free_used_maps:
102009756af4SAlexei Starovoitov 	free_used_maps(prog->aux);
102109756af4SAlexei Starovoitov free_prog:
1022aaac3ba9SAlexei Starovoitov 	bpf_prog_uncharge_memlock(prog);
1023aaac3ba9SAlexei Starovoitov free_prog_nouncharge:
102409756af4SAlexei Starovoitov 	bpf_prog_free(prog);
102509756af4SAlexei Starovoitov 	return err;
102609756af4SAlexei Starovoitov }
102709756af4SAlexei Starovoitov 
1028b2197755SDaniel Borkmann #define BPF_OBJ_LAST_FIELD bpf_fd
1029b2197755SDaniel Borkmann 
1030b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr)
1031b2197755SDaniel Borkmann {
1032b2197755SDaniel Borkmann 	if (CHECK_ATTR(BPF_OBJ))
1033b2197755SDaniel Borkmann 		return -EINVAL;
1034b2197755SDaniel Borkmann 
1035535e7b4bSMickaël Salaün 	return bpf_obj_pin_user(attr->bpf_fd, u64_to_user_ptr(attr->pathname));
1036b2197755SDaniel Borkmann }
1037b2197755SDaniel Borkmann 
1038b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr)
1039b2197755SDaniel Borkmann {
1040b2197755SDaniel Borkmann 	if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0)
1041b2197755SDaniel Borkmann 		return -EINVAL;
1042b2197755SDaniel Borkmann 
1043535e7b4bSMickaël Salaün 	return bpf_obj_get_user(u64_to_user_ptr(attr->pathname));
1044b2197755SDaniel Borkmann }
1045b2197755SDaniel Borkmann 
1046f4324551SDaniel Mack #ifdef CONFIG_CGROUP_BPF
1047f4324551SDaniel Mack 
10487f677633SAlexei Starovoitov #define BPF_PROG_ATTACH_LAST_FIELD attach_flags
1049f4324551SDaniel Mack 
1050f4324551SDaniel Mack static int bpf_prog_attach(const union bpf_attr *attr)
1051f4324551SDaniel Mack {
10527f677633SAlexei Starovoitov 	enum bpf_prog_type ptype;
1053f4324551SDaniel Mack 	struct bpf_prog *prog;
1054f4324551SDaniel Mack 	struct cgroup *cgrp;
10557f677633SAlexei Starovoitov 	int ret;
1056f4324551SDaniel Mack 
1057f4324551SDaniel Mack 	if (!capable(CAP_NET_ADMIN))
1058f4324551SDaniel Mack 		return -EPERM;
1059f4324551SDaniel Mack 
1060f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_ATTACH))
1061f4324551SDaniel Mack 		return -EINVAL;
1062f4324551SDaniel Mack 
10637f677633SAlexei Starovoitov 	if (attr->attach_flags & ~BPF_F_ALLOW_OVERRIDE)
10647f677633SAlexei Starovoitov 		return -EINVAL;
10657f677633SAlexei Starovoitov 
1066f4324551SDaniel Mack 	switch (attr->attach_type) {
1067f4324551SDaniel Mack 	case BPF_CGROUP_INET_INGRESS:
1068f4324551SDaniel Mack 	case BPF_CGROUP_INET_EGRESS:
1069b2cd1257SDavid Ahern 		ptype = BPF_PROG_TYPE_CGROUP_SKB;
1070b2cd1257SDavid Ahern 		break;
107161023658SDavid Ahern 	case BPF_CGROUP_INET_SOCK_CREATE:
107261023658SDavid Ahern 		ptype = BPF_PROG_TYPE_CGROUP_SOCK;
107361023658SDavid Ahern 		break;
107440304b2aSLawrence Brakmo 	case BPF_CGROUP_SOCK_OPS:
107540304b2aSLawrence Brakmo 		ptype = BPF_PROG_TYPE_SOCK_OPS;
107640304b2aSLawrence Brakmo 		break;
1077b2cd1257SDavid Ahern 	default:
1078b2cd1257SDavid Ahern 		return -EINVAL;
1079b2cd1257SDavid Ahern 	}
1080b2cd1257SDavid Ahern 
1081b2cd1257SDavid Ahern 	prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
1082f4324551SDaniel Mack 	if (IS_ERR(prog))
1083f4324551SDaniel Mack 		return PTR_ERR(prog);
1084f4324551SDaniel Mack 
1085f4324551SDaniel Mack 	cgrp = cgroup_get_from_fd(attr->target_fd);
1086f4324551SDaniel Mack 	if (IS_ERR(cgrp)) {
1087f4324551SDaniel Mack 		bpf_prog_put(prog);
1088f4324551SDaniel Mack 		return PTR_ERR(cgrp);
1089f4324551SDaniel Mack 	}
1090f4324551SDaniel Mack 
10917f677633SAlexei Starovoitov 	ret = cgroup_bpf_update(cgrp, prog, attr->attach_type,
10927f677633SAlexei Starovoitov 				attr->attach_flags & BPF_F_ALLOW_OVERRIDE);
10937f677633SAlexei Starovoitov 	if (ret)
10947f677633SAlexei Starovoitov 		bpf_prog_put(prog);
1095f4324551SDaniel Mack 	cgroup_put(cgrp);
1096f4324551SDaniel Mack 
10977f677633SAlexei Starovoitov 	return ret;
1098f4324551SDaniel Mack }
1099f4324551SDaniel Mack 
1100f4324551SDaniel Mack #define BPF_PROG_DETACH_LAST_FIELD attach_type
1101f4324551SDaniel Mack 
1102f4324551SDaniel Mack static int bpf_prog_detach(const union bpf_attr *attr)
1103f4324551SDaniel Mack {
1104f4324551SDaniel Mack 	struct cgroup *cgrp;
11057f677633SAlexei Starovoitov 	int ret;
1106f4324551SDaniel Mack 
1107f4324551SDaniel Mack 	if (!capable(CAP_NET_ADMIN))
1108f4324551SDaniel Mack 		return -EPERM;
1109f4324551SDaniel Mack 
1110f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_DETACH))
1111f4324551SDaniel Mack 		return -EINVAL;
1112f4324551SDaniel Mack 
1113f4324551SDaniel Mack 	switch (attr->attach_type) {
1114f4324551SDaniel Mack 	case BPF_CGROUP_INET_INGRESS:
1115f4324551SDaniel Mack 	case BPF_CGROUP_INET_EGRESS:
111661023658SDavid Ahern 	case BPF_CGROUP_INET_SOCK_CREATE:
111740304b2aSLawrence Brakmo 	case BPF_CGROUP_SOCK_OPS:
1118f4324551SDaniel Mack 		cgrp = cgroup_get_from_fd(attr->target_fd);
1119f4324551SDaniel Mack 		if (IS_ERR(cgrp))
1120f4324551SDaniel Mack 			return PTR_ERR(cgrp);
1121f4324551SDaniel Mack 
11227f677633SAlexei Starovoitov 		ret = cgroup_bpf_update(cgrp, NULL, attr->attach_type, false);
1123f4324551SDaniel Mack 		cgroup_put(cgrp);
1124f4324551SDaniel Mack 		break;
1125f4324551SDaniel Mack 
1126f4324551SDaniel Mack 	default:
1127f4324551SDaniel Mack 		return -EINVAL;
1128f4324551SDaniel Mack 	}
1129f4324551SDaniel Mack 
11307f677633SAlexei Starovoitov 	return ret;
1131f4324551SDaniel Mack }
113240304b2aSLawrence Brakmo 
1133f4324551SDaniel Mack #endif /* CONFIG_CGROUP_BPF */
1134f4324551SDaniel Mack 
11351cf1cae9SAlexei Starovoitov #define BPF_PROG_TEST_RUN_LAST_FIELD test.duration
11361cf1cae9SAlexei Starovoitov 
11371cf1cae9SAlexei Starovoitov static int bpf_prog_test_run(const union bpf_attr *attr,
11381cf1cae9SAlexei Starovoitov 			     union bpf_attr __user *uattr)
11391cf1cae9SAlexei Starovoitov {
11401cf1cae9SAlexei Starovoitov 	struct bpf_prog *prog;
11411cf1cae9SAlexei Starovoitov 	int ret = -ENOTSUPP;
11421cf1cae9SAlexei Starovoitov 
11431cf1cae9SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_TEST_RUN))
11441cf1cae9SAlexei Starovoitov 		return -EINVAL;
11451cf1cae9SAlexei Starovoitov 
11461cf1cae9SAlexei Starovoitov 	prog = bpf_prog_get(attr->test.prog_fd);
11471cf1cae9SAlexei Starovoitov 	if (IS_ERR(prog))
11481cf1cae9SAlexei Starovoitov 		return PTR_ERR(prog);
11491cf1cae9SAlexei Starovoitov 
11501cf1cae9SAlexei Starovoitov 	if (prog->aux->ops->test_run)
11511cf1cae9SAlexei Starovoitov 		ret = prog->aux->ops->test_run(prog, attr, uattr);
11521cf1cae9SAlexei Starovoitov 
11531cf1cae9SAlexei Starovoitov 	bpf_prog_put(prog);
11541cf1cae9SAlexei Starovoitov 	return ret;
11551cf1cae9SAlexei Starovoitov }
11561cf1cae9SAlexei Starovoitov 
115734ad5580SMartin KaFai Lau #define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id
115834ad5580SMartin KaFai Lau 
115934ad5580SMartin KaFai Lau static int bpf_obj_get_next_id(const union bpf_attr *attr,
116034ad5580SMartin KaFai Lau 			       union bpf_attr __user *uattr,
116134ad5580SMartin KaFai Lau 			       struct idr *idr,
116234ad5580SMartin KaFai Lau 			       spinlock_t *lock)
116334ad5580SMartin KaFai Lau {
116434ad5580SMartin KaFai Lau 	u32 next_id = attr->start_id;
116534ad5580SMartin KaFai Lau 	int err = 0;
116634ad5580SMartin KaFai Lau 
116734ad5580SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX)
116834ad5580SMartin KaFai Lau 		return -EINVAL;
116934ad5580SMartin KaFai Lau 
117034ad5580SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
117134ad5580SMartin KaFai Lau 		return -EPERM;
117234ad5580SMartin KaFai Lau 
117334ad5580SMartin KaFai Lau 	next_id++;
117434ad5580SMartin KaFai Lau 	spin_lock_bh(lock);
117534ad5580SMartin KaFai Lau 	if (!idr_get_next(idr, &next_id))
117634ad5580SMartin KaFai Lau 		err = -ENOENT;
117734ad5580SMartin KaFai Lau 	spin_unlock_bh(lock);
117834ad5580SMartin KaFai Lau 
117934ad5580SMartin KaFai Lau 	if (!err)
118034ad5580SMartin KaFai Lau 		err = put_user(next_id, &uattr->next_id);
118134ad5580SMartin KaFai Lau 
118234ad5580SMartin KaFai Lau 	return err;
118334ad5580SMartin KaFai Lau }
118434ad5580SMartin KaFai Lau 
1185b16d9aa4SMartin KaFai Lau #define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id
1186b16d9aa4SMartin KaFai Lau 
1187b16d9aa4SMartin KaFai Lau static int bpf_prog_get_fd_by_id(const union bpf_attr *attr)
1188b16d9aa4SMartin KaFai Lau {
1189b16d9aa4SMartin KaFai Lau 	struct bpf_prog *prog;
1190b16d9aa4SMartin KaFai Lau 	u32 id = attr->prog_id;
1191b16d9aa4SMartin KaFai Lau 	int fd;
1192b16d9aa4SMartin KaFai Lau 
1193b16d9aa4SMartin KaFai Lau 	if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID))
1194b16d9aa4SMartin KaFai Lau 		return -EINVAL;
1195b16d9aa4SMartin KaFai Lau 
1196b16d9aa4SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
1197b16d9aa4SMartin KaFai Lau 		return -EPERM;
1198b16d9aa4SMartin KaFai Lau 
1199b16d9aa4SMartin KaFai Lau 	spin_lock_bh(&prog_idr_lock);
1200b16d9aa4SMartin KaFai Lau 	prog = idr_find(&prog_idr, id);
1201b16d9aa4SMartin KaFai Lau 	if (prog)
1202b16d9aa4SMartin KaFai Lau 		prog = bpf_prog_inc_not_zero(prog);
1203b16d9aa4SMartin KaFai Lau 	else
1204b16d9aa4SMartin KaFai Lau 		prog = ERR_PTR(-ENOENT);
1205b16d9aa4SMartin KaFai Lau 	spin_unlock_bh(&prog_idr_lock);
1206b16d9aa4SMartin KaFai Lau 
1207b16d9aa4SMartin KaFai Lau 	if (IS_ERR(prog))
1208b16d9aa4SMartin KaFai Lau 		return PTR_ERR(prog);
1209b16d9aa4SMartin KaFai Lau 
1210b16d9aa4SMartin KaFai Lau 	fd = bpf_prog_new_fd(prog);
1211b16d9aa4SMartin KaFai Lau 	if (fd < 0)
1212b16d9aa4SMartin KaFai Lau 		bpf_prog_put(prog);
1213b16d9aa4SMartin KaFai Lau 
1214b16d9aa4SMartin KaFai Lau 	return fd;
1215b16d9aa4SMartin KaFai Lau }
1216b16d9aa4SMartin KaFai Lau 
1217bd5f5f4eSMartin KaFai Lau #define BPF_MAP_GET_FD_BY_ID_LAST_FIELD map_id
1218bd5f5f4eSMartin KaFai Lau 
1219bd5f5f4eSMartin KaFai Lau static int bpf_map_get_fd_by_id(const union bpf_attr *attr)
1220bd5f5f4eSMartin KaFai Lau {
1221bd5f5f4eSMartin KaFai Lau 	struct bpf_map *map;
1222bd5f5f4eSMartin KaFai Lau 	u32 id = attr->map_id;
1223bd5f5f4eSMartin KaFai Lau 	int fd;
1224bd5f5f4eSMartin KaFai Lau 
1225bd5f5f4eSMartin KaFai Lau 	if (CHECK_ATTR(BPF_MAP_GET_FD_BY_ID))
1226bd5f5f4eSMartin KaFai Lau 		return -EINVAL;
1227bd5f5f4eSMartin KaFai Lau 
1228bd5f5f4eSMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
1229bd5f5f4eSMartin KaFai Lau 		return -EPERM;
1230bd5f5f4eSMartin KaFai Lau 
1231bd5f5f4eSMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
1232bd5f5f4eSMartin KaFai Lau 	map = idr_find(&map_idr, id);
1233bd5f5f4eSMartin KaFai Lau 	if (map)
1234bd5f5f4eSMartin KaFai Lau 		map = bpf_map_inc_not_zero(map, true);
1235bd5f5f4eSMartin KaFai Lau 	else
1236bd5f5f4eSMartin KaFai Lau 		map = ERR_PTR(-ENOENT);
1237bd5f5f4eSMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
1238bd5f5f4eSMartin KaFai Lau 
1239bd5f5f4eSMartin KaFai Lau 	if (IS_ERR(map))
1240bd5f5f4eSMartin KaFai Lau 		return PTR_ERR(map);
1241bd5f5f4eSMartin KaFai Lau 
1242bd5f5f4eSMartin KaFai Lau 	fd = bpf_map_new_fd(map);
1243bd5f5f4eSMartin KaFai Lau 	if (fd < 0)
1244bd5f5f4eSMartin KaFai Lau 		bpf_map_put(map);
1245bd5f5f4eSMartin KaFai Lau 
1246bd5f5f4eSMartin KaFai Lau 	return fd;
1247bd5f5f4eSMartin KaFai Lau }
1248bd5f5f4eSMartin KaFai Lau 
12491e270976SMartin KaFai Lau static int check_uarg_tail_zero(void __user *uaddr,
12501e270976SMartin KaFai Lau 				size_t expected_size,
12511e270976SMartin KaFai Lau 				size_t actual_size)
12521e270976SMartin KaFai Lau {
12531e270976SMartin KaFai Lau 	unsigned char __user *addr;
12541e270976SMartin KaFai Lau 	unsigned char __user *end;
12551e270976SMartin KaFai Lau 	unsigned char val;
12561e270976SMartin KaFai Lau 	int err;
12571e270976SMartin KaFai Lau 
12581e270976SMartin KaFai Lau 	if (actual_size <= expected_size)
12591e270976SMartin KaFai Lau 		return 0;
12601e270976SMartin KaFai Lau 
12611e270976SMartin KaFai Lau 	addr = uaddr + expected_size;
12621e270976SMartin KaFai Lau 	end  = uaddr + actual_size;
12631e270976SMartin KaFai Lau 
12641e270976SMartin KaFai Lau 	for (; addr < end; addr++) {
12651e270976SMartin KaFai Lau 		err = get_user(val, addr);
12661e270976SMartin KaFai Lau 		if (err)
12671e270976SMartin KaFai Lau 			return err;
12681e270976SMartin KaFai Lau 		if (val)
12691e270976SMartin KaFai Lau 			return -E2BIG;
12701e270976SMartin KaFai Lau 	}
12711e270976SMartin KaFai Lau 
12721e270976SMartin KaFai Lau 	return 0;
12731e270976SMartin KaFai Lau }
12741e270976SMartin KaFai Lau 
12751e270976SMartin KaFai Lau static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
12761e270976SMartin KaFai Lau 				   const union bpf_attr *attr,
12771e270976SMartin KaFai Lau 				   union bpf_attr __user *uattr)
12781e270976SMartin KaFai Lau {
12791e270976SMartin KaFai Lau 	struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info);
12801e270976SMartin KaFai Lau 	struct bpf_prog_info info = {};
12811e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
12821e270976SMartin KaFai Lau 	char __user *uinsns;
12831e270976SMartin KaFai Lau 	u32 ulen;
12841e270976SMartin KaFai Lau 	int err;
12851e270976SMartin KaFai Lau 
12861e270976SMartin KaFai Lau 	err = check_uarg_tail_zero(uinfo, sizeof(info), info_len);
12871e270976SMartin KaFai Lau 	if (err)
12881e270976SMartin KaFai Lau 		return err;
12891e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
12901e270976SMartin KaFai Lau 
12911e270976SMartin KaFai Lau 	if (copy_from_user(&info, uinfo, info_len))
129289b09689SDaniel Borkmann 		return -EFAULT;
12931e270976SMartin KaFai Lau 
12941e270976SMartin KaFai Lau 	info.type = prog->type;
12951e270976SMartin KaFai Lau 	info.id = prog->aux->id;
12961e270976SMartin KaFai Lau 
12971e270976SMartin KaFai Lau 	memcpy(info.tag, prog->tag, sizeof(prog->tag));
12981e270976SMartin KaFai Lau 
12991e270976SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN)) {
13001e270976SMartin KaFai Lau 		info.jited_prog_len = 0;
13011e270976SMartin KaFai Lau 		info.xlated_prog_len = 0;
13021e270976SMartin KaFai Lau 		goto done;
13031e270976SMartin KaFai Lau 	}
13041e270976SMartin KaFai Lau 
13051e270976SMartin KaFai Lau 	ulen = info.jited_prog_len;
13061e270976SMartin KaFai Lau 	info.jited_prog_len = prog->jited_len;
13071e270976SMartin KaFai Lau 	if (info.jited_prog_len && ulen) {
13081e270976SMartin KaFai Lau 		uinsns = u64_to_user_ptr(info.jited_prog_insns);
13091e270976SMartin KaFai Lau 		ulen = min_t(u32, info.jited_prog_len, ulen);
13101e270976SMartin KaFai Lau 		if (copy_to_user(uinsns, prog->bpf_func, ulen))
13111e270976SMartin KaFai Lau 			return -EFAULT;
13121e270976SMartin KaFai Lau 	}
13131e270976SMartin KaFai Lau 
13141e270976SMartin KaFai Lau 	ulen = info.xlated_prog_len;
1315*9975a54bSDaniel Borkmann 	info.xlated_prog_len = bpf_prog_insn_size(prog);
13161e270976SMartin KaFai Lau 	if (info.xlated_prog_len && ulen) {
13171e270976SMartin KaFai Lau 		uinsns = u64_to_user_ptr(info.xlated_prog_insns);
13181e270976SMartin KaFai Lau 		ulen = min_t(u32, info.xlated_prog_len, ulen);
13191e270976SMartin KaFai Lau 		if (copy_to_user(uinsns, prog->insnsi, ulen))
13201e270976SMartin KaFai Lau 			return -EFAULT;
13211e270976SMartin KaFai Lau 	}
13221e270976SMartin KaFai Lau 
13231e270976SMartin KaFai Lau done:
13241e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
13251e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
13261e270976SMartin KaFai Lau 		return -EFAULT;
13271e270976SMartin KaFai Lau 
13281e270976SMartin KaFai Lau 	return 0;
13291e270976SMartin KaFai Lau }
13301e270976SMartin KaFai Lau 
13311e270976SMartin KaFai Lau static int bpf_map_get_info_by_fd(struct bpf_map *map,
13321e270976SMartin KaFai Lau 				  const union bpf_attr *attr,
13331e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
13341e270976SMartin KaFai Lau {
13351e270976SMartin KaFai Lau 	struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info);
13361e270976SMartin KaFai Lau 	struct bpf_map_info info = {};
13371e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
13381e270976SMartin KaFai Lau 	int err;
13391e270976SMartin KaFai Lau 
13401e270976SMartin KaFai Lau 	err = check_uarg_tail_zero(uinfo, sizeof(info), info_len);
13411e270976SMartin KaFai Lau 	if (err)
13421e270976SMartin KaFai Lau 		return err;
13431e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
13441e270976SMartin KaFai Lau 
13451e270976SMartin KaFai Lau 	info.type = map->map_type;
13461e270976SMartin KaFai Lau 	info.id = map->id;
13471e270976SMartin KaFai Lau 	info.key_size = map->key_size;
13481e270976SMartin KaFai Lau 	info.value_size = map->value_size;
13491e270976SMartin KaFai Lau 	info.max_entries = map->max_entries;
13501e270976SMartin KaFai Lau 	info.map_flags = map->map_flags;
13511e270976SMartin KaFai Lau 
13521e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
13531e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
13541e270976SMartin KaFai Lau 		return -EFAULT;
13551e270976SMartin KaFai Lau 
13561e270976SMartin KaFai Lau 	return 0;
13571e270976SMartin KaFai Lau }
13581e270976SMartin KaFai Lau 
13591e270976SMartin KaFai Lau #define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info
13601e270976SMartin KaFai Lau 
13611e270976SMartin KaFai Lau static int bpf_obj_get_info_by_fd(const union bpf_attr *attr,
13621e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
13631e270976SMartin KaFai Lau {
13641e270976SMartin KaFai Lau 	int ufd = attr->info.bpf_fd;
13651e270976SMartin KaFai Lau 	struct fd f;
13661e270976SMartin KaFai Lau 	int err;
13671e270976SMartin KaFai Lau 
13681e270976SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD))
13691e270976SMartin KaFai Lau 		return -EINVAL;
13701e270976SMartin KaFai Lau 
13711e270976SMartin KaFai Lau 	f = fdget(ufd);
13721e270976SMartin KaFai Lau 	if (!f.file)
13731e270976SMartin KaFai Lau 		return -EBADFD;
13741e270976SMartin KaFai Lau 
13751e270976SMartin KaFai Lau 	if (f.file->f_op == &bpf_prog_fops)
13761e270976SMartin KaFai Lau 		err = bpf_prog_get_info_by_fd(f.file->private_data, attr,
13771e270976SMartin KaFai Lau 					      uattr);
13781e270976SMartin KaFai Lau 	else if (f.file->f_op == &bpf_map_fops)
13791e270976SMartin KaFai Lau 		err = bpf_map_get_info_by_fd(f.file->private_data, attr,
13801e270976SMartin KaFai Lau 					     uattr);
13811e270976SMartin KaFai Lau 	else
13821e270976SMartin KaFai Lau 		err = -EINVAL;
13831e270976SMartin KaFai Lau 
13841e270976SMartin KaFai Lau 	fdput(f);
13851e270976SMartin KaFai Lau 	return err;
13861e270976SMartin KaFai Lau }
13871e270976SMartin KaFai Lau 
138899c55f7dSAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
138999c55f7dSAlexei Starovoitov {
139099c55f7dSAlexei Starovoitov 	union bpf_attr attr = {};
139199c55f7dSAlexei Starovoitov 	int err;
139299c55f7dSAlexei Starovoitov 
13931be7f75dSAlexei Starovoitov 	if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled)
139499c55f7dSAlexei Starovoitov 		return -EPERM;
139599c55f7dSAlexei Starovoitov 
139699c55f7dSAlexei Starovoitov 	if (!access_ok(VERIFY_READ, uattr, 1))
139799c55f7dSAlexei Starovoitov 		return -EFAULT;
139899c55f7dSAlexei Starovoitov 
139999c55f7dSAlexei Starovoitov 	if (size > PAGE_SIZE)	/* silly large */
140099c55f7dSAlexei Starovoitov 		return -E2BIG;
140199c55f7dSAlexei Starovoitov 
140299c55f7dSAlexei Starovoitov 	/* If we're handed a bigger struct than we know of,
140399c55f7dSAlexei Starovoitov 	 * ensure all the unknown bits are 0 - i.e. new
140499c55f7dSAlexei Starovoitov 	 * user-space does not rely on any kernel feature
140599c55f7dSAlexei Starovoitov 	 * extensions we dont know about yet.
140699c55f7dSAlexei Starovoitov 	 */
14071e270976SMartin KaFai Lau 	err = check_uarg_tail_zero(uattr, sizeof(attr), size);
140899c55f7dSAlexei Starovoitov 	if (err)
140999c55f7dSAlexei Starovoitov 		return err;
14101e270976SMartin KaFai Lau 	size = min_t(u32, size, sizeof(attr));
141199c55f7dSAlexei Starovoitov 
141299c55f7dSAlexei Starovoitov 	/* copy attributes from user space, may be less than sizeof(bpf_attr) */
141399c55f7dSAlexei Starovoitov 	if (copy_from_user(&attr, uattr, size) != 0)
141499c55f7dSAlexei Starovoitov 		return -EFAULT;
141599c55f7dSAlexei Starovoitov 
141699c55f7dSAlexei Starovoitov 	switch (cmd) {
141799c55f7dSAlexei Starovoitov 	case BPF_MAP_CREATE:
141899c55f7dSAlexei Starovoitov 		err = map_create(&attr);
141999c55f7dSAlexei Starovoitov 		break;
1420db20fd2bSAlexei Starovoitov 	case BPF_MAP_LOOKUP_ELEM:
1421db20fd2bSAlexei Starovoitov 		err = map_lookup_elem(&attr);
1422db20fd2bSAlexei Starovoitov 		break;
1423db20fd2bSAlexei Starovoitov 	case BPF_MAP_UPDATE_ELEM:
1424db20fd2bSAlexei Starovoitov 		err = map_update_elem(&attr);
1425db20fd2bSAlexei Starovoitov 		break;
1426db20fd2bSAlexei Starovoitov 	case BPF_MAP_DELETE_ELEM:
1427db20fd2bSAlexei Starovoitov 		err = map_delete_elem(&attr);
1428db20fd2bSAlexei Starovoitov 		break;
1429db20fd2bSAlexei Starovoitov 	case BPF_MAP_GET_NEXT_KEY:
1430db20fd2bSAlexei Starovoitov 		err = map_get_next_key(&attr);
1431db20fd2bSAlexei Starovoitov 		break;
143209756af4SAlexei Starovoitov 	case BPF_PROG_LOAD:
143309756af4SAlexei Starovoitov 		err = bpf_prog_load(&attr);
143409756af4SAlexei Starovoitov 		break;
1435b2197755SDaniel Borkmann 	case BPF_OBJ_PIN:
1436b2197755SDaniel Borkmann 		err = bpf_obj_pin(&attr);
1437b2197755SDaniel Borkmann 		break;
1438b2197755SDaniel Borkmann 	case BPF_OBJ_GET:
1439b2197755SDaniel Borkmann 		err = bpf_obj_get(&attr);
1440b2197755SDaniel Borkmann 		break;
1441f4324551SDaniel Mack #ifdef CONFIG_CGROUP_BPF
1442f4324551SDaniel Mack 	case BPF_PROG_ATTACH:
1443f4324551SDaniel Mack 		err = bpf_prog_attach(&attr);
1444f4324551SDaniel Mack 		break;
1445f4324551SDaniel Mack 	case BPF_PROG_DETACH:
1446f4324551SDaniel Mack 		err = bpf_prog_detach(&attr);
1447f4324551SDaniel Mack 		break;
1448f4324551SDaniel Mack #endif
14491cf1cae9SAlexei Starovoitov 	case BPF_PROG_TEST_RUN:
14501cf1cae9SAlexei Starovoitov 		err = bpf_prog_test_run(&attr, uattr);
14511cf1cae9SAlexei Starovoitov 		break;
145234ad5580SMartin KaFai Lau 	case BPF_PROG_GET_NEXT_ID:
145334ad5580SMartin KaFai Lau 		err = bpf_obj_get_next_id(&attr, uattr,
145434ad5580SMartin KaFai Lau 					  &prog_idr, &prog_idr_lock);
145534ad5580SMartin KaFai Lau 		break;
145634ad5580SMartin KaFai Lau 	case BPF_MAP_GET_NEXT_ID:
145734ad5580SMartin KaFai Lau 		err = bpf_obj_get_next_id(&attr, uattr,
145834ad5580SMartin KaFai Lau 					  &map_idr, &map_idr_lock);
145934ad5580SMartin KaFai Lau 		break;
1460b16d9aa4SMartin KaFai Lau 	case BPF_PROG_GET_FD_BY_ID:
1461b16d9aa4SMartin KaFai Lau 		err = bpf_prog_get_fd_by_id(&attr);
1462b16d9aa4SMartin KaFai Lau 		break;
1463bd5f5f4eSMartin KaFai Lau 	case BPF_MAP_GET_FD_BY_ID:
1464bd5f5f4eSMartin KaFai Lau 		err = bpf_map_get_fd_by_id(&attr);
1465bd5f5f4eSMartin KaFai Lau 		break;
14661e270976SMartin KaFai Lau 	case BPF_OBJ_GET_INFO_BY_FD:
14671e270976SMartin KaFai Lau 		err = bpf_obj_get_info_by_fd(&attr, uattr);
14681e270976SMartin KaFai Lau 		break;
146999c55f7dSAlexei Starovoitov 	default:
147099c55f7dSAlexei Starovoitov 		err = -EINVAL;
147199c55f7dSAlexei Starovoitov 		break;
147299c55f7dSAlexei Starovoitov 	}
147399c55f7dSAlexei Starovoitov 
147499c55f7dSAlexei Starovoitov 	return err;
147599c55f7dSAlexei Starovoitov }
1476