xref: /linux/kernel/bpf/syscall.c (revision d74bad4e74ee373787a9ae24197c17b7cdc428d5)
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>
26cb4d2b3fSMartin KaFai Lau #include <linux/cred.h>
27cb4d2b3fSMartin KaFai Lau #include <linux/timekeeping.h>
28cb4d2b3fSMartin KaFai Lau #include <linux/ctype.h>
2999c55f7dSAlexei Starovoitov 
3014dc6f04SMartin KaFai Lau #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY || \
3114dc6f04SMartin KaFai Lau 			   (map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \
3214dc6f04SMartin KaFai Lau 			   (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \
3314dc6f04SMartin KaFai Lau 			   (map)->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS)
3414dc6f04SMartin KaFai Lau #define IS_FD_HASH(map) ((map)->map_type == BPF_MAP_TYPE_HASH_OF_MAPS)
3514dc6f04SMartin KaFai Lau #define IS_FD_MAP(map) (IS_FD_ARRAY(map) || IS_FD_HASH(map))
3614dc6f04SMartin KaFai Lau 
376e71b04aSChenbo Feng #define BPF_OBJ_FLAG_MASK   (BPF_F_RDONLY | BPF_F_WRONLY)
386e71b04aSChenbo Feng 
39b121d1e7SAlexei Starovoitov DEFINE_PER_CPU(int, bpf_prog_active);
40dc4bb0e2SMartin KaFai Lau static DEFINE_IDR(prog_idr);
41dc4bb0e2SMartin KaFai Lau static DEFINE_SPINLOCK(prog_idr_lock);
42f3f1c054SMartin KaFai Lau static DEFINE_IDR(map_idr);
43f3f1c054SMartin KaFai Lau static DEFINE_SPINLOCK(map_idr_lock);
44b121d1e7SAlexei Starovoitov 
451be7f75dSAlexei Starovoitov int sysctl_unprivileged_bpf_disabled __read_mostly;
461be7f75dSAlexei Starovoitov 
4740077e0cSJohannes Berg static const struct bpf_map_ops * const bpf_map_types[] = {
4840077e0cSJohannes Berg #define BPF_PROG_TYPE(_id, _ops)
4940077e0cSJohannes Berg #define BPF_MAP_TYPE(_id, _ops) \
5040077e0cSJohannes Berg 	[_id] = &_ops,
5140077e0cSJohannes Berg #include <linux/bpf_types.h>
5240077e0cSJohannes Berg #undef BPF_PROG_TYPE
5340077e0cSJohannes Berg #undef BPF_MAP_TYPE
5440077e0cSJohannes Berg };
5599c55f7dSAlexei Starovoitov 
56752ba56fSMickaël Salaün /*
57752ba56fSMickaël Salaün  * If we're handed a bigger struct than we know of, ensure all the unknown bits
58752ba56fSMickaël Salaün  * are 0 - i.e. new user-space does not rely on any kernel feature extensions
59752ba56fSMickaël Salaün  * we don't know about yet.
60752ba56fSMickaël Salaün  *
61752ba56fSMickaël Salaün  * There is a ToCToU between this function call and the following
62752ba56fSMickaël Salaün  * copy_from_user() call. However, this is not a concern since this function is
63752ba56fSMickaël Salaün  * meant to be a future-proofing of bits.
64752ba56fSMickaël Salaün  */
6558291a74SMickaël Salaün static int check_uarg_tail_zero(void __user *uaddr,
6658291a74SMickaël Salaün 				size_t expected_size,
6758291a74SMickaël Salaün 				size_t actual_size)
6858291a74SMickaël Salaün {
6958291a74SMickaël Salaün 	unsigned char __user *addr;
7058291a74SMickaël Salaün 	unsigned char __user *end;
7158291a74SMickaël Salaün 	unsigned char val;
7258291a74SMickaël Salaün 	int err;
7358291a74SMickaël Salaün 
74752ba56fSMickaël Salaün 	if (unlikely(actual_size > PAGE_SIZE))	/* silly large */
75752ba56fSMickaël Salaün 		return -E2BIG;
76752ba56fSMickaël Salaün 
77752ba56fSMickaël Salaün 	if (unlikely(!access_ok(VERIFY_READ, uaddr, actual_size)))
78752ba56fSMickaël Salaün 		return -EFAULT;
79752ba56fSMickaël Salaün 
8058291a74SMickaël Salaün 	if (actual_size <= expected_size)
8158291a74SMickaël Salaün 		return 0;
8258291a74SMickaël Salaün 
8358291a74SMickaël Salaün 	addr = uaddr + expected_size;
8458291a74SMickaël Salaün 	end  = uaddr + actual_size;
8558291a74SMickaël Salaün 
8658291a74SMickaël Salaün 	for (; addr < end; addr++) {
8758291a74SMickaël Salaün 		err = get_user(val, addr);
8858291a74SMickaël Salaün 		if (err)
8958291a74SMickaël Salaün 			return err;
9058291a74SMickaël Salaün 		if (val)
9158291a74SMickaël Salaün 			return -E2BIG;
9258291a74SMickaël Salaün 	}
9358291a74SMickaël Salaün 
9458291a74SMickaël Salaün 	return 0;
9558291a74SMickaël Salaün }
9658291a74SMickaël Salaün 
97a3884572SJakub Kicinski const struct bpf_map_ops bpf_map_offload_ops = {
98a3884572SJakub Kicinski 	.map_alloc = bpf_map_offload_map_alloc,
99a3884572SJakub Kicinski 	.map_free = bpf_map_offload_map_free,
100a3884572SJakub Kicinski };
101a3884572SJakub Kicinski 
10299c55f7dSAlexei Starovoitov static struct bpf_map *find_and_alloc_map(union bpf_attr *attr)
10399c55f7dSAlexei Starovoitov {
1041110f3a9SJakub Kicinski 	const struct bpf_map_ops *ops;
10599c55f7dSAlexei Starovoitov 	struct bpf_map *map;
1061110f3a9SJakub Kicinski 	int err;
10799c55f7dSAlexei Starovoitov 
1081110f3a9SJakub Kicinski 	if (attr->map_type >= ARRAY_SIZE(bpf_map_types))
1091110f3a9SJakub Kicinski 		return ERR_PTR(-EINVAL);
1101110f3a9SJakub Kicinski 	ops = bpf_map_types[attr->map_type];
1111110f3a9SJakub Kicinski 	if (!ops)
11240077e0cSJohannes Berg 		return ERR_PTR(-EINVAL);
11340077e0cSJohannes Berg 
1141110f3a9SJakub Kicinski 	if (ops->map_alloc_check) {
1151110f3a9SJakub Kicinski 		err = ops->map_alloc_check(attr);
1161110f3a9SJakub Kicinski 		if (err)
1171110f3a9SJakub Kicinski 			return ERR_PTR(err);
1181110f3a9SJakub Kicinski 	}
119a3884572SJakub Kicinski 	if (attr->map_ifindex)
120a3884572SJakub Kicinski 		ops = &bpf_map_offload_ops;
1211110f3a9SJakub Kicinski 	map = ops->map_alloc(attr);
12299c55f7dSAlexei Starovoitov 	if (IS_ERR(map))
12399c55f7dSAlexei Starovoitov 		return map;
1241110f3a9SJakub Kicinski 	map->ops = ops;
12599c55f7dSAlexei Starovoitov 	map->map_type = attr->map_type;
12699c55f7dSAlexei Starovoitov 	return map;
12799c55f7dSAlexei Starovoitov }
12899c55f7dSAlexei Starovoitov 
12996eabe7aSMartin KaFai Lau void *bpf_map_area_alloc(size_t size, int numa_node)
130d407bd25SDaniel Borkmann {
131d407bd25SDaniel Borkmann 	/* We definitely need __GFP_NORETRY, so OOM killer doesn't
132d407bd25SDaniel Borkmann 	 * trigger under memory pressure as we really just want to
133d407bd25SDaniel Borkmann 	 * fail instead.
134d407bd25SDaniel Borkmann 	 */
135d407bd25SDaniel Borkmann 	const gfp_t flags = __GFP_NOWARN | __GFP_NORETRY | __GFP_ZERO;
136d407bd25SDaniel Borkmann 	void *area;
137d407bd25SDaniel Borkmann 
138d407bd25SDaniel Borkmann 	if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
13996eabe7aSMartin KaFai Lau 		area = kmalloc_node(size, GFP_USER | flags, numa_node);
140d407bd25SDaniel Borkmann 		if (area != NULL)
141d407bd25SDaniel Borkmann 			return area;
142d407bd25SDaniel Borkmann 	}
143d407bd25SDaniel Borkmann 
14496eabe7aSMartin KaFai Lau 	return __vmalloc_node_flags_caller(size, numa_node, GFP_KERNEL | flags,
14596eabe7aSMartin KaFai Lau 					   __builtin_return_address(0));
146d407bd25SDaniel Borkmann }
147d407bd25SDaniel Borkmann 
148d407bd25SDaniel Borkmann void bpf_map_area_free(void *area)
149d407bd25SDaniel Borkmann {
150d407bd25SDaniel Borkmann 	kvfree(area);
151d407bd25SDaniel Borkmann }
152d407bd25SDaniel Borkmann 
153bd475643SJakub Kicinski void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr)
154bd475643SJakub Kicinski {
155bd475643SJakub Kicinski 	map->map_type = attr->map_type;
156bd475643SJakub Kicinski 	map->key_size = attr->key_size;
157bd475643SJakub Kicinski 	map->value_size = attr->value_size;
158bd475643SJakub Kicinski 	map->max_entries = attr->max_entries;
159bd475643SJakub Kicinski 	map->map_flags = attr->map_flags;
160bd475643SJakub Kicinski 	map->numa_node = bpf_map_attr_numa_node(attr);
161bd475643SJakub Kicinski }
162bd475643SJakub Kicinski 
1636c905981SAlexei Starovoitov int bpf_map_precharge_memlock(u32 pages)
1646c905981SAlexei Starovoitov {
1656c905981SAlexei Starovoitov 	struct user_struct *user = get_current_user();
1666c905981SAlexei Starovoitov 	unsigned long memlock_limit, cur;
1676c905981SAlexei Starovoitov 
1686c905981SAlexei Starovoitov 	memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
1696c905981SAlexei Starovoitov 	cur = atomic_long_read(&user->locked_vm);
1706c905981SAlexei Starovoitov 	free_uid(user);
1716c905981SAlexei Starovoitov 	if (cur + pages > memlock_limit)
1726c905981SAlexei Starovoitov 		return -EPERM;
1736c905981SAlexei Starovoitov 	return 0;
1746c905981SAlexei Starovoitov }
1756c905981SAlexei Starovoitov 
176aaac3ba9SAlexei Starovoitov static int bpf_map_charge_memlock(struct bpf_map *map)
177aaac3ba9SAlexei Starovoitov {
178aaac3ba9SAlexei Starovoitov 	struct user_struct *user = get_current_user();
179aaac3ba9SAlexei Starovoitov 	unsigned long memlock_limit;
180aaac3ba9SAlexei Starovoitov 
181aaac3ba9SAlexei Starovoitov 	memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
182aaac3ba9SAlexei Starovoitov 
183aaac3ba9SAlexei Starovoitov 	atomic_long_add(map->pages, &user->locked_vm);
184aaac3ba9SAlexei Starovoitov 
185aaac3ba9SAlexei Starovoitov 	if (atomic_long_read(&user->locked_vm) > memlock_limit) {
186aaac3ba9SAlexei Starovoitov 		atomic_long_sub(map->pages, &user->locked_vm);
187aaac3ba9SAlexei Starovoitov 		free_uid(user);
188aaac3ba9SAlexei Starovoitov 		return -EPERM;
189aaac3ba9SAlexei Starovoitov 	}
190aaac3ba9SAlexei Starovoitov 	map->user = user;
191aaac3ba9SAlexei Starovoitov 	return 0;
192aaac3ba9SAlexei Starovoitov }
193aaac3ba9SAlexei Starovoitov 
194aaac3ba9SAlexei Starovoitov static void bpf_map_uncharge_memlock(struct bpf_map *map)
195aaac3ba9SAlexei Starovoitov {
196aaac3ba9SAlexei Starovoitov 	struct user_struct *user = map->user;
197aaac3ba9SAlexei Starovoitov 
198aaac3ba9SAlexei Starovoitov 	atomic_long_sub(map->pages, &user->locked_vm);
199aaac3ba9SAlexei Starovoitov 	free_uid(user);
200aaac3ba9SAlexei Starovoitov }
201aaac3ba9SAlexei Starovoitov 
202f3f1c054SMartin KaFai Lau static int bpf_map_alloc_id(struct bpf_map *map)
203f3f1c054SMartin KaFai Lau {
204f3f1c054SMartin KaFai Lau 	int id;
205f3f1c054SMartin KaFai Lau 
206b76354cdSShaohua Li 	idr_preload(GFP_KERNEL);
207f3f1c054SMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
208f3f1c054SMartin KaFai Lau 	id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC);
209f3f1c054SMartin KaFai Lau 	if (id > 0)
210f3f1c054SMartin KaFai Lau 		map->id = id;
211f3f1c054SMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
212b76354cdSShaohua Li 	idr_preload_end();
213f3f1c054SMartin KaFai Lau 
214f3f1c054SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
215f3f1c054SMartin KaFai Lau 		return -ENOSPC;
216f3f1c054SMartin KaFai Lau 
217f3f1c054SMartin KaFai Lau 	return id > 0 ? 0 : id;
218f3f1c054SMartin KaFai Lau }
219f3f1c054SMartin KaFai Lau 
220a3884572SJakub Kicinski void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock)
221f3f1c054SMartin KaFai Lau {
222930651a7SEric Dumazet 	unsigned long flags;
223930651a7SEric Dumazet 
224a3884572SJakub Kicinski 	/* Offloaded maps are removed from the IDR store when their device
225a3884572SJakub Kicinski 	 * disappears - even if someone holds an fd to them they are unusable,
226a3884572SJakub Kicinski 	 * the memory is gone, all ops will fail; they are simply waiting for
227a3884572SJakub Kicinski 	 * refcnt to drop to be freed.
228a3884572SJakub Kicinski 	 */
229a3884572SJakub Kicinski 	if (!map->id)
230a3884572SJakub Kicinski 		return;
231a3884572SJakub Kicinski 
232bd5f5f4eSMartin KaFai Lau 	if (do_idr_lock)
233930651a7SEric Dumazet 		spin_lock_irqsave(&map_idr_lock, flags);
234bd5f5f4eSMartin KaFai Lau 	else
235bd5f5f4eSMartin KaFai Lau 		__acquire(&map_idr_lock);
236bd5f5f4eSMartin KaFai Lau 
237f3f1c054SMartin KaFai Lau 	idr_remove(&map_idr, map->id);
238a3884572SJakub Kicinski 	map->id = 0;
239bd5f5f4eSMartin KaFai Lau 
240bd5f5f4eSMartin KaFai Lau 	if (do_idr_lock)
241930651a7SEric Dumazet 		spin_unlock_irqrestore(&map_idr_lock, flags);
242bd5f5f4eSMartin KaFai Lau 	else
243bd5f5f4eSMartin KaFai Lau 		__release(&map_idr_lock);
244f3f1c054SMartin KaFai Lau }
245f3f1c054SMartin KaFai Lau 
24699c55f7dSAlexei Starovoitov /* called from workqueue */
24799c55f7dSAlexei Starovoitov static void bpf_map_free_deferred(struct work_struct *work)
24899c55f7dSAlexei Starovoitov {
24999c55f7dSAlexei Starovoitov 	struct bpf_map *map = container_of(work, struct bpf_map, work);
25099c55f7dSAlexei Starovoitov 
251aaac3ba9SAlexei Starovoitov 	bpf_map_uncharge_memlock(map);
252afdb09c7SChenbo Feng 	security_bpf_map_free(map);
25399c55f7dSAlexei Starovoitov 	/* implementation dependent freeing */
25499c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
25599c55f7dSAlexei Starovoitov }
25699c55f7dSAlexei Starovoitov 
257c9da161cSDaniel Borkmann static void bpf_map_put_uref(struct bpf_map *map)
258c9da161cSDaniel Borkmann {
259c9da161cSDaniel Borkmann 	if (atomic_dec_and_test(&map->usercnt)) {
260c9da161cSDaniel Borkmann 		if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY)
261c9da161cSDaniel Borkmann 			bpf_fd_array_map_clear(map);
262c9da161cSDaniel Borkmann 	}
263c9da161cSDaniel Borkmann }
264c9da161cSDaniel Borkmann 
26599c55f7dSAlexei Starovoitov /* decrement map refcnt and schedule it for freeing via workqueue
26699c55f7dSAlexei Starovoitov  * (unrelying map implementation ops->map_free() might sleep)
26799c55f7dSAlexei Starovoitov  */
268bd5f5f4eSMartin KaFai Lau static void __bpf_map_put(struct bpf_map *map, bool do_idr_lock)
26999c55f7dSAlexei Starovoitov {
27099c55f7dSAlexei Starovoitov 	if (atomic_dec_and_test(&map->refcnt)) {
27134ad5580SMartin KaFai Lau 		/* bpf_map_free_id() must be called first */
272bd5f5f4eSMartin KaFai Lau 		bpf_map_free_id(map, do_idr_lock);
27399c55f7dSAlexei Starovoitov 		INIT_WORK(&map->work, bpf_map_free_deferred);
27499c55f7dSAlexei Starovoitov 		schedule_work(&map->work);
27599c55f7dSAlexei Starovoitov 	}
27699c55f7dSAlexei Starovoitov }
27799c55f7dSAlexei Starovoitov 
278bd5f5f4eSMartin KaFai Lau void bpf_map_put(struct bpf_map *map)
279bd5f5f4eSMartin KaFai Lau {
280bd5f5f4eSMartin KaFai Lau 	__bpf_map_put(map, true);
281bd5f5f4eSMartin KaFai Lau }
282bd5f5f4eSMartin KaFai Lau 
283c9da161cSDaniel Borkmann void bpf_map_put_with_uref(struct bpf_map *map)
284c9da161cSDaniel Borkmann {
285c9da161cSDaniel Borkmann 	bpf_map_put_uref(map);
286c9da161cSDaniel Borkmann 	bpf_map_put(map);
287c9da161cSDaniel Borkmann }
288c9da161cSDaniel Borkmann 
28999c55f7dSAlexei Starovoitov static int bpf_map_release(struct inode *inode, struct file *filp)
29099c55f7dSAlexei Starovoitov {
29161d1b6a4SDaniel Borkmann 	struct bpf_map *map = filp->private_data;
29261d1b6a4SDaniel Borkmann 
29361d1b6a4SDaniel Borkmann 	if (map->ops->map_release)
29461d1b6a4SDaniel Borkmann 		map->ops->map_release(map, filp);
29561d1b6a4SDaniel Borkmann 
29661d1b6a4SDaniel Borkmann 	bpf_map_put_with_uref(map);
29799c55f7dSAlexei Starovoitov 	return 0;
29899c55f7dSAlexei Starovoitov }
29999c55f7dSAlexei Starovoitov 
300f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
301f99bf205SDaniel Borkmann static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)
302f99bf205SDaniel Borkmann {
303f99bf205SDaniel Borkmann 	const struct bpf_map *map = filp->private_data;
30421116b70SDaniel Borkmann 	const struct bpf_array *array;
30521116b70SDaniel Borkmann 	u32 owner_prog_type = 0;
3069780c0abSDaniel Borkmann 	u32 owner_jited = 0;
30721116b70SDaniel Borkmann 
30821116b70SDaniel Borkmann 	if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) {
30921116b70SDaniel Borkmann 		array = container_of(map, struct bpf_array, map);
31021116b70SDaniel Borkmann 		owner_prog_type = array->owner_prog_type;
3119780c0abSDaniel Borkmann 		owner_jited = array->owner_jited;
31221116b70SDaniel Borkmann 	}
313f99bf205SDaniel Borkmann 
314f99bf205SDaniel Borkmann 	seq_printf(m,
315f99bf205SDaniel Borkmann 		   "map_type:\t%u\n"
316f99bf205SDaniel Borkmann 		   "key_size:\t%u\n"
317f99bf205SDaniel Borkmann 		   "value_size:\t%u\n"
318322cea2fSDaniel Borkmann 		   "max_entries:\t%u\n"
31921116b70SDaniel Borkmann 		   "map_flags:\t%#x\n"
32021116b70SDaniel Borkmann 		   "memlock:\t%llu\n",
321f99bf205SDaniel Borkmann 		   map->map_type,
322f99bf205SDaniel Borkmann 		   map->key_size,
323f99bf205SDaniel Borkmann 		   map->value_size,
324322cea2fSDaniel Borkmann 		   map->max_entries,
32521116b70SDaniel Borkmann 		   map->map_flags,
32621116b70SDaniel Borkmann 		   map->pages * 1ULL << PAGE_SHIFT);
32721116b70SDaniel Borkmann 
3289780c0abSDaniel Borkmann 	if (owner_prog_type) {
32921116b70SDaniel Borkmann 		seq_printf(m, "owner_prog_type:\t%u\n",
33021116b70SDaniel Borkmann 			   owner_prog_type);
3319780c0abSDaniel Borkmann 		seq_printf(m, "owner_jited:\t%u\n",
3329780c0abSDaniel Borkmann 			   owner_jited);
3339780c0abSDaniel Borkmann 	}
334f99bf205SDaniel Borkmann }
335f99bf205SDaniel Borkmann #endif
336f99bf205SDaniel Borkmann 
3376e71b04aSChenbo Feng static ssize_t bpf_dummy_read(struct file *filp, char __user *buf, size_t siz,
3386e71b04aSChenbo Feng 			      loff_t *ppos)
3396e71b04aSChenbo Feng {
3406e71b04aSChenbo Feng 	/* We need this handler such that alloc_file() enables
3416e71b04aSChenbo Feng 	 * f_mode with FMODE_CAN_READ.
3426e71b04aSChenbo Feng 	 */
3436e71b04aSChenbo Feng 	return -EINVAL;
3446e71b04aSChenbo Feng }
3456e71b04aSChenbo Feng 
3466e71b04aSChenbo Feng static ssize_t bpf_dummy_write(struct file *filp, const char __user *buf,
3476e71b04aSChenbo Feng 			       size_t siz, loff_t *ppos)
3486e71b04aSChenbo Feng {
3496e71b04aSChenbo Feng 	/* We need this handler such that alloc_file() enables
3506e71b04aSChenbo Feng 	 * f_mode with FMODE_CAN_WRITE.
3516e71b04aSChenbo Feng 	 */
3526e71b04aSChenbo Feng 	return -EINVAL;
3536e71b04aSChenbo Feng }
3546e71b04aSChenbo Feng 
355f66e448cSChenbo Feng const struct file_operations bpf_map_fops = {
356f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
357f99bf205SDaniel Borkmann 	.show_fdinfo	= bpf_map_show_fdinfo,
358f99bf205SDaniel Borkmann #endif
35999c55f7dSAlexei Starovoitov 	.release	= bpf_map_release,
3606e71b04aSChenbo Feng 	.read		= bpf_dummy_read,
3616e71b04aSChenbo Feng 	.write		= bpf_dummy_write,
36299c55f7dSAlexei Starovoitov };
36399c55f7dSAlexei Starovoitov 
3646e71b04aSChenbo Feng int bpf_map_new_fd(struct bpf_map *map, int flags)
365aa79781bSDaniel Borkmann {
366afdb09c7SChenbo Feng 	int ret;
367afdb09c7SChenbo Feng 
368afdb09c7SChenbo Feng 	ret = security_bpf_map(map, OPEN_FMODE(flags));
369afdb09c7SChenbo Feng 	if (ret < 0)
370afdb09c7SChenbo Feng 		return ret;
371afdb09c7SChenbo Feng 
372aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-map", &bpf_map_fops, map,
3736e71b04aSChenbo Feng 				flags | O_CLOEXEC);
3746e71b04aSChenbo Feng }
3756e71b04aSChenbo Feng 
3766e71b04aSChenbo Feng int bpf_get_file_flag(int flags)
3776e71b04aSChenbo Feng {
3786e71b04aSChenbo Feng 	if ((flags & BPF_F_RDONLY) && (flags & BPF_F_WRONLY))
3796e71b04aSChenbo Feng 		return -EINVAL;
3806e71b04aSChenbo Feng 	if (flags & BPF_F_RDONLY)
3816e71b04aSChenbo Feng 		return O_RDONLY;
3826e71b04aSChenbo Feng 	if (flags & BPF_F_WRONLY)
3836e71b04aSChenbo Feng 		return O_WRONLY;
3846e71b04aSChenbo Feng 	return O_RDWR;
385aa79781bSDaniel Borkmann }
386aa79781bSDaniel Borkmann 
38799c55f7dSAlexei Starovoitov /* helper macro to check that unused fields 'union bpf_attr' are zero */
38899c55f7dSAlexei Starovoitov #define CHECK_ATTR(CMD) \
38999c55f7dSAlexei Starovoitov 	memchr_inv((void *) &attr->CMD##_LAST_FIELD + \
39099c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD), 0, \
39199c55f7dSAlexei Starovoitov 		   sizeof(*attr) - \
39299c55f7dSAlexei Starovoitov 		   offsetof(union bpf_attr, CMD##_LAST_FIELD) - \
39399c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD)) != NULL
39499c55f7dSAlexei Starovoitov 
395cb4d2b3fSMartin KaFai Lau /* dst and src must have at least BPF_OBJ_NAME_LEN number of bytes.
396cb4d2b3fSMartin KaFai Lau  * Return 0 on success and < 0 on error.
397cb4d2b3fSMartin KaFai Lau  */
398cb4d2b3fSMartin KaFai Lau static int bpf_obj_name_cpy(char *dst, const char *src)
399cb4d2b3fSMartin KaFai Lau {
400cb4d2b3fSMartin KaFai Lau 	const char *end = src + BPF_OBJ_NAME_LEN;
401cb4d2b3fSMartin KaFai Lau 
402473d9734SMartin KaFai Lau 	memset(dst, 0, BPF_OBJ_NAME_LEN);
403473d9734SMartin KaFai Lau 
404cb4d2b3fSMartin KaFai Lau 	/* Copy all isalnum() and '_' char */
405cb4d2b3fSMartin KaFai Lau 	while (src < end && *src) {
406cb4d2b3fSMartin KaFai Lau 		if (!isalnum(*src) && *src != '_')
407cb4d2b3fSMartin KaFai Lau 			return -EINVAL;
408cb4d2b3fSMartin KaFai Lau 		*dst++ = *src++;
409cb4d2b3fSMartin KaFai Lau 	}
410cb4d2b3fSMartin KaFai Lau 
411cb4d2b3fSMartin KaFai Lau 	/* No '\0' found in BPF_OBJ_NAME_LEN number of bytes */
412cb4d2b3fSMartin KaFai Lau 	if (src == end)
413cb4d2b3fSMartin KaFai Lau 		return -EINVAL;
414cb4d2b3fSMartin KaFai Lau 
415cb4d2b3fSMartin KaFai Lau 	return 0;
416cb4d2b3fSMartin KaFai Lau }
417cb4d2b3fSMartin KaFai Lau 
418a3884572SJakub Kicinski #define BPF_MAP_CREATE_LAST_FIELD map_ifindex
41999c55f7dSAlexei Starovoitov /* called via syscall */
42099c55f7dSAlexei Starovoitov static int map_create(union bpf_attr *attr)
42199c55f7dSAlexei Starovoitov {
42296eabe7aSMartin KaFai Lau 	int numa_node = bpf_map_attr_numa_node(attr);
42399c55f7dSAlexei Starovoitov 	struct bpf_map *map;
4246e71b04aSChenbo Feng 	int f_flags;
42599c55f7dSAlexei Starovoitov 	int err;
42699c55f7dSAlexei Starovoitov 
42799c55f7dSAlexei Starovoitov 	err = CHECK_ATTR(BPF_MAP_CREATE);
42899c55f7dSAlexei Starovoitov 	if (err)
42999c55f7dSAlexei Starovoitov 		return -EINVAL;
43099c55f7dSAlexei Starovoitov 
4316e71b04aSChenbo Feng 	f_flags = bpf_get_file_flag(attr->map_flags);
4326e71b04aSChenbo Feng 	if (f_flags < 0)
4336e71b04aSChenbo Feng 		return f_flags;
4346e71b04aSChenbo Feng 
43596eabe7aSMartin KaFai Lau 	if (numa_node != NUMA_NO_NODE &&
43696e5ae4eSEric Dumazet 	    ((unsigned int)numa_node >= nr_node_ids ||
43796e5ae4eSEric Dumazet 	     !node_online(numa_node)))
43896eabe7aSMartin KaFai Lau 		return -EINVAL;
43996eabe7aSMartin KaFai Lau 
44099c55f7dSAlexei Starovoitov 	/* find map type and init map: hashtable vs rbtree vs bloom vs ... */
44199c55f7dSAlexei Starovoitov 	map = find_and_alloc_map(attr);
44299c55f7dSAlexei Starovoitov 	if (IS_ERR(map))
44399c55f7dSAlexei Starovoitov 		return PTR_ERR(map);
44499c55f7dSAlexei Starovoitov 
445ad5b177bSMartin KaFai Lau 	err = bpf_obj_name_cpy(map->name, attr->map_name);
446ad5b177bSMartin KaFai Lau 	if (err)
447ad5b177bSMartin KaFai Lau 		goto free_map_nouncharge;
448ad5b177bSMartin KaFai Lau 
44999c55f7dSAlexei Starovoitov 	atomic_set(&map->refcnt, 1);
450c9da161cSDaniel Borkmann 	atomic_set(&map->usercnt, 1);
45199c55f7dSAlexei Starovoitov 
452afdb09c7SChenbo Feng 	err = security_bpf_map_alloc(map);
453aaac3ba9SAlexei Starovoitov 	if (err)
45420b2b24fSDaniel Borkmann 		goto free_map_nouncharge;
455aaac3ba9SAlexei Starovoitov 
456afdb09c7SChenbo Feng 	err = bpf_map_charge_memlock(map);
457afdb09c7SChenbo Feng 	if (err)
458afdb09c7SChenbo Feng 		goto free_map_sec;
459afdb09c7SChenbo Feng 
460f3f1c054SMartin KaFai Lau 	err = bpf_map_alloc_id(map);
461f3f1c054SMartin KaFai Lau 	if (err)
462f3f1c054SMartin KaFai Lau 		goto free_map;
463f3f1c054SMartin KaFai Lau 
4646e71b04aSChenbo Feng 	err = bpf_map_new_fd(map, f_flags);
465bd5f5f4eSMartin KaFai Lau 	if (err < 0) {
466bd5f5f4eSMartin KaFai Lau 		/* failed to allocate fd.
467bd5f5f4eSMartin KaFai Lau 		 * bpf_map_put() is needed because the above
468bd5f5f4eSMartin KaFai Lau 		 * bpf_map_alloc_id() has published the map
469bd5f5f4eSMartin KaFai Lau 		 * to the userspace and the userspace may
470bd5f5f4eSMartin KaFai Lau 		 * have refcnt-ed it through BPF_MAP_GET_FD_BY_ID.
471bd5f5f4eSMartin KaFai Lau 		 */
472bd5f5f4eSMartin KaFai Lau 		bpf_map_put(map);
473bd5f5f4eSMartin KaFai Lau 		return err;
474bd5f5f4eSMartin KaFai Lau 	}
47599c55f7dSAlexei Starovoitov 
476a67edbf4SDaniel Borkmann 	trace_bpf_map_create(map, err);
47799c55f7dSAlexei Starovoitov 	return err;
47899c55f7dSAlexei Starovoitov 
47999c55f7dSAlexei Starovoitov free_map:
48020b2b24fSDaniel Borkmann 	bpf_map_uncharge_memlock(map);
481afdb09c7SChenbo Feng free_map_sec:
482afdb09c7SChenbo Feng 	security_bpf_map_free(map);
48320b2b24fSDaniel Borkmann free_map_nouncharge:
48499c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
48599c55f7dSAlexei Starovoitov 	return err;
48699c55f7dSAlexei Starovoitov }
48799c55f7dSAlexei Starovoitov 
488db20fd2bSAlexei Starovoitov /* if error is returned, fd is released.
489db20fd2bSAlexei Starovoitov  * On success caller should complete fd access with matching fdput()
490db20fd2bSAlexei Starovoitov  */
491c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f)
492db20fd2bSAlexei Starovoitov {
493db20fd2bSAlexei Starovoitov 	if (!f.file)
494db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EBADF);
495db20fd2bSAlexei Starovoitov 	if (f.file->f_op != &bpf_map_fops) {
496db20fd2bSAlexei Starovoitov 		fdput(f);
497db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EINVAL);
498db20fd2bSAlexei Starovoitov 	}
499db20fd2bSAlexei Starovoitov 
500c2101297SDaniel Borkmann 	return f.file->private_data;
501c2101297SDaniel Borkmann }
502c2101297SDaniel Borkmann 
50392117d84SAlexei Starovoitov /* prog's and map's refcnt limit */
50492117d84SAlexei Starovoitov #define BPF_MAX_REFCNT 32768
50592117d84SAlexei Starovoitov 
50692117d84SAlexei Starovoitov struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref)
507c9da161cSDaniel Borkmann {
50892117d84SAlexei Starovoitov 	if (atomic_inc_return(&map->refcnt) > BPF_MAX_REFCNT) {
50992117d84SAlexei Starovoitov 		atomic_dec(&map->refcnt);
51092117d84SAlexei Starovoitov 		return ERR_PTR(-EBUSY);
51192117d84SAlexei Starovoitov 	}
512c9da161cSDaniel Borkmann 	if (uref)
513c9da161cSDaniel Borkmann 		atomic_inc(&map->usercnt);
51492117d84SAlexei Starovoitov 	return map;
515c9da161cSDaniel Borkmann }
516c9da161cSDaniel Borkmann 
517c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd)
518c2101297SDaniel Borkmann {
519c2101297SDaniel Borkmann 	struct fd f = fdget(ufd);
520c2101297SDaniel Borkmann 	struct bpf_map *map;
521c2101297SDaniel Borkmann 
522c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
523c2101297SDaniel Borkmann 	if (IS_ERR(map))
524c2101297SDaniel Borkmann 		return map;
525c2101297SDaniel Borkmann 
52692117d84SAlexei Starovoitov 	map = bpf_map_inc(map, true);
527c2101297SDaniel Borkmann 	fdput(f);
528db20fd2bSAlexei Starovoitov 
529db20fd2bSAlexei Starovoitov 	return map;
530db20fd2bSAlexei Starovoitov }
531db20fd2bSAlexei Starovoitov 
532bd5f5f4eSMartin KaFai Lau /* map_idr_lock should have been held */
533bd5f5f4eSMartin KaFai Lau static struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map,
534bd5f5f4eSMartin KaFai Lau 					    bool uref)
535bd5f5f4eSMartin KaFai Lau {
536bd5f5f4eSMartin KaFai Lau 	int refold;
537bd5f5f4eSMartin KaFai Lau 
538bd5f5f4eSMartin KaFai Lau 	refold = __atomic_add_unless(&map->refcnt, 1, 0);
539bd5f5f4eSMartin KaFai Lau 
540bd5f5f4eSMartin KaFai Lau 	if (refold >= BPF_MAX_REFCNT) {
541bd5f5f4eSMartin KaFai Lau 		__bpf_map_put(map, false);
542bd5f5f4eSMartin KaFai Lau 		return ERR_PTR(-EBUSY);
543bd5f5f4eSMartin KaFai Lau 	}
544bd5f5f4eSMartin KaFai Lau 
545bd5f5f4eSMartin KaFai Lau 	if (!refold)
546bd5f5f4eSMartin KaFai Lau 		return ERR_PTR(-ENOENT);
547bd5f5f4eSMartin KaFai Lau 
548bd5f5f4eSMartin KaFai Lau 	if (uref)
549bd5f5f4eSMartin KaFai Lau 		atomic_inc(&map->usercnt);
550bd5f5f4eSMartin KaFai Lau 
551bd5f5f4eSMartin KaFai Lau 	return map;
552bd5f5f4eSMartin KaFai Lau }
553bd5f5f4eSMartin KaFai Lau 
554b8cdc051SAlexei Starovoitov int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
555b8cdc051SAlexei Starovoitov {
556b8cdc051SAlexei Starovoitov 	return -ENOTSUPP;
557b8cdc051SAlexei Starovoitov }
558b8cdc051SAlexei Starovoitov 
559db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
560db20fd2bSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD value
561db20fd2bSAlexei Starovoitov 
562db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr)
563db20fd2bSAlexei Starovoitov {
564535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
565535e7b4bSMickaël Salaün 	void __user *uvalue = u64_to_user_ptr(attr->value);
566db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
567db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
5688ebe667cSAlexei Starovoitov 	void *key, *value, *ptr;
56915a07b33SAlexei Starovoitov 	u32 value_size;
570592867bfSDaniel Borkmann 	struct fd f;
571db20fd2bSAlexei Starovoitov 	int err;
572db20fd2bSAlexei Starovoitov 
573db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
574db20fd2bSAlexei Starovoitov 		return -EINVAL;
575db20fd2bSAlexei Starovoitov 
576592867bfSDaniel Borkmann 	f = fdget(ufd);
577c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
578db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
579db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
580db20fd2bSAlexei Starovoitov 
5816e71b04aSChenbo Feng 	if (!(f.file->f_mode & FMODE_CAN_READ)) {
5826e71b04aSChenbo Feng 		err = -EPERM;
5836e71b04aSChenbo Feng 		goto err_put;
5846e71b04aSChenbo Feng 	}
5856e71b04aSChenbo Feng 
586e4448ed8SAl Viro 	key = memdup_user(ukey, map->key_size);
587e4448ed8SAl Viro 	if (IS_ERR(key)) {
588e4448ed8SAl Viro 		err = PTR_ERR(key);
589db20fd2bSAlexei Starovoitov 		goto err_put;
590e4448ed8SAl Viro 	}
591db20fd2bSAlexei Starovoitov 
59215a07b33SAlexei Starovoitov 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
5938f844938SMartin KaFai Lau 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
59415a07b33SAlexei Starovoitov 	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
59515a07b33SAlexei Starovoitov 		value_size = round_up(map->value_size, 8) * num_possible_cpus();
59614dc6f04SMartin KaFai Lau 	else if (IS_FD_MAP(map))
59714dc6f04SMartin KaFai Lau 		value_size = sizeof(u32);
59815a07b33SAlexei Starovoitov 	else
59915a07b33SAlexei Starovoitov 		value_size = map->value_size;
60015a07b33SAlexei Starovoitov 
6018ebe667cSAlexei Starovoitov 	err = -ENOMEM;
60215a07b33SAlexei Starovoitov 	value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
603db20fd2bSAlexei Starovoitov 	if (!value)
6048ebe667cSAlexei Starovoitov 		goto free_key;
6058ebe667cSAlexei Starovoitov 
606a3884572SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
607a3884572SJakub Kicinski 		err = bpf_map_offload_lookup_elem(map, key, value);
608a3884572SJakub Kicinski 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
6098f844938SMartin KaFai Lau 		   map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
61015a07b33SAlexei Starovoitov 		err = bpf_percpu_hash_copy(map, key, value);
61115a07b33SAlexei Starovoitov 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
61215a07b33SAlexei Starovoitov 		err = bpf_percpu_array_copy(map, key, value);
613557c0c6eSAlexei Starovoitov 	} else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) {
614557c0c6eSAlexei Starovoitov 		err = bpf_stackmap_copy(map, key, value);
61514dc6f04SMartin KaFai Lau 	} else if (IS_FD_ARRAY(map)) {
61614dc6f04SMartin KaFai Lau 		err = bpf_fd_array_map_lookup_elem(map, key, value);
61714dc6f04SMartin KaFai Lau 	} else if (IS_FD_HASH(map)) {
61814dc6f04SMartin KaFai Lau 		err = bpf_fd_htab_map_lookup_elem(map, key, value);
61915a07b33SAlexei Starovoitov 	} else {
6208ebe667cSAlexei Starovoitov 		rcu_read_lock();
6218ebe667cSAlexei Starovoitov 		ptr = map->ops->map_lookup_elem(map, key);
6228ebe667cSAlexei Starovoitov 		if (ptr)
62315a07b33SAlexei Starovoitov 			memcpy(value, ptr, value_size);
6248ebe667cSAlexei Starovoitov 		rcu_read_unlock();
62515a07b33SAlexei Starovoitov 		err = ptr ? 0 : -ENOENT;
62615a07b33SAlexei Starovoitov 	}
6278ebe667cSAlexei Starovoitov 
62815a07b33SAlexei Starovoitov 	if (err)
6298ebe667cSAlexei Starovoitov 		goto free_value;
630db20fd2bSAlexei Starovoitov 
631db20fd2bSAlexei Starovoitov 	err = -EFAULT;
63215a07b33SAlexei Starovoitov 	if (copy_to_user(uvalue, value, value_size) != 0)
6338ebe667cSAlexei Starovoitov 		goto free_value;
634db20fd2bSAlexei Starovoitov 
635a67edbf4SDaniel Borkmann 	trace_bpf_map_lookup_elem(map, ufd, key, value);
636db20fd2bSAlexei Starovoitov 	err = 0;
637db20fd2bSAlexei Starovoitov 
6388ebe667cSAlexei Starovoitov free_value:
6398ebe667cSAlexei Starovoitov 	kfree(value);
640db20fd2bSAlexei Starovoitov free_key:
641db20fd2bSAlexei Starovoitov 	kfree(key);
642db20fd2bSAlexei Starovoitov err_put:
643db20fd2bSAlexei Starovoitov 	fdput(f);
644db20fd2bSAlexei Starovoitov 	return err;
645db20fd2bSAlexei Starovoitov }
646db20fd2bSAlexei Starovoitov 
6473274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags
648db20fd2bSAlexei Starovoitov 
649db20fd2bSAlexei Starovoitov static int map_update_elem(union bpf_attr *attr)
650db20fd2bSAlexei Starovoitov {
651535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
652535e7b4bSMickaël Salaün 	void __user *uvalue = u64_to_user_ptr(attr->value);
653db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
654db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
655db20fd2bSAlexei Starovoitov 	void *key, *value;
65615a07b33SAlexei Starovoitov 	u32 value_size;
657592867bfSDaniel Borkmann 	struct fd f;
658db20fd2bSAlexei Starovoitov 	int err;
659db20fd2bSAlexei Starovoitov 
660db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM))
661db20fd2bSAlexei Starovoitov 		return -EINVAL;
662db20fd2bSAlexei Starovoitov 
663592867bfSDaniel Borkmann 	f = fdget(ufd);
664c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
665db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
666db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
667db20fd2bSAlexei Starovoitov 
6686e71b04aSChenbo Feng 	if (!(f.file->f_mode & FMODE_CAN_WRITE)) {
6696e71b04aSChenbo Feng 		err = -EPERM;
6706e71b04aSChenbo Feng 		goto err_put;
6716e71b04aSChenbo Feng 	}
6726e71b04aSChenbo Feng 
673e4448ed8SAl Viro 	key = memdup_user(ukey, map->key_size);
674e4448ed8SAl Viro 	if (IS_ERR(key)) {
675e4448ed8SAl Viro 		err = PTR_ERR(key);
676db20fd2bSAlexei Starovoitov 		goto err_put;
677e4448ed8SAl Viro 	}
678db20fd2bSAlexei Starovoitov 
67915a07b33SAlexei Starovoitov 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
6808f844938SMartin KaFai Lau 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
68115a07b33SAlexei Starovoitov 	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
68215a07b33SAlexei Starovoitov 		value_size = round_up(map->value_size, 8) * num_possible_cpus();
68315a07b33SAlexei Starovoitov 	else
68415a07b33SAlexei Starovoitov 		value_size = map->value_size;
68515a07b33SAlexei Starovoitov 
686db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
68715a07b33SAlexei Starovoitov 	value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
688db20fd2bSAlexei Starovoitov 	if (!value)
689db20fd2bSAlexei Starovoitov 		goto free_key;
690db20fd2bSAlexei Starovoitov 
691db20fd2bSAlexei Starovoitov 	err = -EFAULT;
69215a07b33SAlexei Starovoitov 	if (copy_from_user(value, uvalue, value_size) != 0)
693db20fd2bSAlexei Starovoitov 		goto free_value;
694db20fd2bSAlexei Starovoitov 
6956710e112SJesper Dangaard Brouer 	/* Need to create a kthread, thus must support schedule */
696a3884572SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
697a3884572SJakub Kicinski 		err = bpf_map_offload_update_elem(map, key, value, attr->flags);
698a3884572SJakub Kicinski 		goto out;
699a3884572SJakub Kicinski 	} else if (map->map_type == BPF_MAP_TYPE_CPUMAP) {
7006710e112SJesper Dangaard Brouer 		err = map->ops->map_update_elem(map, key, value, attr->flags);
7016710e112SJesper Dangaard Brouer 		goto out;
7026710e112SJesper Dangaard Brouer 	}
7036710e112SJesper Dangaard Brouer 
704b121d1e7SAlexei Starovoitov 	/* must increment bpf_prog_active to avoid kprobe+bpf triggering from
705b121d1e7SAlexei Starovoitov 	 * inside bpf map update or delete otherwise deadlocks are possible
706b121d1e7SAlexei Starovoitov 	 */
707b121d1e7SAlexei Starovoitov 	preempt_disable();
708b121d1e7SAlexei Starovoitov 	__this_cpu_inc(bpf_prog_active);
7098f844938SMartin KaFai Lau 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
7108f844938SMartin KaFai Lau 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
71115a07b33SAlexei Starovoitov 		err = bpf_percpu_hash_update(map, key, value, attr->flags);
71215a07b33SAlexei Starovoitov 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
71315a07b33SAlexei Starovoitov 		err = bpf_percpu_array_update(map, key, value, attr->flags);
7149c147b56SMickaël Salaün 	} else if (IS_FD_ARRAY(map)) {
715d056a788SDaniel Borkmann 		rcu_read_lock();
716d056a788SDaniel Borkmann 		err = bpf_fd_array_map_update_elem(map, f.file, key, value,
717d056a788SDaniel Borkmann 						   attr->flags);
718d056a788SDaniel Borkmann 		rcu_read_unlock();
719bcc6b1b7SMartin KaFai Lau 	} else if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) {
720bcc6b1b7SMartin KaFai Lau 		rcu_read_lock();
721bcc6b1b7SMartin KaFai Lau 		err = bpf_fd_htab_map_update_elem(map, f.file, key, value,
722bcc6b1b7SMartin KaFai Lau 						  attr->flags);
723bcc6b1b7SMartin KaFai Lau 		rcu_read_unlock();
72415a07b33SAlexei Starovoitov 	} else {
725db20fd2bSAlexei Starovoitov 		rcu_read_lock();
7263274f520SAlexei Starovoitov 		err = map->ops->map_update_elem(map, key, value, attr->flags);
727db20fd2bSAlexei Starovoitov 		rcu_read_unlock();
72815a07b33SAlexei Starovoitov 	}
729b121d1e7SAlexei Starovoitov 	__this_cpu_dec(bpf_prog_active);
730b121d1e7SAlexei Starovoitov 	preempt_enable();
7316710e112SJesper Dangaard Brouer out:
732a67edbf4SDaniel Borkmann 	if (!err)
733a67edbf4SDaniel Borkmann 		trace_bpf_map_update_elem(map, ufd, key, value);
734db20fd2bSAlexei Starovoitov free_value:
735db20fd2bSAlexei Starovoitov 	kfree(value);
736db20fd2bSAlexei Starovoitov free_key:
737db20fd2bSAlexei Starovoitov 	kfree(key);
738db20fd2bSAlexei Starovoitov err_put:
739db20fd2bSAlexei Starovoitov 	fdput(f);
740db20fd2bSAlexei Starovoitov 	return err;
741db20fd2bSAlexei Starovoitov }
742db20fd2bSAlexei Starovoitov 
743db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key
744db20fd2bSAlexei Starovoitov 
745db20fd2bSAlexei Starovoitov static int map_delete_elem(union bpf_attr *attr)
746db20fd2bSAlexei Starovoitov {
747535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
748db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
749db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
750592867bfSDaniel Borkmann 	struct fd f;
751db20fd2bSAlexei Starovoitov 	void *key;
752db20fd2bSAlexei Starovoitov 	int err;
753db20fd2bSAlexei Starovoitov 
754db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_DELETE_ELEM))
755db20fd2bSAlexei Starovoitov 		return -EINVAL;
756db20fd2bSAlexei Starovoitov 
757592867bfSDaniel Borkmann 	f = fdget(ufd);
758c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
759db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
760db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
761db20fd2bSAlexei Starovoitov 
7626e71b04aSChenbo Feng 	if (!(f.file->f_mode & FMODE_CAN_WRITE)) {
7636e71b04aSChenbo Feng 		err = -EPERM;
7646e71b04aSChenbo Feng 		goto err_put;
7656e71b04aSChenbo Feng 	}
7666e71b04aSChenbo Feng 
767e4448ed8SAl Viro 	key = memdup_user(ukey, map->key_size);
768e4448ed8SAl Viro 	if (IS_ERR(key)) {
769e4448ed8SAl Viro 		err = PTR_ERR(key);
770db20fd2bSAlexei Starovoitov 		goto err_put;
771e4448ed8SAl Viro 	}
772db20fd2bSAlexei Starovoitov 
773a3884572SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
774a3884572SJakub Kicinski 		err = bpf_map_offload_delete_elem(map, key);
775a3884572SJakub Kicinski 		goto out;
776a3884572SJakub Kicinski 	}
777a3884572SJakub Kicinski 
778b121d1e7SAlexei Starovoitov 	preempt_disable();
779b121d1e7SAlexei Starovoitov 	__this_cpu_inc(bpf_prog_active);
780db20fd2bSAlexei Starovoitov 	rcu_read_lock();
781db20fd2bSAlexei Starovoitov 	err = map->ops->map_delete_elem(map, key);
782db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
783b121d1e7SAlexei Starovoitov 	__this_cpu_dec(bpf_prog_active);
784b121d1e7SAlexei Starovoitov 	preempt_enable();
785a3884572SJakub Kicinski out:
786a67edbf4SDaniel Borkmann 	if (!err)
787a67edbf4SDaniel Borkmann 		trace_bpf_map_delete_elem(map, ufd, key);
788db20fd2bSAlexei Starovoitov 	kfree(key);
789db20fd2bSAlexei Starovoitov err_put:
790db20fd2bSAlexei Starovoitov 	fdput(f);
791db20fd2bSAlexei Starovoitov 	return err;
792db20fd2bSAlexei Starovoitov }
793db20fd2bSAlexei Starovoitov 
794db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
795db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key
796db20fd2bSAlexei Starovoitov 
797db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr)
798db20fd2bSAlexei Starovoitov {
799535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
800535e7b4bSMickaël Salaün 	void __user *unext_key = u64_to_user_ptr(attr->next_key);
801db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
802db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
803db20fd2bSAlexei Starovoitov 	void *key, *next_key;
804592867bfSDaniel Borkmann 	struct fd f;
805db20fd2bSAlexei Starovoitov 	int err;
806db20fd2bSAlexei Starovoitov 
807db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY))
808db20fd2bSAlexei Starovoitov 		return -EINVAL;
809db20fd2bSAlexei Starovoitov 
810592867bfSDaniel Borkmann 	f = fdget(ufd);
811c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
812db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
813db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
814db20fd2bSAlexei Starovoitov 
8156e71b04aSChenbo Feng 	if (!(f.file->f_mode & FMODE_CAN_READ)) {
8166e71b04aSChenbo Feng 		err = -EPERM;
8176e71b04aSChenbo Feng 		goto err_put;
8186e71b04aSChenbo Feng 	}
8196e71b04aSChenbo Feng 
8208fe45924STeng Qin 	if (ukey) {
821e4448ed8SAl Viro 		key = memdup_user(ukey, map->key_size);
822e4448ed8SAl Viro 		if (IS_ERR(key)) {
823e4448ed8SAl Viro 			err = PTR_ERR(key);
824db20fd2bSAlexei Starovoitov 			goto err_put;
825e4448ed8SAl Viro 		}
8268fe45924STeng Qin 	} else {
8278fe45924STeng Qin 		key = NULL;
8288fe45924STeng Qin 	}
829db20fd2bSAlexei Starovoitov 
830db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
831db20fd2bSAlexei Starovoitov 	next_key = kmalloc(map->key_size, GFP_USER);
832db20fd2bSAlexei Starovoitov 	if (!next_key)
833db20fd2bSAlexei Starovoitov 		goto free_key;
834db20fd2bSAlexei Starovoitov 
835a3884572SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
836a3884572SJakub Kicinski 		err = bpf_map_offload_get_next_key(map, key, next_key);
837a3884572SJakub Kicinski 		goto out;
838a3884572SJakub Kicinski 	}
839a3884572SJakub Kicinski 
840db20fd2bSAlexei Starovoitov 	rcu_read_lock();
841db20fd2bSAlexei Starovoitov 	err = map->ops->map_get_next_key(map, key, next_key);
842db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
843a3884572SJakub Kicinski out:
844db20fd2bSAlexei Starovoitov 	if (err)
845db20fd2bSAlexei Starovoitov 		goto free_next_key;
846db20fd2bSAlexei Starovoitov 
847db20fd2bSAlexei Starovoitov 	err = -EFAULT;
848db20fd2bSAlexei Starovoitov 	if (copy_to_user(unext_key, next_key, map->key_size) != 0)
849db20fd2bSAlexei Starovoitov 		goto free_next_key;
850db20fd2bSAlexei Starovoitov 
851a67edbf4SDaniel Borkmann 	trace_bpf_map_next_key(map, ufd, key, next_key);
852db20fd2bSAlexei Starovoitov 	err = 0;
853db20fd2bSAlexei Starovoitov 
854db20fd2bSAlexei Starovoitov free_next_key:
855db20fd2bSAlexei Starovoitov 	kfree(next_key);
856db20fd2bSAlexei Starovoitov free_key:
857db20fd2bSAlexei Starovoitov 	kfree(key);
858db20fd2bSAlexei Starovoitov err_put:
859db20fd2bSAlexei Starovoitov 	fdput(f);
860db20fd2bSAlexei Starovoitov 	return err;
861db20fd2bSAlexei Starovoitov }
862db20fd2bSAlexei Starovoitov 
8637de16e3aSJakub Kicinski static const struct bpf_prog_ops * const bpf_prog_types[] = {
8647de16e3aSJakub Kicinski #define BPF_PROG_TYPE(_id, _name) \
8657de16e3aSJakub Kicinski 	[_id] = & _name ## _prog_ops,
8667de16e3aSJakub Kicinski #define BPF_MAP_TYPE(_id, _ops)
8677de16e3aSJakub Kicinski #include <linux/bpf_types.h>
8687de16e3aSJakub Kicinski #undef BPF_PROG_TYPE
8697de16e3aSJakub Kicinski #undef BPF_MAP_TYPE
8707de16e3aSJakub Kicinski };
8717de16e3aSJakub Kicinski 
87209756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
87309756af4SAlexei Starovoitov {
874be9370a7SJohannes Berg 	if (type >= ARRAY_SIZE(bpf_prog_types) || !bpf_prog_types[type])
875be9370a7SJohannes Berg 		return -EINVAL;
87609756af4SAlexei Starovoitov 
877ab3f0063SJakub Kicinski 	if (!bpf_prog_is_dev_bound(prog->aux))
878be9370a7SJohannes Berg 		prog->aux->ops = bpf_prog_types[type];
879ab3f0063SJakub Kicinski 	else
880ab3f0063SJakub Kicinski 		prog->aux->ops = &bpf_offload_prog_ops;
88124701eceSDaniel Borkmann 	prog->type = type;
88209756af4SAlexei Starovoitov 	return 0;
88309756af4SAlexei Starovoitov }
88409756af4SAlexei Starovoitov 
88509756af4SAlexei Starovoitov /* drop refcnt on maps used by eBPF program and free auxilary data */
88609756af4SAlexei Starovoitov static void free_used_maps(struct bpf_prog_aux *aux)
88709756af4SAlexei Starovoitov {
88809756af4SAlexei Starovoitov 	int i;
88909756af4SAlexei Starovoitov 
89009756af4SAlexei Starovoitov 	for (i = 0; i < aux->used_map_cnt; i++)
89109756af4SAlexei Starovoitov 		bpf_map_put(aux->used_maps[i]);
89209756af4SAlexei Starovoitov 
89309756af4SAlexei Starovoitov 	kfree(aux->used_maps);
89409756af4SAlexei Starovoitov }
89509756af4SAlexei Starovoitov 
8965ccb071eSDaniel Borkmann int __bpf_prog_charge(struct user_struct *user, u32 pages)
8975ccb071eSDaniel Borkmann {
8985ccb071eSDaniel Borkmann 	unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
8995ccb071eSDaniel Borkmann 	unsigned long user_bufs;
9005ccb071eSDaniel Borkmann 
9015ccb071eSDaniel Borkmann 	if (user) {
9025ccb071eSDaniel Borkmann 		user_bufs = atomic_long_add_return(pages, &user->locked_vm);
9035ccb071eSDaniel Borkmann 		if (user_bufs > memlock_limit) {
9045ccb071eSDaniel Borkmann 			atomic_long_sub(pages, &user->locked_vm);
9055ccb071eSDaniel Borkmann 			return -EPERM;
9065ccb071eSDaniel Borkmann 		}
9075ccb071eSDaniel Borkmann 	}
9085ccb071eSDaniel Borkmann 
9095ccb071eSDaniel Borkmann 	return 0;
9105ccb071eSDaniel Borkmann }
9115ccb071eSDaniel Borkmann 
9125ccb071eSDaniel Borkmann void __bpf_prog_uncharge(struct user_struct *user, u32 pages)
9135ccb071eSDaniel Borkmann {
9145ccb071eSDaniel Borkmann 	if (user)
9155ccb071eSDaniel Borkmann 		atomic_long_sub(pages, &user->locked_vm);
9165ccb071eSDaniel Borkmann }
9175ccb071eSDaniel Borkmann 
918aaac3ba9SAlexei Starovoitov static int bpf_prog_charge_memlock(struct bpf_prog *prog)
919aaac3ba9SAlexei Starovoitov {
920aaac3ba9SAlexei Starovoitov 	struct user_struct *user = get_current_user();
9215ccb071eSDaniel Borkmann 	int ret;
922aaac3ba9SAlexei Starovoitov 
9235ccb071eSDaniel Borkmann 	ret = __bpf_prog_charge(user, prog->pages);
9245ccb071eSDaniel Borkmann 	if (ret) {
925aaac3ba9SAlexei Starovoitov 		free_uid(user);
9265ccb071eSDaniel Borkmann 		return ret;
927aaac3ba9SAlexei Starovoitov 	}
9285ccb071eSDaniel Borkmann 
929aaac3ba9SAlexei Starovoitov 	prog->aux->user = user;
930aaac3ba9SAlexei Starovoitov 	return 0;
931aaac3ba9SAlexei Starovoitov }
932aaac3ba9SAlexei Starovoitov 
933aaac3ba9SAlexei Starovoitov static void bpf_prog_uncharge_memlock(struct bpf_prog *prog)
934aaac3ba9SAlexei Starovoitov {
935aaac3ba9SAlexei Starovoitov 	struct user_struct *user = prog->aux->user;
936aaac3ba9SAlexei Starovoitov 
9375ccb071eSDaniel Borkmann 	__bpf_prog_uncharge(user, prog->pages);
938aaac3ba9SAlexei Starovoitov 	free_uid(user);
939aaac3ba9SAlexei Starovoitov }
940aaac3ba9SAlexei Starovoitov 
941dc4bb0e2SMartin KaFai Lau static int bpf_prog_alloc_id(struct bpf_prog *prog)
942dc4bb0e2SMartin KaFai Lau {
943dc4bb0e2SMartin KaFai Lau 	int id;
944dc4bb0e2SMartin KaFai Lau 
945b76354cdSShaohua Li 	idr_preload(GFP_KERNEL);
946dc4bb0e2SMartin KaFai Lau 	spin_lock_bh(&prog_idr_lock);
947dc4bb0e2SMartin KaFai Lau 	id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC);
948dc4bb0e2SMartin KaFai Lau 	if (id > 0)
949dc4bb0e2SMartin KaFai Lau 		prog->aux->id = id;
950dc4bb0e2SMartin KaFai Lau 	spin_unlock_bh(&prog_idr_lock);
951b76354cdSShaohua Li 	idr_preload_end();
952dc4bb0e2SMartin KaFai Lau 
953dc4bb0e2SMartin KaFai Lau 	/* id is in [1, INT_MAX) */
954dc4bb0e2SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
955dc4bb0e2SMartin KaFai Lau 		return -ENOSPC;
956dc4bb0e2SMartin KaFai Lau 
957dc4bb0e2SMartin KaFai Lau 	return id > 0 ? 0 : id;
958dc4bb0e2SMartin KaFai Lau }
959dc4bb0e2SMartin KaFai Lau 
960ad8ad79fSJakub Kicinski void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
961dc4bb0e2SMartin KaFai Lau {
962ad8ad79fSJakub Kicinski 	/* cBPF to eBPF migrations are currently not in the idr store.
963ad8ad79fSJakub Kicinski 	 * Offloaded programs are removed from the store when their device
964ad8ad79fSJakub Kicinski 	 * disappears - even if someone grabs an fd to them they are unusable,
965ad8ad79fSJakub Kicinski 	 * simply waiting for refcnt to drop to be freed.
966ad8ad79fSJakub Kicinski 	 */
967dc4bb0e2SMartin KaFai Lau 	if (!prog->aux->id)
968dc4bb0e2SMartin KaFai Lau 		return;
969dc4bb0e2SMartin KaFai Lau 
970b16d9aa4SMartin KaFai Lau 	if (do_idr_lock)
971dc4bb0e2SMartin KaFai Lau 		spin_lock_bh(&prog_idr_lock);
972b16d9aa4SMartin KaFai Lau 	else
973b16d9aa4SMartin KaFai Lau 		__acquire(&prog_idr_lock);
974b16d9aa4SMartin KaFai Lau 
975dc4bb0e2SMartin KaFai Lau 	idr_remove(&prog_idr, prog->aux->id);
976ad8ad79fSJakub Kicinski 	prog->aux->id = 0;
977b16d9aa4SMartin KaFai Lau 
978b16d9aa4SMartin KaFai Lau 	if (do_idr_lock)
979dc4bb0e2SMartin KaFai Lau 		spin_unlock_bh(&prog_idr_lock);
980b16d9aa4SMartin KaFai Lau 	else
981b16d9aa4SMartin KaFai Lau 		__release(&prog_idr_lock);
982dc4bb0e2SMartin KaFai Lau }
983dc4bb0e2SMartin KaFai Lau 
9841aacde3dSDaniel Borkmann static void __bpf_prog_put_rcu(struct rcu_head *rcu)
985abf2e7d6SAlexei Starovoitov {
986abf2e7d6SAlexei Starovoitov 	struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
987abf2e7d6SAlexei Starovoitov 
988abf2e7d6SAlexei Starovoitov 	free_used_maps(aux);
989aaac3ba9SAlexei Starovoitov 	bpf_prog_uncharge_memlock(aux->prog);
990afdb09c7SChenbo Feng 	security_bpf_prog_free(aux);
991abf2e7d6SAlexei Starovoitov 	bpf_prog_free(aux->prog);
992abf2e7d6SAlexei Starovoitov }
993abf2e7d6SAlexei Starovoitov 
994b16d9aa4SMartin KaFai Lau static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock)
99509756af4SAlexei Starovoitov {
996a67edbf4SDaniel Borkmann 	if (atomic_dec_and_test(&prog->aux->refcnt)) {
9974f74d809SDaniel Borkmann 		int i;
9984f74d809SDaniel Borkmann 
999a67edbf4SDaniel Borkmann 		trace_bpf_prog_put_rcu(prog);
100034ad5580SMartin KaFai Lau 		/* bpf_prog_free_id() must be called first */
1001b16d9aa4SMartin KaFai Lau 		bpf_prog_free_id(prog, do_idr_lock);
10024f74d809SDaniel Borkmann 
10034f74d809SDaniel Borkmann 		for (i = 0; i < prog->aux->func_cnt; i++)
10044f74d809SDaniel Borkmann 			bpf_prog_kallsyms_del(prog->aux->func[i]);
100574451e66SDaniel Borkmann 		bpf_prog_kallsyms_del(prog);
10064f74d809SDaniel Borkmann 
10071aacde3dSDaniel Borkmann 		call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
100809756af4SAlexei Starovoitov 	}
1009a67edbf4SDaniel Borkmann }
1010b16d9aa4SMartin KaFai Lau 
1011b16d9aa4SMartin KaFai Lau void bpf_prog_put(struct bpf_prog *prog)
1012b16d9aa4SMartin KaFai Lau {
1013b16d9aa4SMartin KaFai Lau 	__bpf_prog_put(prog, true);
1014b16d9aa4SMartin KaFai Lau }
1015e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put);
101609756af4SAlexei Starovoitov 
101709756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp)
101809756af4SAlexei Starovoitov {
101909756af4SAlexei Starovoitov 	struct bpf_prog *prog = filp->private_data;
102009756af4SAlexei Starovoitov 
10211aacde3dSDaniel Borkmann 	bpf_prog_put(prog);
102209756af4SAlexei Starovoitov 	return 0;
102309756af4SAlexei Starovoitov }
102409756af4SAlexei Starovoitov 
10257bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
10267bd509e3SDaniel Borkmann static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp)
10277bd509e3SDaniel Borkmann {
10287bd509e3SDaniel Borkmann 	const struct bpf_prog *prog = filp->private_data;
1029f1f7714eSDaniel Borkmann 	char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
10307bd509e3SDaniel Borkmann 
1031f1f7714eSDaniel Borkmann 	bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
10327bd509e3SDaniel Borkmann 	seq_printf(m,
10337bd509e3SDaniel Borkmann 		   "prog_type:\t%u\n"
10347bd509e3SDaniel Borkmann 		   "prog_jited:\t%u\n"
1035f1f7714eSDaniel Borkmann 		   "prog_tag:\t%s\n"
10367bd509e3SDaniel Borkmann 		   "memlock:\t%llu\n",
10377bd509e3SDaniel Borkmann 		   prog->type,
10387bd509e3SDaniel Borkmann 		   prog->jited,
1039f1f7714eSDaniel Borkmann 		   prog_tag,
10407bd509e3SDaniel Borkmann 		   prog->pages * 1ULL << PAGE_SHIFT);
10417bd509e3SDaniel Borkmann }
10427bd509e3SDaniel Borkmann #endif
10437bd509e3SDaniel Borkmann 
1044f66e448cSChenbo Feng const struct file_operations bpf_prog_fops = {
10457bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
10467bd509e3SDaniel Borkmann 	.show_fdinfo	= bpf_prog_show_fdinfo,
10477bd509e3SDaniel Borkmann #endif
104809756af4SAlexei Starovoitov 	.release	= bpf_prog_release,
10496e71b04aSChenbo Feng 	.read		= bpf_dummy_read,
10506e71b04aSChenbo Feng 	.write		= bpf_dummy_write,
105109756af4SAlexei Starovoitov };
105209756af4SAlexei Starovoitov 
1053b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog)
1054aa79781bSDaniel Borkmann {
1055afdb09c7SChenbo Feng 	int ret;
1056afdb09c7SChenbo Feng 
1057afdb09c7SChenbo Feng 	ret = security_bpf_prog(prog);
1058afdb09c7SChenbo Feng 	if (ret < 0)
1059afdb09c7SChenbo Feng 		return ret;
1060afdb09c7SChenbo Feng 
1061aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog,
1062aa79781bSDaniel Borkmann 				O_RDWR | O_CLOEXEC);
1063aa79781bSDaniel Borkmann }
1064aa79781bSDaniel Borkmann 
1065113214beSDaniel Borkmann static struct bpf_prog *____bpf_prog_get(struct fd f)
106609756af4SAlexei Starovoitov {
106709756af4SAlexei Starovoitov 	if (!f.file)
106809756af4SAlexei Starovoitov 		return ERR_PTR(-EBADF);
106909756af4SAlexei Starovoitov 	if (f.file->f_op != &bpf_prog_fops) {
107009756af4SAlexei Starovoitov 		fdput(f);
107109756af4SAlexei Starovoitov 		return ERR_PTR(-EINVAL);
107209756af4SAlexei Starovoitov 	}
107309756af4SAlexei Starovoitov 
1074c2101297SDaniel Borkmann 	return f.file->private_data;
107509756af4SAlexei Starovoitov }
107609756af4SAlexei Starovoitov 
107759d3656dSBrenden Blanco struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i)
107892117d84SAlexei Starovoitov {
107959d3656dSBrenden Blanco 	if (atomic_add_return(i, &prog->aux->refcnt) > BPF_MAX_REFCNT) {
108059d3656dSBrenden Blanco 		atomic_sub(i, &prog->aux->refcnt);
108192117d84SAlexei Starovoitov 		return ERR_PTR(-EBUSY);
108292117d84SAlexei Starovoitov 	}
108392117d84SAlexei Starovoitov 	return prog;
108492117d84SAlexei Starovoitov }
108559d3656dSBrenden Blanco EXPORT_SYMBOL_GPL(bpf_prog_add);
108659d3656dSBrenden Blanco 
1087c540594fSDaniel Borkmann void bpf_prog_sub(struct bpf_prog *prog, int i)
1088c540594fSDaniel Borkmann {
1089c540594fSDaniel Borkmann 	/* Only to be used for undoing previous bpf_prog_add() in some
1090c540594fSDaniel Borkmann 	 * error path. We still know that another entity in our call
1091c540594fSDaniel Borkmann 	 * path holds a reference to the program, thus atomic_sub() can
1092c540594fSDaniel Borkmann 	 * be safely used in such cases!
1093c540594fSDaniel Borkmann 	 */
1094c540594fSDaniel Borkmann 	WARN_ON(atomic_sub_return(i, &prog->aux->refcnt) == 0);
1095c540594fSDaniel Borkmann }
1096c540594fSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_sub);
1097c540594fSDaniel Borkmann 
109859d3656dSBrenden Blanco struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog)
109959d3656dSBrenden Blanco {
110059d3656dSBrenden Blanco 	return bpf_prog_add(prog, 1);
110159d3656dSBrenden Blanco }
110297bc402dSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_inc);
110392117d84SAlexei Starovoitov 
1104b16d9aa4SMartin KaFai Lau /* prog_idr_lock should have been held */
1105a6f6df69SJohn Fastabend struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog)
1106b16d9aa4SMartin KaFai Lau {
1107b16d9aa4SMartin KaFai Lau 	int refold;
1108b16d9aa4SMartin KaFai Lau 
1109b16d9aa4SMartin KaFai Lau 	refold = __atomic_add_unless(&prog->aux->refcnt, 1, 0);
1110b16d9aa4SMartin KaFai Lau 
1111b16d9aa4SMartin KaFai Lau 	if (refold >= BPF_MAX_REFCNT) {
1112b16d9aa4SMartin KaFai Lau 		__bpf_prog_put(prog, false);
1113b16d9aa4SMartin KaFai Lau 		return ERR_PTR(-EBUSY);
1114b16d9aa4SMartin KaFai Lau 	}
1115b16d9aa4SMartin KaFai Lau 
1116b16d9aa4SMartin KaFai Lau 	if (!refold)
1117b16d9aa4SMartin KaFai Lau 		return ERR_PTR(-ENOENT);
1118b16d9aa4SMartin KaFai Lau 
1119b16d9aa4SMartin KaFai Lau 	return prog;
1120b16d9aa4SMartin KaFai Lau }
1121a6f6df69SJohn Fastabend EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero);
1122b16d9aa4SMartin KaFai Lau 
1123040ee692SAl Viro bool bpf_prog_get_ok(struct bpf_prog *prog,
1124288b3de5SJakub Kicinski 			    enum bpf_prog_type *attach_type, bool attach_drv)
1125248f346fSJakub Kicinski {
1126288b3de5SJakub Kicinski 	/* not an attachment, just a refcount inc, always allow */
1127288b3de5SJakub Kicinski 	if (!attach_type)
1128288b3de5SJakub Kicinski 		return true;
1129248f346fSJakub Kicinski 
1130248f346fSJakub Kicinski 	if (prog->type != *attach_type)
1131248f346fSJakub Kicinski 		return false;
1132288b3de5SJakub Kicinski 	if (bpf_prog_is_dev_bound(prog->aux) && !attach_drv)
1133248f346fSJakub Kicinski 		return false;
1134248f346fSJakub Kicinski 
1135248f346fSJakub Kicinski 	return true;
1136248f346fSJakub Kicinski }
1137248f346fSJakub Kicinski 
1138248f346fSJakub Kicinski static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type,
1139288b3de5SJakub Kicinski 				       bool attach_drv)
114009756af4SAlexei Starovoitov {
114109756af4SAlexei Starovoitov 	struct fd f = fdget(ufd);
114209756af4SAlexei Starovoitov 	struct bpf_prog *prog;
114309756af4SAlexei Starovoitov 
1144113214beSDaniel Borkmann 	prog = ____bpf_prog_get(f);
114509756af4SAlexei Starovoitov 	if (IS_ERR(prog))
114609756af4SAlexei Starovoitov 		return prog;
1147288b3de5SJakub Kicinski 	if (!bpf_prog_get_ok(prog, attach_type, attach_drv)) {
1148113214beSDaniel Borkmann 		prog = ERR_PTR(-EINVAL);
1149113214beSDaniel Borkmann 		goto out;
1150113214beSDaniel Borkmann 	}
115109756af4SAlexei Starovoitov 
115292117d84SAlexei Starovoitov 	prog = bpf_prog_inc(prog);
1153113214beSDaniel Borkmann out:
115409756af4SAlexei Starovoitov 	fdput(f);
115509756af4SAlexei Starovoitov 	return prog;
115609756af4SAlexei Starovoitov }
1157113214beSDaniel Borkmann 
1158113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get(u32 ufd)
1159113214beSDaniel Borkmann {
1160288b3de5SJakub Kicinski 	return __bpf_prog_get(ufd, NULL, false);
1161113214beSDaniel Borkmann }
1162113214beSDaniel Borkmann 
1163248f346fSJakub Kicinski struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type,
1164288b3de5SJakub Kicinski 				       bool attach_drv)
1165248f346fSJakub Kicinski {
1166288b3de5SJakub Kicinski 	struct bpf_prog *prog = __bpf_prog_get(ufd, &type, attach_drv);
1167248f346fSJakub Kicinski 
1168248f346fSJakub Kicinski 	if (!IS_ERR(prog))
1169248f346fSJakub Kicinski 		trace_bpf_prog_get_type(prog);
1170248f346fSJakub Kicinski 	return prog;
1171248f346fSJakub Kicinski }
11726c8dfe21SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_prog_get_type_dev);
1173248f346fSJakub Kicinski 
11745e43f899SAndrey Ignatov static int
11755e43f899SAndrey Ignatov bpf_prog_load_check_attach_type(enum bpf_prog_type prog_type,
11765e43f899SAndrey Ignatov 				enum bpf_attach_type expected_attach_type)
11775e43f899SAndrey Ignatov {
11784fbac77dSAndrey Ignatov 	switch (prog_type) {
11794fbac77dSAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
11804fbac77dSAndrey Ignatov 		switch (expected_attach_type) {
11814fbac77dSAndrey Ignatov 		case BPF_CGROUP_INET4_BIND:
11824fbac77dSAndrey Ignatov 		case BPF_CGROUP_INET6_BIND:
1183*d74bad4eSAndrey Ignatov 		case BPF_CGROUP_INET4_CONNECT:
1184*d74bad4eSAndrey Ignatov 		case BPF_CGROUP_INET6_CONNECT:
11855e43f899SAndrey Ignatov 			return 0;
11864fbac77dSAndrey Ignatov 		default:
11874fbac77dSAndrey Ignatov 			return -EINVAL;
11884fbac77dSAndrey Ignatov 		}
11894fbac77dSAndrey Ignatov 	default:
11904fbac77dSAndrey Ignatov 		return 0;
11914fbac77dSAndrey Ignatov 	}
11925e43f899SAndrey Ignatov }
11935e43f899SAndrey Ignatov 
11945e43f899SAndrey Ignatov static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog,
11955e43f899SAndrey Ignatov 					     enum bpf_attach_type attach_type)
11965e43f899SAndrey Ignatov {
11974fbac77dSAndrey Ignatov 	switch (prog->type) {
11984fbac77dSAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
11994fbac77dSAndrey Ignatov 		return attach_type == prog->expected_attach_type ? 0 : -EINVAL;
12004fbac77dSAndrey Ignatov 	default:
12015e43f899SAndrey Ignatov 		return 0;
12025e43f899SAndrey Ignatov 	}
12034fbac77dSAndrey Ignatov }
12045e43f899SAndrey Ignatov 
120509756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
12065e43f899SAndrey Ignatov #define	BPF_PROG_LOAD_LAST_FIELD expected_attach_type
120709756af4SAlexei Starovoitov 
120809756af4SAlexei Starovoitov static int bpf_prog_load(union bpf_attr *attr)
120909756af4SAlexei Starovoitov {
121009756af4SAlexei Starovoitov 	enum bpf_prog_type type = attr->prog_type;
121109756af4SAlexei Starovoitov 	struct bpf_prog *prog;
121209756af4SAlexei Starovoitov 	int err;
121309756af4SAlexei Starovoitov 	char license[128];
121409756af4SAlexei Starovoitov 	bool is_gpl;
121509756af4SAlexei Starovoitov 
121609756af4SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_LOAD))
121709756af4SAlexei Starovoitov 		return -EINVAL;
121809756af4SAlexei Starovoitov 
1219e07b98d9SDavid S. Miller 	if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT)
1220e07b98d9SDavid S. Miller 		return -EINVAL;
1221e07b98d9SDavid S. Miller 
122209756af4SAlexei Starovoitov 	/* copy eBPF program license from user space */
1223535e7b4bSMickaël Salaün 	if (strncpy_from_user(license, u64_to_user_ptr(attr->license),
122409756af4SAlexei Starovoitov 			      sizeof(license) - 1) < 0)
122509756af4SAlexei Starovoitov 		return -EFAULT;
122609756af4SAlexei Starovoitov 	license[sizeof(license) - 1] = 0;
122709756af4SAlexei Starovoitov 
122809756af4SAlexei Starovoitov 	/* eBPF programs must be GPL compatible to use GPL-ed functions */
122909756af4SAlexei Starovoitov 	is_gpl = license_is_gpl_compatible(license);
123009756af4SAlexei Starovoitov 
1231ef0915caSDaniel Borkmann 	if (attr->insn_cnt == 0 || attr->insn_cnt > BPF_MAXINSNS)
1232ef0915caSDaniel Borkmann 		return -E2BIG;
123309756af4SAlexei Starovoitov 
12342541517cSAlexei Starovoitov 	if (type == BPF_PROG_TYPE_KPROBE &&
12352541517cSAlexei Starovoitov 	    attr->kern_version != LINUX_VERSION_CODE)
12362541517cSAlexei Starovoitov 		return -EINVAL;
12372541517cSAlexei Starovoitov 
123880b7d819SChenbo Feng 	if (type != BPF_PROG_TYPE_SOCKET_FILTER &&
123980b7d819SChenbo Feng 	    type != BPF_PROG_TYPE_CGROUP_SKB &&
124080b7d819SChenbo Feng 	    !capable(CAP_SYS_ADMIN))
12411be7f75dSAlexei Starovoitov 		return -EPERM;
12421be7f75dSAlexei Starovoitov 
12435e43f899SAndrey Ignatov 	if (bpf_prog_load_check_attach_type(type, attr->expected_attach_type))
12445e43f899SAndrey Ignatov 		return -EINVAL;
12455e43f899SAndrey Ignatov 
124609756af4SAlexei Starovoitov 	/* plain bpf_prog allocation */
124709756af4SAlexei Starovoitov 	prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
124809756af4SAlexei Starovoitov 	if (!prog)
124909756af4SAlexei Starovoitov 		return -ENOMEM;
125009756af4SAlexei Starovoitov 
12515e43f899SAndrey Ignatov 	prog->expected_attach_type = attr->expected_attach_type;
12525e43f899SAndrey Ignatov 
12539a18eedbSJakub Kicinski 	prog->aux->offload_requested = !!attr->prog_ifindex;
12549a18eedbSJakub Kicinski 
1255afdb09c7SChenbo Feng 	err = security_bpf_prog_alloc(prog->aux);
1256aaac3ba9SAlexei Starovoitov 	if (err)
1257aaac3ba9SAlexei Starovoitov 		goto free_prog_nouncharge;
1258aaac3ba9SAlexei Starovoitov 
1259afdb09c7SChenbo Feng 	err = bpf_prog_charge_memlock(prog);
1260afdb09c7SChenbo Feng 	if (err)
1261afdb09c7SChenbo Feng 		goto free_prog_sec;
1262afdb09c7SChenbo Feng 
126309756af4SAlexei Starovoitov 	prog->len = attr->insn_cnt;
126409756af4SAlexei Starovoitov 
126509756af4SAlexei Starovoitov 	err = -EFAULT;
1266535e7b4bSMickaël Salaün 	if (copy_from_user(prog->insns, u64_to_user_ptr(attr->insns),
1267aafe6ae9SDaniel Borkmann 			   bpf_prog_insn_size(prog)) != 0)
126809756af4SAlexei Starovoitov 		goto free_prog;
126909756af4SAlexei Starovoitov 
127009756af4SAlexei Starovoitov 	prog->orig_prog = NULL;
1271a91263d5SDaniel Borkmann 	prog->jited = 0;
127209756af4SAlexei Starovoitov 
127309756af4SAlexei Starovoitov 	atomic_set(&prog->aux->refcnt, 1);
1274a91263d5SDaniel Borkmann 	prog->gpl_compatible = is_gpl ? 1 : 0;
127509756af4SAlexei Starovoitov 
12769a18eedbSJakub Kicinski 	if (bpf_prog_is_dev_bound(prog->aux)) {
1277ab3f0063SJakub Kicinski 		err = bpf_prog_offload_init(prog, attr);
1278ab3f0063SJakub Kicinski 		if (err)
1279ab3f0063SJakub Kicinski 			goto free_prog;
1280ab3f0063SJakub Kicinski 	}
1281ab3f0063SJakub Kicinski 
128209756af4SAlexei Starovoitov 	/* find program type: socket_filter vs tracing_filter */
128309756af4SAlexei Starovoitov 	err = find_prog_type(type, prog);
128409756af4SAlexei Starovoitov 	if (err < 0)
128509756af4SAlexei Starovoitov 		goto free_prog;
128609756af4SAlexei Starovoitov 
1287cb4d2b3fSMartin KaFai Lau 	prog->aux->load_time = ktime_get_boot_ns();
1288cb4d2b3fSMartin KaFai Lau 	err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name);
1289cb4d2b3fSMartin KaFai Lau 	if (err)
1290cb4d2b3fSMartin KaFai Lau 		goto free_prog;
1291cb4d2b3fSMartin KaFai Lau 
129209756af4SAlexei Starovoitov 	/* run eBPF verifier */
12939bac3d6dSAlexei Starovoitov 	err = bpf_check(&prog, attr);
129409756af4SAlexei Starovoitov 	if (err < 0)
129509756af4SAlexei Starovoitov 		goto free_used_maps;
129609756af4SAlexei Starovoitov 
129709756af4SAlexei Starovoitov 	/* eBPF program is ready to be JITed */
12981c2a088aSAlexei Starovoitov 	if (!prog->bpf_func)
1299d1c55ab5SDaniel Borkmann 		prog = bpf_prog_select_runtime(prog, &err);
130004fd61abSAlexei Starovoitov 	if (err < 0)
130104fd61abSAlexei Starovoitov 		goto free_used_maps;
130209756af4SAlexei Starovoitov 
1303dc4bb0e2SMartin KaFai Lau 	err = bpf_prog_alloc_id(prog);
1304dc4bb0e2SMartin KaFai Lau 	if (err)
1305dc4bb0e2SMartin KaFai Lau 		goto free_used_maps;
1306dc4bb0e2SMartin KaFai Lau 
1307aa79781bSDaniel Borkmann 	err = bpf_prog_new_fd(prog);
1308b16d9aa4SMartin KaFai Lau 	if (err < 0) {
1309b16d9aa4SMartin KaFai Lau 		/* failed to allocate fd.
1310b16d9aa4SMartin KaFai Lau 		 * bpf_prog_put() is needed because the above
1311b16d9aa4SMartin KaFai Lau 		 * bpf_prog_alloc_id() has published the prog
1312b16d9aa4SMartin KaFai Lau 		 * to the userspace and the userspace may
1313b16d9aa4SMartin KaFai Lau 		 * have refcnt-ed it through BPF_PROG_GET_FD_BY_ID.
1314b16d9aa4SMartin KaFai Lau 		 */
1315b16d9aa4SMartin KaFai Lau 		bpf_prog_put(prog);
1316b16d9aa4SMartin KaFai Lau 		return err;
1317b16d9aa4SMartin KaFai Lau 	}
131809756af4SAlexei Starovoitov 
131974451e66SDaniel Borkmann 	bpf_prog_kallsyms_add(prog);
1320a67edbf4SDaniel Borkmann 	trace_bpf_prog_load(prog, err);
132109756af4SAlexei Starovoitov 	return err;
132209756af4SAlexei Starovoitov 
132309756af4SAlexei Starovoitov free_used_maps:
132409756af4SAlexei Starovoitov 	free_used_maps(prog->aux);
132509756af4SAlexei Starovoitov free_prog:
1326aaac3ba9SAlexei Starovoitov 	bpf_prog_uncharge_memlock(prog);
1327afdb09c7SChenbo Feng free_prog_sec:
1328afdb09c7SChenbo Feng 	security_bpf_prog_free(prog->aux);
1329aaac3ba9SAlexei Starovoitov free_prog_nouncharge:
133009756af4SAlexei Starovoitov 	bpf_prog_free(prog);
133109756af4SAlexei Starovoitov 	return err;
133209756af4SAlexei Starovoitov }
133309756af4SAlexei Starovoitov 
13346e71b04aSChenbo Feng #define BPF_OBJ_LAST_FIELD file_flags
1335b2197755SDaniel Borkmann 
1336b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr)
1337b2197755SDaniel Borkmann {
13386e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_OBJ) || attr->file_flags != 0)
1339b2197755SDaniel Borkmann 		return -EINVAL;
1340b2197755SDaniel Borkmann 
1341535e7b4bSMickaël Salaün 	return bpf_obj_pin_user(attr->bpf_fd, u64_to_user_ptr(attr->pathname));
1342b2197755SDaniel Borkmann }
1343b2197755SDaniel Borkmann 
1344b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr)
1345b2197755SDaniel Borkmann {
13466e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0 ||
13476e71b04aSChenbo Feng 	    attr->file_flags & ~BPF_OBJ_FLAG_MASK)
1348b2197755SDaniel Borkmann 		return -EINVAL;
1349b2197755SDaniel Borkmann 
13506e71b04aSChenbo Feng 	return bpf_obj_get_user(u64_to_user_ptr(attr->pathname),
13516e71b04aSChenbo Feng 				attr->file_flags);
1352b2197755SDaniel Borkmann }
1353b2197755SDaniel Borkmann 
1354c4f6699dSAlexei Starovoitov struct bpf_raw_tracepoint {
1355c4f6699dSAlexei Starovoitov 	struct bpf_raw_event_map *btp;
1356c4f6699dSAlexei Starovoitov 	struct bpf_prog *prog;
1357c4f6699dSAlexei Starovoitov };
1358c4f6699dSAlexei Starovoitov 
1359c4f6699dSAlexei Starovoitov static int bpf_raw_tracepoint_release(struct inode *inode, struct file *filp)
1360c4f6699dSAlexei Starovoitov {
1361c4f6699dSAlexei Starovoitov 	struct bpf_raw_tracepoint *raw_tp = filp->private_data;
1362c4f6699dSAlexei Starovoitov 
1363c4f6699dSAlexei Starovoitov 	if (raw_tp->prog) {
1364c4f6699dSAlexei Starovoitov 		bpf_probe_unregister(raw_tp->btp, raw_tp->prog);
1365c4f6699dSAlexei Starovoitov 		bpf_prog_put(raw_tp->prog);
1366c4f6699dSAlexei Starovoitov 	}
1367c4f6699dSAlexei Starovoitov 	kfree(raw_tp);
1368c4f6699dSAlexei Starovoitov 	return 0;
1369c4f6699dSAlexei Starovoitov }
1370c4f6699dSAlexei Starovoitov 
1371c4f6699dSAlexei Starovoitov static const struct file_operations bpf_raw_tp_fops = {
1372c4f6699dSAlexei Starovoitov 	.release	= bpf_raw_tracepoint_release,
1373c4f6699dSAlexei Starovoitov 	.read		= bpf_dummy_read,
1374c4f6699dSAlexei Starovoitov 	.write		= bpf_dummy_write,
1375c4f6699dSAlexei Starovoitov };
1376c4f6699dSAlexei Starovoitov 
1377c4f6699dSAlexei Starovoitov #define BPF_RAW_TRACEPOINT_OPEN_LAST_FIELD raw_tracepoint.prog_fd
1378c4f6699dSAlexei Starovoitov 
1379c4f6699dSAlexei Starovoitov static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
1380c4f6699dSAlexei Starovoitov {
1381c4f6699dSAlexei Starovoitov 	struct bpf_raw_tracepoint *raw_tp;
1382c4f6699dSAlexei Starovoitov 	struct bpf_raw_event_map *btp;
1383c4f6699dSAlexei Starovoitov 	struct bpf_prog *prog;
1384c4f6699dSAlexei Starovoitov 	char tp_name[128];
1385c4f6699dSAlexei Starovoitov 	int tp_fd, err;
1386c4f6699dSAlexei Starovoitov 
1387c4f6699dSAlexei Starovoitov 	if (strncpy_from_user(tp_name, u64_to_user_ptr(attr->raw_tracepoint.name),
1388c4f6699dSAlexei Starovoitov 			      sizeof(tp_name) - 1) < 0)
1389c4f6699dSAlexei Starovoitov 		return -EFAULT;
1390c4f6699dSAlexei Starovoitov 	tp_name[sizeof(tp_name) - 1] = 0;
1391c4f6699dSAlexei Starovoitov 
1392c4f6699dSAlexei Starovoitov 	btp = bpf_find_raw_tracepoint(tp_name);
1393c4f6699dSAlexei Starovoitov 	if (!btp)
1394c4f6699dSAlexei Starovoitov 		return -ENOENT;
1395c4f6699dSAlexei Starovoitov 
1396c4f6699dSAlexei Starovoitov 	raw_tp = kzalloc(sizeof(*raw_tp), GFP_USER);
1397c4f6699dSAlexei Starovoitov 	if (!raw_tp)
1398c4f6699dSAlexei Starovoitov 		return -ENOMEM;
1399c4f6699dSAlexei Starovoitov 	raw_tp->btp = btp;
1400c4f6699dSAlexei Starovoitov 
1401c4f6699dSAlexei Starovoitov 	prog = bpf_prog_get_type(attr->raw_tracepoint.prog_fd,
1402c4f6699dSAlexei Starovoitov 				 BPF_PROG_TYPE_RAW_TRACEPOINT);
1403c4f6699dSAlexei Starovoitov 	if (IS_ERR(prog)) {
1404c4f6699dSAlexei Starovoitov 		err = PTR_ERR(prog);
1405c4f6699dSAlexei Starovoitov 		goto out_free_tp;
1406c4f6699dSAlexei Starovoitov 	}
1407c4f6699dSAlexei Starovoitov 
1408c4f6699dSAlexei Starovoitov 	err = bpf_probe_register(raw_tp->btp, prog);
1409c4f6699dSAlexei Starovoitov 	if (err)
1410c4f6699dSAlexei Starovoitov 		goto out_put_prog;
1411c4f6699dSAlexei Starovoitov 
1412c4f6699dSAlexei Starovoitov 	raw_tp->prog = prog;
1413c4f6699dSAlexei Starovoitov 	tp_fd = anon_inode_getfd("bpf-raw-tracepoint", &bpf_raw_tp_fops, raw_tp,
1414c4f6699dSAlexei Starovoitov 				 O_CLOEXEC);
1415c4f6699dSAlexei Starovoitov 	if (tp_fd < 0) {
1416c4f6699dSAlexei Starovoitov 		bpf_probe_unregister(raw_tp->btp, prog);
1417c4f6699dSAlexei Starovoitov 		err = tp_fd;
1418c4f6699dSAlexei Starovoitov 		goto out_put_prog;
1419c4f6699dSAlexei Starovoitov 	}
1420c4f6699dSAlexei Starovoitov 	return tp_fd;
1421c4f6699dSAlexei Starovoitov 
1422c4f6699dSAlexei Starovoitov out_put_prog:
1423c4f6699dSAlexei Starovoitov 	bpf_prog_put(prog);
1424c4f6699dSAlexei Starovoitov out_free_tp:
1425c4f6699dSAlexei Starovoitov 	kfree(raw_tp);
1426c4f6699dSAlexei Starovoitov 	return err;
1427c4f6699dSAlexei Starovoitov }
1428c4f6699dSAlexei Starovoitov 
1429f4324551SDaniel Mack #ifdef CONFIG_CGROUP_BPF
1430f4324551SDaniel Mack 
1431464bc0fdSJohn Fastabend #define BPF_PROG_ATTACH_LAST_FIELD attach_flags
1432174a79ffSJohn Fastabend 
14334f738adbSJohn Fastabend static int sockmap_get_from_fd(const union bpf_attr *attr,
14344f738adbSJohn Fastabend 			       int type, bool attach)
1435174a79ffSJohn Fastabend {
14365a67da2aSJohn Fastabend 	struct bpf_prog *prog = NULL;
1437174a79ffSJohn Fastabend 	int ufd = attr->target_fd;
1438174a79ffSJohn Fastabend 	struct bpf_map *map;
1439174a79ffSJohn Fastabend 	struct fd f;
1440174a79ffSJohn Fastabend 	int err;
1441174a79ffSJohn Fastabend 
1442174a79ffSJohn Fastabend 	f = fdget(ufd);
1443174a79ffSJohn Fastabend 	map = __bpf_map_get(f);
1444174a79ffSJohn Fastabend 	if (IS_ERR(map))
1445174a79ffSJohn Fastabend 		return PTR_ERR(map);
1446174a79ffSJohn Fastabend 
14475a67da2aSJohn Fastabend 	if (attach) {
14484f738adbSJohn Fastabend 		prog = bpf_prog_get_type(attr->attach_bpf_fd, type);
1449464bc0fdSJohn Fastabend 		if (IS_ERR(prog)) {
1450174a79ffSJohn Fastabend 			fdput(f);
1451464bc0fdSJohn Fastabend 			return PTR_ERR(prog);
1452174a79ffSJohn Fastabend 		}
14535a67da2aSJohn Fastabend 	}
1454174a79ffSJohn Fastabend 
14555a67da2aSJohn Fastabend 	err = sock_map_prog(map, prog, attr->attach_type);
1456174a79ffSJohn Fastabend 	if (err) {
1457174a79ffSJohn Fastabend 		fdput(f);
14585a67da2aSJohn Fastabend 		if (prog)
1459464bc0fdSJohn Fastabend 			bpf_prog_put(prog);
1460ae2b27b8SDan Carpenter 		return err;
1461174a79ffSJohn Fastabend 	}
1462174a79ffSJohn Fastabend 
1463174a79ffSJohn Fastabend 	fdput(f);
1464ae2b27b8SDan Carpenter 	return 0;
1465174a79ffSJohn Fastabend }
1466f4324551SDaniel Mack 
1467324bda9eSAlexei Starovoitov #define BPF_F_ATTACH_MASK \
1468324bda9eSAlexei Starovoitov 	(BPF_F_ALLOW_OVERRIDE | BPF_F_ALLOW_MULTI)
1469324bda9eSAlexei Starovoitov 
1470f4324551SDaniel Mack static int bpf_prog_attach(const union bpf_attr *attr)
1471f4324551SDaniel Mack {
14727f677633SAlexei Starovoitov 	enum bpf_prog_type ptype;
1473f4324551SDaniel Mack 	struct bpf_prog *prog;
1474f4324551SDaniel Mack 	struct cgroup *cgrp;
14757f677633SAlexei Starovoitov 	int ret;
1476f4324551SDaniel Mack 
1477f4324551SDaniel Mack 	if (!capable(CAP_NET_ADMIN))
1478f4324551SDaniel Mack 		return -EPERM;
1479f4324551SDaniel Mack 
1480f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_ATTACH))
1481f4324551SDaniel Mack 		return -EINVAL;
1482f4324551SDaniel Mack 
1483324bda9eSAlexei Starovoitov 	if (attr->attach_flags & ~BPF_F_ATTACH_MASK)
14847f677633SAlexei Starovoitov 		return -EINVAL;
14857f677633SAlexei Starovoitov 
1486f4324551SDaniel Mack 	switch (attr->attach_type) {
1487f4324551SDaniel Mack 	case BPF_CGROUP_INET_INGRESS:
1488f4324551SDaniel Mack 	case BPF_CGROUP_INET_EGRESS:
1489b2cd1257SDavid Ahern 		ptype = BPF_PROG_TYPE_CGROUP_SKB;
1490b2cd1257SDavid Ahern 		break;
149161023658SDavid Ahern 	case BPF_CGROUP_INET_SOCK_CREATE:
149261023658SDavid Ahern 		ptype = BPF_PROG_TYPE_CGROUP_SOCK;
149361023658SDavid Ahern 		break;
14944fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET4_BIND:
14954fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET6_BIND:
1496*d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET4_CONNECT:
1497*d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET6_CONNECT:
14984fbac77dSAndrey Ignatov 		ptype = BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
14994fbac77dSAndrey Ignatov 		break;
150040304b2aSLawrence Brakmo 	case BPF_CGROUP_SOCK_OPS:
150140304b2aSLawrence Brakmo 		ptype = BPF_PROG_TYPE_SOCK_OPS;
150240304b2aSLawrence Brakmo 		break;
1503ebc614f6SRoman Gushchin 	case BPF_CGROUP_DEVICE:
1504ebc614f6SRoman Gushchin 		ptype = BPF_PROG_TYPE_CGROUP_DEVICE;
1505ebc614f6SRoman Gushchin 		break;
15064f738adbSJohn Fastabend 	case BPF_SK_MSG_VERDICT:
15074f738adbSJohn Fastabend 		return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_MSG, true);
1508464bc0fdSJohn Fastabend 	case BPF_SK_SKB_STREAM_PARSER:
1509464bc0fdSJohn Fastabend 	case BPF_SK_SKB_STREAM_VERDICT:
15104f738adbSJohn Fastabend 		return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_SKB, true);
1511b2cd1257SDavid Ahern 	default:
1512b2cd1257SDavid Ahern 		return -EINVAL;
1513b2cd1257SDavid Ahern 	}
1514b2cd1257SDavid Ahern 
1515b2cd1257SDavid Ahern 	prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
1516f4324551SDaniel Mack 	if (IS_ERR(prog))
1517f4324551SDaniel Mack 		return PTR_ERR(prog);
1518f4324551SDaniel Mack 
15195e43f899SAndrey Ignatov 	if (bpf_prog_attach_check_attach_type(prog, attr->attach_type)) {
15205e43f899SAndrey Ignatov 		bpf_prog_put(prog);
15215e43f899SAndrey Ignatov 		return -EINVAL;
15225e43f899SAndrey Ignatov 	}
15235e43f899SAndrey Ignatov 
1524f4324551SDaniel Mack 	cgrp = cgroup_get_from_fd(attr->target_fd);
1525f4324551SDaniel Mack 	if (IS_ERR(cgrp)) {
1526f4324551SDaniel Mack 		bpf_prog_put(prog);
1527f4324551SDaniel Mack 		return PTR_ERR(cgrp);
1528f4324551SDaniel Mack 	}
1529f4324551SDaniel Mack 
1530324bda9eSAlexei Starovoitov 	ret = cgroup_bpf_attach(cgrp, prog, attr->attach_type,
1531324bda9eSAlexei Starovoitov 				attr->attach_flags);
15327f677633SAlexei Starovoitov 	if (ret)
15337f677633SAlexei Starovoitov 		bpf_prog_put(prog);
1534f4324551SDaniel Mack 	cgroup_put(cgrp);
1535f4324551SDaniel Mack 
15367f677633SAlexei Starovoitov 	return ret;
1537f4324551SDaniel Mack }
1538f4324551SDaniel Mack 
1539f4324551SDaniel Mack #define BPF_PROG_DETACH_LAST_FIELD attach_type
1540f4324551SDaniel Mack 
1541f4324551SDaniel Mack static int bpf_prog_detach(const union bpf_attr *attr)
1542f4324551SDaniel Mack {
1543324bda9eSAlexei Starovoitov 	enum bpf_prog_type ptype;
1544324bda9eSAlexei Starovoitov 	struct bpf_prog *prog;
1545f4324551SDaniel Mack 	struct cgroup *cgrp;
15467f677633SAlexei Starovoitov 	int ret;
1547f4324551SDaniel Mack 
1548f4324551SDaniel Mack 	if (!capable(CAP_NET_ADMIN))
1549f4324551SDaniel Mack 		return -EPERM;
1550f4324551SDaniel Mack 
1551f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_DETACH))
1552f4324551SDaniel Mack 		return -EINVAL;
1553f4324551SDaniel Mack 
1554f4324551SDaniel Mack 	switch (attr->attach_type) {
1555f4324551SDaniel Mack 	case BPF_CGROUP_INET_INGRESS:
1556f4324551SDaniel Mack 	case BPF_CGROUP_INET_EGRESS:
1557324bda9eSAlexei Starovoitov 		ptype = BPF_PROG_TYPE_CGROUP_SKB;
1558324bda9eSAlexei Starovoitov 		break;
155961023658SDavid Ahern 	case BPF_CGROUP_INET_SOCK_CREATE:
1560324bda9eSAlexei Starovoitov 		ptype = BPF_PROG_TYPE_CGROUP_SOCK;
1561324bda9eSAlexei Starovoitov 		break;
15624fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET4_BIND:
15634fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET6_BIND:
1564*d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET4_CONNECT:
1565*d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET6_CONNECT:
15664fbac77dSAndrey Ignatov 		ptype = BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
15674fbac77dSAndrey Ignatov 		break;
156840304b2aSLawrence Brakmo 	case BPF_CGROUP_SOCK_OPS:
1569324bda9eSAlexei Starovoitov 		ptype = BPF_PROG_TYPE_SOCK_OPS;
1570f4324551SDaniel Mack 		break;
1571ebc614f6SRoman Gushchin 	case BPF_CGROUP_DEVICE:
1572ebc614f6SRoman Gushchin 		ptype = BPF_PROG_TYPE_CGROUP_DEVICE;
1573ebc614f6SRoman Gushchin 		break;
15744f738adbSJohn Fastabend 	case BPF_SK_MSG_VERDICT:
15754f738adbSJohn Fastabend 		return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_MSG, false);
15765a67da2aSJohn Fastabend 	case BPF_SK_SKB_STREAM_PARSER:
15775a67da2aSJohn Fastabend 	case BPF_SK_SKB_STREAM_VERDICT:
15784f738adbSJohn Fastabend 		return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_SKB, false);
1579f4324551SDaniel Mack 	default:
1580f4324551SDaniel Mack 		return -EINVAL;
1581f4324551SDaniel Mack 	}
1582f4324551SDaniel Mack 
1583324bda9eSAlexei Starovoitov 	cgrp = cgroup_get_from_fd(attr->target_fd);
1584324bda9eSAlexei Starovoitov 	if (IS_ERR(cgrp))
1585324bda9eSAlexei Starovoitov 		return PTR_ERR(cgrp);
1586324bda9eSAlexei Starovoitov 
1587324bda9eSAlexei Starovoitov 	prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
1588324bda9eSAlexei Starovoitov 	if (IS_ERR(prog))
1589324bda9eSAlexei Starovoitov 		prog = NULL;
1590324bda9eSAlexei Starovoitov 
1591324bda9eSAlexei Starovoitov 	ret = cgroup_bpf_detach(cgrp, prog, attr->attach_type, 0);
1592324bda9eSAlexei Starovoitov 	if (prog)
1593324bda9eSAlexei Starovoitov 		bpf_prog_put(prog);
1594324bda9eSAlexei Starovoitov 	cgroup_put(cgrp);
15957f677633SAlexei Starovoitov 	return ret;
1596f4324551SDaniel Mack }
159740304b2aSLawrence Brakmo 
1598468e2f64SAlexei Starovoitov #define BPF_PROG_QUERY_LAST_FIELD query.prog_cnt
1599468e2f64SAlexei Starovoitov 
1600468e2f64SAlexei Starovoitov static int bpf_prog_query(const union bpf_attr *attr,
1601468e2f64SAlexei Starovoitov 			  union bpf_attr __user *uattr)
1602468e2f64SAlexei Starovoitov {
1603468e2f64SAlexei Starovoitov 	struct cgroup *cgrp;
1604468e2f64SAlexei Starovoitov 	int ret;
1605468e2f64SAlexei Starovoitov 
1606468e2f64SAlexei Starovoitov 	if (!capable(CAP_NET_ADMIN))
1607468e2f64SAlexei Starovoitov 		return -EPERM;
1608468e2f64SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_QUERY))
1609468e2f64SAlexei Starovoitov 		return -EINVAL;
1610468e2f64SAlexei Starovoitov 	if (attr->query.query_flags & ~BPF_F_QUERY_EFFECTIVE)
1611468e2f64SAlexei Starovoitov 		return -EINVAL;
1612468e2f64SAlexei Starovoitov 
1613468e2f64SAlexei Starovoitov 	switch (attr->query.attach_type) {
1614468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_INGRESS:
1615468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_EGRESS:
1616468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_SOCK_CREATE:
16174fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET4_BIND:
16184fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET6_BIND:
1619*d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET4_CONNECT:
1620*d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET6_CONNECT:
1621468e2f64SAlexei Starovoitov 	case BPF_CGROUP_SOCK_OPS:
1622ebc614f6SRoman Gushchin 	case BPF_CGROUP_DEVICE:
1623468e2f64SAlexei Starovoitov 		break;
1624468e2f64SAlexei Starovoitov 	default:
1625468e2f64SAlexei Starovoitov 		return -EINVAL;
1626468e2f64SAlexei Starovoitov 	}
1627468e2f64SAlexei Starovoitov 	cgrp = cgroup_get_from_fd(attr->query.target_fd);
1628468e2f64SAlexei Starovoitov 	if (IS_ERR(cgrp))
1629468e2f64SAlexei Starovoitov 		return PTR_ERR(cgrp);
1630468e2f64SAlexei Starovoitov 	ret = cgroup_bpf_query(cgrp, attr, uattr);
1631468e2f64SAlexei Starovoitov 	cgroup_put(cgrp);
1632468e2f64SAlexei Starovoitov 	return ret;
1633468e2f64SAlexei Starovoitov }
1634f4324551SDaniel Mack #endif /* CONFIG_CGROUP_BPF */
1635f4324551SDaniel Mack 
16361cf1cae9SAlexei Starovoitov #define BPF_PROG_TEST_RUN_LAST_FIELD test.duration
16371cf1cae9SAlexei Starovoitov 
16381cf1cae9SAlexei Starovoitov static int bpf_prog_test_run(const union bpf_attr *attr,
16391cf1cae9SAlexei Starovoitov 			     union bpf_attr __user *uattr)
16401cf1cae9SAlexei Starovoitov {
16411cf1cae9SAlexei Starovoitov 	struct bpf_prog *prog;
16421cf1cae9SAlexei Starovoitov 	int ret = -ENOTSUPP;
16431cf1cae9SAlexei Starovoitov 
164461f3c964SAlexei Starovoitov 	if (!capable(CAP_SYS_ADMIN))
164561f3c964SAlexei Starovoitov 		return -EPERM;
16461cf1cae9SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_TEST_RUN))
16471cf1cae9SAlexei Starovoitov 		return -EINVAL;
16481cf1cae9SAlexei Starovoitov 
16491cf1cae9SAlexei Starovoitov 	prog = bpf_prog_get(attr->test.prog_fd);
16501cf1cae9SAlexei Starovoitov 	if (IS_ERR(prog))
16511cf1cae9SAlexei Starovoitov 		return PTR_ERR(prog);
16521cf1cae9SAlexei Starovoitov 
16531cf1cae9SAlexei Starovoitov 	if (prog->aux->ops->test_run)
16541cf1cae9SAlexei Starovoitov 		ret = prog->aux->ops->test_run(prog, attr, uattr);
16551cf1cae9SAlexei Starovoitov 
16561cf1cae9SAlexei Starovoitov 	bpf_prog_put(prog);
16571cf1cae9SAlexei Starovoitov 	return ret;
16581cf1cae9SAlexei Starovoitov }
16591cf1cae9SAlexei Starovoitov 
166034ad5580SMartin KaFai Lau #define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id
166134ad5580SMartin KaFai Lau 
166234ad5580SMartin KaFai Lau static int bpf_obj_get_next_id(const union bpf_attr *attr,
166334ad5580SMartin KaFai Lau 			       union bpf_attr __user *uattr,
166434ad5580SMartin KaFai Lau 			       struct idr *idr,
166534ad5580SMartin KaFai Lau 			       spinlock_t *lock)
166634ad5580SMartin KaFai Lau {
166734ad5580SMartin KaFai Lau 	u32 next_id = attr->start_id;
166834ad5580SMartin KaFai Lau 	int err = 0;
166934ad5580SMartin KaFai Lau 
167034ad5580SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX)
167134ad5580SMartin KaFai Lau 		return -EINVAL;
167234ad5580SMartin KaFai Lau 
167334ad5580SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
167434ad5580SMartin KaFai Lau 		return -EPERM;
167534ad5580SMartin KaFai Lau 
167634ad5580SMartin KaFai Lau 	next_id++;
167734ad5580SMartin KaFai Lau 	spin_lock_bh(lock);
167834ad5580SMartin KaFai Lau 	if (!idr_get_next(idr, &next_id))
167934ad5580SMartin KaFai Lau 		err = -ENOENT;
168034ad5580SMartin KaFai Lau 	spin_unlock_bh(lock);
168134ad5580SMartin KaFai Lau 
168234ad5580SMartin KaFai Lau 	if (!err)
168334ad5580SMartin KaFai Lau 		err = put_user(next_id, &uattr->next_id);
168434ad5580SMartin KaFai Lau 
168534ad5580SMartin KaFai Lau 	return err;
168634ad5580SMartin KaFai Lau }
168734ad5580SMartin KaFai Lau 
1688b16d9aa4SMartin KaFai Lau #define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id
1689b16d9aa4SMartin KaFai Lau 
1690b16d9aa4SMartin KaFai Lau static int bpf_prog_get_fd_by_id(const union bpf_attr *attr)
1691b16d9aa4SMartin KaFai Lau {
1692b16d9aa4SMartin KaFai Lau 	struct bpf_prog *prog;
1693b16d9aa4SMartin KaFai Lau 	u32 id = attr->prog_id;
1694b16d9aa4SMartin KaFai Lau 	int fd;
1695b16d9aa4SMartin KaFai Lau 
1696b16d9aa4SMartin KaFai Lau 	if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID))
1697b16d9aa4SMartin KaFai Lau 		return -EINVAL;
1698b16d9aa4SMartin KaFai Lau 
1699b16d9aa4SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
1700b16d9aa4SMartin KaFai Lau 		return -EPERM;
1701b16d9aa4SMartin KaFai Lau 
1702b16d9aa4SMartin KaFai Lau 	spin_lock_bh(&prog_idr_lock);
1703b16d9aa4SMartin KaFai Lau 	prog = idr_find(&prog_idr, id);
1704b16d9aa4SMartin KaFai Lau 	if (prog)
1705b16d9aa4SMartin KaFai Lau 		prog = bpf_prog_inc_not_zero(prog);
1706b16d9aa4SMartin KaFai Lau 	else
1707b16d9aa4SMartin KaFai Lau 		prog = ERR_PTR(-ENOENT);
1708b16d9aa4SMartin KaFai Lau 	spin_unlock_bh(&prog_idr_lock);
1709b16d9aa4SMartin KaFai Lau 
1710b16d9aa4SMartin KaFai Lau 	if (IS_ERR(prog))
1711b16d9aa4SMartin KaFai Lau 		return PTR_ERR(prog);
1712b16d9aa4SMartin KaFai Lau 
1713b16d9aa4SMartin KaFai Lau 	fd = bpf_prog_new_fd(prog);
1714b16d9aa4SMartin KaFai Lau 	if (fd < 0)
1715b16d9aa4SMartin KaFai Lau 		bpf_prog_put(prog);
1716b16d9aa4SMartin KaFai Lau 
1717b16d9aa4SMartin KaFai Lau 	return fd;
1718b16d9aa4SMartin KaFai Lau }
1719b16d9aa4SMartin KaFai Lau 
17206e71b04aSChenbo Feng #define BPF_MAP_GET_FD_BY_ID_LAST_FIELD open_flags
1721bd5f5f4eSMartin KaFai Lau 
1722bd5f5f4eSMartin KaFai Lau static int bpf_map_get_fd_by_id(const union bpf_attr *attr)
1723bd5f5f4eSMartin KaFai Lau {
1724bd5f5f4eSMartin KaFai Lau 	struct bpf_map *map;
1725bd5f5f4eSMartin KaFai Lau 	u32 id = attr->map_id;
17266e71b04aSChenbo Feng 	int f_flags;
1727bd5f5f4eSMartin KaFai Lau 	int fd;
1728bd5f5f4eSMartin KaFai Lau 
17296e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_MAP_GET_FD_BY_ID) ||
17306e71b04aSChenbo Feng 	    attr->open_flags & ~BPF_OBJ_FLAG_MASK)
1731bd5f5f4eSMartin KaFai Lau 		return -EINVAL;
1732bd5f5f4eSMartin KaFai Lau 
1733bd5f5f4eSMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
1734bd5f5f4eSMartin KaFai Lau 		return -EPERM;
1735bd5f5f4eSMartin KaFai Lau 
17366e71b04aSChenbo Feng 	f_flags = bpf_get_file_flag(attr->open_flags);
17376e71b04aSChenbo Feng 	if (f_flags < 0)
17386e71b04aSChenbo Feng 		return f_flags;
17396e71b04aSChenbo Feng 
1740bd5f5f4eSMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
1741bd5f5f4eSMartin KaFai Lau 	map = idr_find(&map_idr, id);
1742bd5f5f4eSMartin KaFai Lau 	if (map)
1743bd5f5f4eSMartin KaFai Lau 		map = bpf_map_inc_not_zero(map, true);
1744bd5f5f4eSMartin KaFai Lau 	else
1745bd5f5f4eSMartin KaFai Lau 		map = ERR_PTR(-ENOENT);
1746bd5f5f4eSMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
1747bd5f5f4eSMartin KaFai Lau 
1748bd5f5f4eSMartin KaFai Lau 	if (IS_ERR(map))
1749bd5f5f4eSMartin KaFai Lau 		return PTR_ERR(map);
1750bd5f5f4eSMartin KaFai Lau 
17516e71b04aSChenbo Feng 	fd = bpf_map_new_fd(map, f_flags);
1752bd5f5f4eSMartin KaFai Lau 	if (fd < 0)
1753bd5f5f4eSMartin KaFai Lau 		bpf_map_put(map);
1754bd5f5f4eSMartin KaFai Lau 
1755bd5f5f4eSMartin KaFai Lau 	return fd;
1756bd5f5f4eSMartin KaFai Lau }
1757bd5f5f4eSMartin KaFai Lau 
17587105e828SDaniel Borkmann static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog,
17597105e828SDaniel Borkmann 					      unsigned long addr)
17607105e828SDaniel Borkmann {
17617105e828SDaniel Borkmann 	int i;
17627105e828SDaniel Borkmann 
17637105e828SDaniel Borkmann 	for (i = 0; i < prog->aux->used_map_cnt; i++)
17647105e828SDaniel Borkmann 		if (prog->aux->used_maps[i] == (void *)addr)
17657105e828SDaniel Borkmann 			return prog->aux->used_maps[i];
17667105e828SDaniel Borkmann 	return NULL;
17677105e828SDaniel Borkmann }
17687105e828SDaniel Borkmann 
17697105e828SDaniel Borkmann static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog)
17707105e828SDaniel Borkmann {
17717105e828SDaniel Borkmann 	const struct bpf_map *map;
17727105e828SDaniel Borkmann 	struct bpf_insn *insns;
17737105e828SDaniel Borkmann 	u64 imm;
17747105e828SDaniel Borkmann 	int i;
17757105e828SDaniel Borkmann 
17767105e828SDaniel Borkmann 	insns = kmemdup(prog->insnsi, bpf_prog_insn_size(prog),
17777105e828SDaniel Borkmann 			GFP_USER);
17787105e828SDaniel Borkmann 	if (!insns)
17797105e828SDaniel Borkmann 		return insns;
17807105e828SDaniel Borkmann 
17817105e828SDaniel Borkmann 	for (i = 0; i < prog->len; i++) {
17827105e828SDaniel Borkmann 		if (insns[i].code == (BPF_JMP | BPF_TAIL_CALL)) {
17837105e828SDaniel Borkmann 			insns[i].code = BPF_JMP | BPF_CALL;
17847105e828SDaniel Borkmann 			insns[i].imm = BPF_FUNC_tail_call;
17857105e828SDaniel Borkmann 			/* fall-through */
17867105e828SDaniel Borkmann 		}
17877105e828SDaniel Borkmann 		if (insns[i].code == (BPF_JMP | BPF_CALL) ||
17887105e828SDaniel Borkmann 		    insns[i].code == (BPF_JMP | BPF_CALL_ARGS)) {
17897105e828SDaniel Borkmann 			if (insns[i].code == (BPF_JMP | BPF_CALL_ARGS))
17907105e828SDaniel Borkmann 				insns[i].code = BPF_JMP | BPF_CALL;
17917105e828SDaniel Borkmann 			if (!bpf_dump_raw_ok())
17927105e828SDaniel Borkmann 				insns[i].imm = 0;
17937105e828SDaniel Borkmann 			continue;
17947105e828SDaniel Borkmann 		}
17957105e828SDaniel Borkmann 
17967105e828SDaniel Borkmann 		if (insns[i].code != (BPF_LD | BPF_IMM | BPF_DW))
17977105e828SDaniel Borkmann 			continue;
17987105e828SDaniel Borkmann 
17997105e828SDaniel Borkmann 		imm = ((u64)insns[i + 1].imm << 32) | (u32)insns[i].imm;
18007105e828SDaniel Borkmann 		map = bpf_map_from_imm(prog, imm);
18017105e828SDaniel Borkmann 		if (map) {
18027105e828SDaniel Borkmann 			insns[i].src_reg = BPF_PSEUDO_MAP_FD;
18037105e828SDaniel Borkmann 			insns[i].imm = map->id;
18047105e828SDaniel Borkmann 			insns[i + 1].imm = 0;
18057105e828SDaniel Borkmann 			continue;
18067105e828SDaniel Borkmann 		}
18077105e828SDaniel Borkmann 
18087105e828SDaniel Borkmann 		if (!bpf_dump_raw_ok() &&
18097105e828SDaniel Borkmann 		    imm == (unsigned long)prog->aux) {
18107105e828SDaniel Borkmann 			insns[i].imm = 0;
18117105e828SDaniel Borkmann 			insns[i + 1].imm = 0;
18127105e828SDaniel Borkmann 			continue;
18137105e828SDaniel Borkmann 		}
18147105e828SDaniel Borkmann 	}
18157105e828SDaniel Borkmann 
18167105e828SDaniel Borkmann 	return insns;
18177105e828SDaniel Borkmann }
18187105e828SDaniel Borkmann 
18191e270976SMartin KaFai Lau static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
18201e270976SMartin KaFai Lau 				   const union bpf_attr *attr,
18211e270976SMartin KaFai Lau 				   union bpf_attr __user *uattr)
18221e270976SMartin KaFai Lau {
18231e270976SMartin KaFai Lau 	struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info);
18241e270976SMartin KaFai Lau 	struct bpf_prog_info info = {};
18251e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
18261e270976SMartin KaFai Lau 	char __user *uinsns;
18271e270976SMartin KaFai Lau 	u32 ulen;
18281e270976SMartin KaFai Lau 	int err;
18291e270976SMartin KaFai Lau 
18301e270976SMartin KaFai Lau 	err = check_uarg_tail_zero(uinfo, sizeof(info), info_len);
18311e270976SMartin KaFai Lau 	if (err)
18321e270976SMartin KaFai Lau 		return err;
18331e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
18341e270976SMartin KaFai Lau 
18351e270976SMartin KaFai Lau 	if (copy_from_user(&info, uinfo, info_len))
183689b09689SDaniel Borkmann 		return -EFAULT;
18371e270976SMartin KaFai Lau 
18381e270976SMartin KaFai Lau 	info.type = prog->type;
18391e270976SMartin KaFai Lau 	info.id = prog->aux->id;
1840cb4d2b3fSMartin KaFai Lau 	info.load_time = prog->aux->load_time;
1841cb4d2b3fSMartin KaFai Lau 	info.created_by_uid = from_kuid_munged(current_user_ns(),
1842cb4d2b3fSMartin KaFai Lau 					       prog->aux->user->uid);
18431e270976SMartin KaFai Lau 
18441e270976SMartin KaFai Lau 	memcpy(info.tag, prog->tag, sizeof(prog->tag));
1845cb4d2b3fSMartin KaFai Lau 	memcpy(info.name, prog->aux->name, sizeof(prog->aux->name));
1846cb4d2b3fSMartin KaFai Lau 
1847cb4d2b3fSMartin KaFai Lau 	ulen = info.nr_map_ids;
1848cb4d2b3fSMartin KaFai Lau 	info.nr_map_ids = prog->aux->used_map_cnt;
1849cb4d2b3fSMartin KaFai Lau 	ulen = min_t(u32, info.nr_map_ids, ulen);
1850cb4d2b3fSMartin KaFai Lau 	if (ulen) {
1851721e08daSMartin KaFai Lau 		u32 __user *user_map_ids = u64_to_user_ptr(info.map_ids);
1852cb4d2b3fSMartin KaFai Lau 		u32 i;
1853cb4d2b3fSMartin KaFai Lau 
1854cb4d2b3fSMartin KaFai Lau 		for (i = 0; i < ulen; i++)
1855cb4d2b3fSMartin KaFai Lau 			if (put_user(prog->aux->used_maps[i]->id,
1856cb4d2b3fSMartin KaFai Lau 				     &user_map_ids[i]))
1857cb4d2b3fSMartin KaFai Lau 				return -EFAULT;
1858cb4d2b3fSMartin KaFai Lau 	}
18591e270976SMartin KaFai Lau 
18601e270976SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN)) {
18611e270976SMartin KaFai Lau 		info.jited_prog_len = 0;
18621e270976SMartin KaFai Lau 		info.xlated_prog_len = 0;
18631e270976SMartin KaFai Lau 		goto done;
18641e270976SMartin KaFai Lau 	}
18651e270976SMartin KaFai Lau 
18661e270976SMartin KaFai Lau 	ulen = info.xlated_prog_len;
18679975a54bSDaniel Borkmann 	info.xlated_prog_len = bpf_prog_insn_size(prog);
18681e270976SMartin KaFai Lau 	if (info.xlated_prog_len && ulen) {
18697105e828SDaniel Borkmann 		struct bpf_insn *insns_sanitized;
18707105e828SDaniel Borkmann 		bool fault;
18717105e828SDaniel Borkmann 
18727105e828SDaniel Borkmann 		if (prog->blinded && !bpf_dump_raw_ok()) {
18737105e828SDaniel Borkmann 			info.xlated_prog_insns = 0;
18747105e828SDaniel Borkmann 			goto done;
18757105e828SDaniel Borkmann 		}
18767105e828SDaniel Borkmann 		insns_sanitized = bpf_insn_prepare_dump(prog);
18777105e828SDaniel Borkmann 		if (!insns_sanitized)
18787105e828SDaniel Borkmann 			return -ENOMEM;
18791e270976SMartin KaFai Lau 		uinsns = u64_to_user_ptr(info.xlated_prog_insns);
18801e270976SMartin KaFai Lau 		ulen = min_t(u32, info.xlated_prog_len, ulen);
18817105e828SDaniel Borkmann 		fault = copy_to_user(uinsns, insns_sanitized, ulen);
18827105e828SDaniel Borkmann 		kfree(insns_sanitized);
18837105e828SDaniel Borkmann 		if (fault)
18841e270976SMartin KaFai Lau 			return -EFAULT;
18851e270976SMartin KaFai Lau 	}
18861e270976SMartin KaFai Lau 
1887675fc275SJakub Kicinski 	if (bpf_prog_is_dev_bound(prog->aux)) {
1888675fc275SJakub Kicinski 		err = bpf_prog_offload_info_fill(&info, prog);
1889675fc275SJakub Kicinski 		if (err)
1890675fc275SJakub Kicinski 			return err;
1891fcfb126dSJiong Wang 		goto done;
1892fcfb126dSJiong Wang 	}
1893fcfb126dSJiong Wang 
1894fcfb126dSJiong Wang 	/* NOTE: the following code is supposed to be skipped for offload.
1895fcfb126dSJiong Wang 	 * bpf_prog_offload_info_fill() is the place to fill similar fields
1896fcfb126dSJiong Wang 	 * for offload.
1897fcfb126dSJiong Wang 	 */
1898fcfb126dSJiong Wang 	ulen = info.jited_prog_len;
1899fcfb126dSJiong Wang 	info.jited_prog_len = prog->jited_len;
1900fcfb126dSJiong Wang 	if (info.jited_prog_len && ulen) {
1901fcfb126dSJiong Wang 		if (bpf_dump_raw_ok()) {
1902fcfb126dSJiong Wang 			uinsns = u64_to_user_ptr(info.jited_prog_insns);
1903fcfb126dSJiong Wang 			ulen = min_t(u32, info.jited_prog_len, ulen);
1904fcfb126dSJiong Wang 			if (copy_to_user(uinsns, prog->bpf_func, ulen))
1905fcfb126dSJiong Wang 				return -EFAULT;
1906fcfb126dSJiong Wang 		} else {
1907fcfb126dSJiong Wang 			info.jited_prog_insns = 0;
1908fcfb126dSJiong Wang 		}
1909675fc275SJakub Kicinski 	}
1910675fc275SJakub Kicinski 
19111e270976SMartin KaFai Lau done:
19121e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
19131e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
19141e270976SMartin KaFai Lau 		return -EFAULT;
19151e270976SMartin KaFai Lau 
19161e270976SMartin KaFai Lau 	return 0;
19171e270976SMartin KaFai Lau }
19181e270976SMartin KaFai Lau 
19191e270976SMartin KaFai Lau static int bpf_map_get_info_by_fd(struct bpf_map *map,
19201e270976SMartin KaFai Lau 				  const union bpf_attr *attr,
19211e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
19221e270976SMartin KaFai Lau {
19231e270976SMartin KaFai Lau 	struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info);
19241e270976SMartin KaFai Lau 	struct bpf_map_info info = {};
19251e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
19261e270976SMartin KaFai Lau 	int err;
19271e270976SMartin KaFai Lau 
19281e270976SMartin KaFai Lau 	err = check_uarg_tail_zero(uinfo, sizeof(info), info_len);
19291e270976SMartin KaFai Lau 	if (err)
19301e270976SMartin KaFai Lau 		return err;
19311e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
19321e270976SMartin KaFai Lau 
19331e270976SMartin KaFai Lau 	info.type = map->map_type;
19341e270976SMartin KaFai Lau 	info.id = map->id;
19351e270976SMartin KaFai Lau 	info.key_size = map->key_size;
19361e270976SMartin KaFai Lau 	info.value_size = map->value_size;
19371e270976SMartin KaFai Lau 	info.max_entries = map->max_entries;
19381e270976SMartin KaFai Lau 	info.map_flags = map->map_flags;
1939ad5b177bSMartin KaFai Lau 	memcpy(info.name, map->name, sizeof(map->name));
19401e270976SMartin KaFai Lau 
194152775b33SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
194252775b33SJakub Kicinski 		err = bpf_map_offload_info_fill(&info, map);
194352775b33SJakub Kicinski 		if (err)
194452775b33SJakub Kicinski 			return err;
194552775b33SJakub Kicinski 	}
194652775b33SJakub Kicinski 
19471e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
19481e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
19491e270976SMartin KaFai Lau 		return -EFAULT;
19501e270976SMartin KaFai Lau 
19511e270976SMartin KaFai Lau 	return 0;
19521e270976SMartin KaFai Lau }
19531e270976SMartin KaFai Lau 
19541e270976SMartin KaFai Lau #define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info
19551e270976SMartin KaFai Lau 
19561e270976SMartin KaFai Lau static int bpf_obj_get_info_by_fd(const union bpf_attr *attr,
19571e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
19581e270976SMartin KaFai Lau {
19591e270976SMartin KaFai Lau 	int ufd = attr->info.bpf_fd;
19601e270976SMartin KaFai Lau 	struct fd f;
19611e270976SMartin KaFai Lau 	int err;
19621e270976SMartin KaFai Lau 
19631e270976SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD))
19641e270976SMartin KaFai Lau 		return -EINVAL;
19651e270976SMartin KaFai Lau 
19661e270976SMartin KaFai Lau 	f = fdget(ufd);
19671e270976SMartin KaFai Lau 	if (!f.file)
19681e270976SMartin KaFai Lau 		return -EBADFD;
19691e270976SMartin KaFai Lau 
19701e270976SMartin KaFai Lau 	if (f.file->f_op == &bpf_prog_fops)
19711e270976SMartin KaFai Lau 		err = bpf_prog_get_info_by_fd(f.file->private_data, attr,
19721e270976SMartin KaFai Lau 					      uattr);
19731e270976SMartin KaFai Lau 	else if (f.file->f_op == &bpf_map_fops)
19741e270976SMartin KaFai Lau 		err = bpf_map_get_info_by_fd(f.file->private_data, attr,
19751e270976SMartin KaFai Lau 					     uattr);
19761e270976SMartin KaFai Lau 	else
19771e270976SMartin KaFai Lau 		err = -EINVAL;
19781e270976SMartin KaFai Lau 
19791e270976SMartin KaFai Lau 	fdput(f);
19801e270976SMartin KaFai Lau 	return err;
19811e270976SMartin KaFai Lau }
19821e270976SMartin KaFai Lau 
198399c55f7dSAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
198499c55f7dSAlexei Starovoitov {
198599c55f7dSAlexei Starovoitov 	union bpf_attr attr = {};
198699c55f7dSAlexei Starovoitov 	int err;
198799c55f7dSAlexei Starovoitov 
19880fa4fe85SChenbo Feng 	if (sysctl_unprivileged_bpf_disabled && !capable(CAP_SYS_ADMIN))
198999c55f7dSAlexei Starovoitov 		return -EPERM;
199099c55f7dSAlexei Starovoitov 
19911e270976SMartin KaFai Lau 	err = check_uarg_tail_zero(uattr, sizeof(attr), size);
199299c55f7dSAlexei Starovoitov 	if (err)
199399c55f7dSAlexei Starovoitov 		return err;
19941e270976SMartin KaFai Lau 	size = min_t(u32, size, sizeof(attr));
199599c55f7dSAlexei Starovoitov 
199699c55f7dSAlexei Starovoitov 	/* copy attributes from user space, may be less than sizeof(bpf_attr) */
199799c55f7dSAlexei Starovoitov 	if (copy_from_user(&attr, uattr, size) != 0)
199899c55f7dSAlexei Starovoitov 		return -EFAULT;
199999c55f7dSAlexei Starovoitov 
2000afdb09c7SChenbo Feng 	err = security_bpf(cmd, &attr, size);
2001afdb09c7SChenbo Feng 	if (err < 0)
2002afdb09c7SChenbo Feng 		return err;
2003afdb09c7SChenbo Feng 
200499c55f7dSAlexei Starovoitov 	switch (cmd) {
200599c55f7dSAlexei Starovoitov 	case BPF_MAP_CREATE:
200699c55f7dSAlexei Starovoitov 		err = map_create(&attr);
200799c55f7dSAlexei Starovoitov 		break;
2008db20fd2bSAlexei Starovoitov 	case BPF_MAP_LOOKUP_ELEM:
2009db20fd2bSAlexei Starovoitov 		err = map_lookup_elem(&attr);
2010db20fd2bSAlexei Starovoitov 		break;
2011db20fd2bSAlexei Starovoitov 	case BPF_MAP_UPDATE_ELEM:
2012db20fd2bSAlexei Starovoitov 		err = map_update_elem(&attr);
2013db20fd2bSAlexei Starovoitov 		break;
2014db20fd2bSAlexei Starovoitov 	case BPF_MAP_DELETE_ELEM:
2015db20fd2bSAlexei Starovoitov 		err = map_delete_elem(&attr);
2016db20fd2bSAlexei Starovoitov 		break;
2017db20fd2bSAlexei Starovoitov 	case BPF_MAP_GET_NEXT_KEY:
2018db20fd2bSAlexei Starovoitov 		err = map_get_next_key(&attr);
2019db20fd2bSAlexei Starovoitov 		break;
202009756af4SAlexei Starovoitov 	case BPF_PROG_LOAD:
202109756af4SAlexei Starovoitov 		err = bpf_prog_load(&attr);
202209756af4SAlexei Starovoitov 		break;
2023b2197755SDaniel Borkmann 	case BPF_OBJ_PIN:
2024b2197755SDaniel Borkmann 		err = bpf_obj_pin(&attr);
2025b2197755SDaniel Borkmann 		break;
2026b2197755SDaniel Borkmann 	case BPF_OBJ_GET:
2027b2197755SDaniel Borkmann 		err = bpf_obj_get(&attr);
2028b2197755SDaniel Borkmann 		break;
2029f4324551SDaniel Mack #ifdef CONFIG_CGROUP_BPF
2030f4324551SDaniel Mack 	case BPF_PROG_ATTACH:
2031f4324551SDaniel Mack 		err = bpf_prog_attach(&attr);
2032f4324551SDaniel Mack 		break;
2033f4324551SDaniel Mack 	case BPF_PROG_DETACH:
2034f4324551SDaniel Mack 		err = bpf_prog_detach(&attr);
2035f4324551SDaniel Mack 		break;
2036468e2f64SAlexei Starovoitov 	case BPF_PROG_QUERY:
2037468e2f64SAlexei Starovoitov 		err = bpf_prog_query(&attr, uattr);
2038468e2f64SAlexei Starovoitov 		break;
2039f4324551SDaniel Mack #endif
20401cf1cae9SAlexei Starovoitov 	case BPF_PROG_TEST_RUN:
20411cf1cae9SAlexei Starovoitov 		err = bpf_prog_test_run(&attr, uattr);
20421cf1cae9SAlexei Starovoitov 		break;
204334ad5580SMartin KaFai Lau 	case BPF_PROG_GET_NEXT_ID:
204434ad5580SMartin KaFai Lau 		err = bpf_obj_get_next_id(&attr, uattr,
204534ad5580SMartin KaFai Lau 					  &prog_idr, &prog_idr_lock);
204634ad5580SMartin KaFai Lau 		break;
204734ad5580SMartin KaFai Lau 	case BPF_MAP_GET_NEXT_ID:
204834ad5580SMartin KaFai Lau 		err = bpf_obj_get_next_id(&attr, uattr,
204934ad5580SMartin KaFai Lau 					  &map_idr, &map_idr_lock);
205034ad5580SMartin KaFai Lau 		break;
2051b16d9aa4SMartin KaFai Lau 	case BPF_PROG_GET_FD_BY_ID:
2052b16d9aa4SMartin KaFai Lau 		err = bpf_prog_get_fd_by_id(&attr);
2053b16d9aa4SMartin KaFai Lau 		break;
2054bd5f5f4eSMartin KaFai Lau 	case BPF_MAP_GET_FD_BY_ID:
2055bd5f5f4eSMartin KaFai Lau 		err = bpf_map_get_fd_by_id(&attr);
2056bd5f5f4eSMartin KaFai Lau 		break;
20571e270976SMartin KaFai Lau 	case BPF_OBJ_GET_INFO_BY_FD:
20581e270976SMartin KaFai Lau 		err = bpf_obj_get_info_by_fd(&attr, uattr);
20591e270976SMartin KaFai Lau 		break;
2060c4f6699dSAlexei Starovoitov 	case BPF_RAW_TRACEPOINT_OPEN:
2061c4f6699dSAlexei Starovoitov 		err = bpf_raw_tracepoint_open(&attr);
2062c4f6699dSAlexei Starovoitov 		break;
206399c55f7dSAlexei Starovoitov 	default:
206499c55f7dSAlexei Starovoitov 		err = -EINVAL;
206599c55f7dSAlexei Starovoitov 		break;
206699c55f7dSAlexei Starovoitov 	}
206799c55f7dSAlexei Starovoitov 
206899c55f7dSAlexei Starovoitov 	return err;
206999c55f7dSAlexei Starovoitov }
2070