xref: /linux/kernel/bpf/syscall.c (revision d5299b67dd59445902cd30cbc60a03c869cf1adb)
15b497af4SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
299c55f7dSAlexei Starovoitov /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
399c55f7dSAlexei Starovoitov  */
499c55f7dSAlexei Starovoitov #include <linux/bpf.h>
5a67edbf4SDaniel Borkmann #include <linux/bpf_trace.h>
6f4364dcfSSean Young #include <linux/bpf_lirc.h>
74a1e7c0cSToke Høiland-Jørgensen #include <linux/bpf_verifier.h>
8f56a653cSMartin KaFai Lau #include <linux/btf.h>
999c55f7dSAlexei Starovoitov #include <linux/syscalls.h>
1099c55f7dSAlexei Starovoitov #include <linux/slab.h>
113f07c014SIngo Molnar #include <linux/sched/signal.h>
12d407bd25SDaniel Borkmann #include <linux/vmalloc.h>
13d407bd25SDaniel Borkmann #include <linux/mmzone.h>
1499c55f7dSAlexei Starovoitov #include <linux/anon_inodes.h>
1541bdc4b4SYonghong Song #include <linux/fdtable.h>
16db20fd2bSAlexei Starovoitov #include <linux/file.h>
1741bdc4b4SYonghong Song #include <linux/fs.h>
1809756af4SAlexei Starovoitov #include <linux/license.h>
1909756af4SAlexei Starovoitov #include <linux/filter.h>
202541517cSAlexei Starovoitov #include <linux/version.h>
21535e7b4bSMickaël Salaün #include <linux/kernel.h>
22dc4bb0e2SMartin KaFai Lau #include <linux/idr.h>
23cb4d2b3fSMartin KaFai Lau #include <linux/cred.h>
24cb4d2b3fSMartin KaFai Lau #include <linux/timekeeping.h>
25cb4d2b3fSMartin KaFai Lau #include <linux/ctype.h>
269ef09e35SMark Rutland #include <linux/nospec.h>
27bae141f5SDaniel Borkmann #include <linux/audit.h>
28ccfe29ebSAlexei Starovoitov #include <uapi/linux/btf.h>
29ca5999fdSMike Rapoport #include <linux/pgtable.h>
309e4e01dfSKP Singh #include <linux/bpf_lsm.h>
31457f4436SAndrii Nakryiko #include <linux/poll.h>
32a3fd7ceeSJakub Sitnicki #include <linux/bpf-netns.h>
331e6c62a8SAlexei Starovoitov #include <linux/rcupdate_trace.h>
3448edc1f7SRoman Gushchin #include <linux/memcontrol.h>
3599c55f7dSAlexei Starovoitov 
36da765a2fSDaniel Borkmann #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \
3714dc6f04SMartin KaFai Lau 			  (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \
3814dc6f04SMartin KaFai Lau 			  (map)->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS)
39da765a2fSDaniel Borkmann #define IS_FD_PROG_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY)
4014dc6f04SMartin KaFai Lau #define IS_FD_HASH(map) ((map)->map_type == BPF_MAP_TYPE_HASH_OF_MAPS)
41da765a2fSDaniel Borkmann #define IS_FD_MAP(map) (IS_FD_ARRAY(map) || IS_FD_PROG_ARRAY(map) || \
42da765a2fSDaniel Borkmann 			IS_FD_HASH(map))
4314dc6f04SMartin KaFai Lau 
446e71b04aSChenbo Feng #define BPF_OBJ_FLAG_MASK   (BPF_F_RDONLY | BPF_F_WRONLY)
456e71b04aSChenbo Feng 
46b121d1e7SAlexei Starovoitov DEFINE_PER_CPU(int, bpf_prog_active);
47dc4bb0e2SMartin KaFai Lau static DEFINE_IDR(prog_idr);
48dc4bb0e2SMartin KaFai Lau static DEFINE_SPINLOCK(prog_idr_lock);
49f3f1c054SMartin KaFai Lau static DEFINE_IDR(map_idr);
50f3f1c054SMartin KaFai Lau static DEFINE_SPINLOCK(map_idr_lock);
51a3b80e10SAndrii Nakryiko static DEFINE_IDR(link_idr);
52a3b80e10SAndrii Nakryiko static DEFINE_SPINLOCK(link_idr_lock);
53b121d1e7SAlexei Starovoitov 
541be7f75dSAlexei Starovoitov int sysctl_unprivileged_bpf_disabled __read_mostly;
551be7f75dSAlexei Starovoitov 
5640077e0cSJohannes Berg static const struct bpf_map_ops * const bpf_map_types[] = {
5791cc1a99SAlexei Starovoitov #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type)
5840077e0cSJohannes Berg #define BPF_MAP_TYPE(_id, _ops) \
5940077e0cSJohannes Berg 	[_id] = &_ops,
60f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name)
6140077e0cSJohannes Berg #include <linux/bpf_types.h>
6240077e0cSJohannes Berg #undef BPF_PROG_TYPE
6340077e0cSJohannes Berg #undef BPF_MAP_TYPE
64f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE
6540077e0cSJohannes Berg };
6699c55f7dSAlexei Starovoitov 
67752ba56fSMickaël Salaün /*
68752ba56fSMickaël Salaün  * If we're handed a bigger struct than we know of, ensure all the unknown bits
69752ba56fSMickaël Salaün  * are 0 - i.e. new user-space does not rely on any kernel feature extensions
70752ba56fSMickaël Salaün  * we don't know about yet.
71752ba56fSMickaël Salaün  *
72752ba56fSMickaël Salaün  * There is a ToCToU between this function call and the following
73752ba56fSMickaël Salaün  * copy_from_user() call. However, this is not a concern since this function is
74752ba56fSMickaël Salaün  * meant to be a future-proofing of bits.
75752ba56fSMickaël Salaün  */
76dcab51f1SMartin KaFai Lau int bpf_check_uarg_tail_zero(void __user *uaddr,
7758291a74SMickaël Salaün 			     size_t expected_size,
7858291a74SMickaël Salaün 			     size_t actual_size)
7958291a74SMickaël Salaün {
80b7e4b65fSAl Viro 	unsigned char __user *addr = uaddr + expected_size;
81b7e4b65fSAl Viro 	int res;
8258291a74SMickaël Salaün 
83752ba56fSMickaël Salaün 	if (unlikely(actual_size > PAGE_SIZE))	/* silly large */
84752ba56fSMickaël Salaün 		return -E2BIG;
85752ba56fSMickaël Salaün 
8658291a74SMickaël Salaün 	if (actual_size <= expected_size)
8758291a74SMickaël Salaün 		return 0;
8858291a74SMickaël Salaün 
89b7e4b65fSAl Viro 	res = check_zeroed_user(addr, actual_size - expected_size);
90b7e4b65fSAl Viro 	if (res < 0)
91b7e4b65fSAl Viro 		return res;
92b7e4b65fSAl Viro 	return res ? 0 : -E2BIG;
9358291a74SMickaël Salaün }
9458291a74SMickaël Salaün 
95a3884572SJakub Kicinski const struct bpf_map_ops bpf_map_offload_ops = {
96f4d05259SMartin KaFai Lau 	.map_meta_equal = bpf_map_meta_equal,
97a3884572SJakub Kicinski 	.map_alloc = bpf_map_offload_map_alloc,
98a3884572SJakub Kicinski 	.map_free = bpf_map_offload_map_free,
99e8d2bec0SDaniel Borkmann 	.map_check_btf = map_check_no_btf,
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;
1059ef09e35SMark Rutland 	u32 type = attr->map_type;
10699c55f7dSAlexei Starovoitov 	struct bpf_map *map;
1071110f3a9SJakub Kicinski 	int err;
10899c55f7dSAlexei Starovoitov 
1099ef09e35SMark Rutland 	if (type >= ARRAY_SIZE(bpf_map_types))
1101110f3a9SJakub Kicinski 		return ERR_PTR(-EINVAL);
1119ef09e35SMark Rutland 	type = array_index_nospec(type, ARRAY_SIZE(bpf_map_types));
1129ef09e35SMark Rutland 	ops = bpf_map_types[type];
1131110f3a9SJakub Kicinski 	if (!ops)
11440077e0cSJohannes Berg 		return ERR_PTR(-EINVAL);
11540077e0cSJohannes Berg 
1161110f3a9SJakub Kicinski 	if (ops->map_alloc_check) {
1171110f3a9SJakub Kicinski 		err = ops->map_alloc_check(attr);
1181110f3a9SJakub Kicinski 		if (err)
1191110f3a9SJakub Kicinski 			return ERR_PTR(err);
1201110f3a9SJakub Kicinski 	}
121a3884572SJakub Kicinski 	if (attr->map_ifindex)
122a3884572SJakub Kicinski 		ops = &bpf_map_offload_ops;
1231110f3a9SJakub Kicinski 	map = ops->map_alloc(attr);
12499c55f7dSAlexei Starovoitov 	if (IS_ERR(map))
12599c55f7dSAlexei Starovoitov 		return map;
1261110f3a9SJakub Kicinski 	map->ops = ops;
1279ef09e35SMark Rutland 	map->map_type = type;
12899c55f7dSAlexei Starovoitov 	return map;
12999c55f7dSAlexei Starovoitov }
13099c55f7dSAlexei Starovoitov 
13115c14a3dSBrian Vazquez static u32 bpf_map_value_size(struct bpf_map *map)
13215c14a3dSBrian Vazquez {
13315c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
13415c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
13515c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY ||
13615c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE)
13715c14a3dSBrian Vazquez 		return round_up(map->value_size, 8) * num_possible_cpus();
13815c14a3dSBrian Vazquez 	else if (IS_FD_MAP(map))
13915c14a3dSBrian Vazquez 		return sizeof(u32);
14015c14a3dSBrian Vazquez 	else
14115c14a3dSBrian Vazquez 		return  map->value_size;
14215c14a3dSBrian Vazquez }
14315c14a3dSBrian Vazquez 
14415c14a3dSBrian Vazquez static void maybe_wait_bpf_programs(struct bpf_map *map)
14515c14a3dSBrian Vazquez {
14615c14a3dSBrian Vazquez 	/* Wait for any running BPF programs to complete so that
14715c14a3dSBrian Vazquez 	 * userspace, when we return to it, knows that all programs
14815c14a3dSBrian Vazquez 	 * that could be running use the new map value.
14915c14a3dSBrian Vazquez 	 */
15015c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS ||
15115c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS)
15215c14a3dSBrian Vazquez 		synchronize_rcu();
15315c14a3dSBrian Vazquez }
15415c14a3dSBrian Vazquez 
15515c14a3dSBrian Vazquez static int bpf_map_update_value(struct bpf_map *map, struct fd f, void *key,
15615c14a3dSBrian Vazquez 				void *value, __u64 flags)
15715c14a3dSBrian Vazquez {
15815c14a3dSBrian Vazquez 	int err;
15915c14a3dSBrian Vazquez 
16015c14a3dSBrian Vazquez 	/* Need to create a kthread, thus must support schedule */
16115c14a3dSBrian Vazquez 	if (bpf_map_is_dev_bound(map)) {
16215c14a3dSBrian Vazquez 		return bpf_map_offload_update_elem(map, key, value, flags);
16315c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_CPUMAP ||
16415c14a3dSBrian Vazquez 		   map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
16515c14a3dSBrian Vazquez 		return map->ops->map_update_elem(map, key, value, flags);
16613b79d3fSLorenz Bauer 	} else if (map->map_type == BPF_MAP_TYPE_SOCKHASH ||
16713b79d3fSLorenz Bauer 		   map->map_type == BPF_MAP_TYPE_SOCKMAP) {
16813b79d3fSLorenz Bauer 		return sock_map_update_elem_sys(map, key, value, flags);
16915c14a3dSBrian Vazquez 	} else if (IS_FD_PROG_ARRAY(map)) {
17015c14a3dSBrian Vazquez 		return bpf_fd_array_map_update_elem(map, f.file, key, value,
17115c14a3dSBrian Vazquez 						    flags);
17215c14a3dSBrian Vazquez 	}
17315c14a3dSBrian Vazquez 
174b6e5dae1SThomas Gleixner 	bpf_disable_instrumentation();
17515c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
17615c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
17715c14a3dSBrian Vazquez 		err = bpf_percpu_hash_update(map, key, value, flags);
17815c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
17915c14a3dSBrian Vazquez 		err = bpf_percpu_array_update(map, key, value, flags);
18015c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
18115c14a3dSBrian Vazquez 		err = bpf_percpu_cgroup_storage_update(map, key, value,
18215c14a3dSBrian Vazquez 						       flags);
18315c14a3dSBrian Vazquez 	} else if (IS_FD_ARRAY(map)) {
18415c14a3dSBrian Vazquez 		rcu_read_lock();
18515c14a3dSBrian Vazquez 		err = bpf_fd_array_map_update_elem(map, f.file, key, value,
18615c14a3dSBrian Vazquez 						   flags);
18715c14a3dSBrian Vazquez 		rcu_read_unlock();
18815c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) {
18915c14a3dSBrian Vazquez 		rcu_read_lock();
19015c14a3dSBrian Vazquez 		err = bpf_fd_htab_map_update_elem(map, f.file, key, value,
19115c14a3dSBrian Vazquez 						  flags);
19215c14a3dSBrian Vazquez 		rcu_read_unlock();
19315c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
19415c14a3dSBrian Vazquez 		/* rcu_read_lock() is not needed */
19515c14a3dSBrian Vazquez 		err = bpf_fd_reuseport_array_update_elem(map, key, value,
19615c14a3dSBrian Vazquez 							 flags);
19715c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
19815c14a3dSBrian Vazquez 		   map->map_type == BPF_MAP_TYPE_STACK) {
19915c14a3dSBrian Vazquez 		err = map->ops->map_push_elem(map, value, flags);
20015c14a3dSBrian Vazquez 	} else {
20115c14a3dSBrian Vazquez 		rcu_read_lock();
20215c14a3dSBrian Vazquez 		err = map->ops->map_update_elem(map, key, value, flags);
20315c14a3dSBrian Vazquez 		rcu_read_unlock();
20415c14a3dSBrian Vazquez 	}
205b6e5dae1SThomas Gleixner 	bpf_enable_instrumentation();
20615c14a3dSBrian Vazquez 	maybe_wait_bpf_programs(map);
20715c14a3dSBrian Vazquez 
20815c14a3dSBrian Vazquez 	return err;
20915c14a3dSBrian Vazquez }
21015c14a3dSBrian Vazquez 
21115c14a3dSBrian Vazquez static int bpf_map_copy_value(struct bpf_map *map, void *key, void *value,
21215c14a3dSBrian Vazquez 			      __u64 flags)
21315c14a3dSBrian Vazquez {
21415c14a3dSBrian Vazquez 	void *ptr;
21515c14a3dSBrian Vazquez 	int err;
21615c14a3dSBrian Vazquez 
217cb4d03abSBrian Vazquez 	if (bpf_map_is_dev_bound(map))
218cb4d03abSBrian Vazquez 		return bpf_map_offload_lookup_elem(map, key, value);
21915c14a3dSBrian Vazquez 
220b6e5dae1SThomas Gleixner 	bpf_disable_instrumentation();
22115c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
22215c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
22315c14a3dSBrian Vazquez 		err = bpf_percpu_hash_copy(map, key, value);
22415c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
22515c14a3dSBrian Vazquez 		err = bpf_percpu_array_copy(map, key, value);
22615c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
22715c14a3dSBrian Vazquez 		err = bpf_percpu_cgroup_storage_copy(map, key, value);
22815c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) {
22915c14a3dSBrian Vazquez 		err = bpf_stackmap_copy(map, key, value);
23015c14a3dSBrian Vazquez 	} else if (IS_FD_ARRAY(map) || IS_FD_PROG_ARRAY(map)) {
23115c14a3dSBrian Vazquez 		err = bpf_fd_array_map_lookup_elem(map, key, value);
23215c14a3dSBrian Vazquez 	} else if (IS_FD_HASH(map)) {
23315c14a3dSBrian Vazquez 		err = bpf_fd_htab_map_lookup_elem(map, key, value);
23415c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
23515c14a3dSBrian Vazquez 		err = bpf_fd_reuseport_array_lookup_elem(map, key, value);
23615c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
23715c14a3dSBrian Vazquez 		   map->map_type == BPF_MAP_TYPE_STACK) {
23815c14a3dSBrian Vazquez 		err = map->ops->map_peek_elem(map, value);
23915c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
24015c14a3dSBrian Vazquez 		/* struct_ops map requires directly updating "value" */
24115c14a3dSBrian Vazquez 		err = bpf_struct_ops_map_sys_lookup_elem(map, key, value);
24215c14a3dSBrian Vazquez 	} else {
24315c14a3dSBrian Vazquez 		rcu_read_lock();
24415c14a3dSBrian Vazquez 		if (map->ops->map_lookup_elem_sys_only)
24515c14a3dSBrian Vazquez 			ptr = map->ops->map_lookup_elem_sys_only(map, key);
24615c14a3dSBrian Vazquez 		else
24715c14a3dSBrian Vazquez 			ptr = map->ops->map_lookup_elem(map, key);
24815c14a3dSBrian Vazquez 		if (IS_ERR(ptr)) {
24915c14a3dSBrian Vazquez 			err = PTR_ERR(ptr);
25015c14a3dSBrian Vazquez 		} else if (!ptr) {
25115c14a3dSBrian Vazquez 			err = -ENOENT;
25215c14a3dSBrian Vazquez 		} else {
25315c14a3dSBrian Vazquez 			err = 0;
25415c14a3dSBrian Vazquez 			if (flags & BPF_F_LOCK)
25515c14a3dSBrian Vazquez 				/* lock 'ptr' and copy everything but lock */
25615c14a3dSBrian Vazquez 				copy_map_value_locked(map, value, ptr, true);
25715c14a3dSBrian Vazquez 			else
25815c14a3dSBrian Vazquez 				copy_map_value(map, value, ptr);
25915c14a3dSBrian Vazquez 			/* mask lock, since value wasn't zero inited */
26015c14a3dSBrian Vazquez 			check_and_init_map_lock(map, value);
26115c14a3dSBrian Vazquez 		}
26215c14a3dSBrian Vazquez 		rcu_read_unlock();
26315c14a3dSBrian Vazquez 	}
26415c14a3dSBrian Vazquez 
265b6e5dae1SThomas Gleixner 	bpf_enable_instrumentation();
26615c14a3dSBrian Vazquez 	maybe_wait_bpf_programs(map);
26715c14a3dSBrian Vazquez 
26815c14a3dSBrian Vazquez 	return err;
26915c14a3dSBrian Vazquez }
27015c14a3dSBrian Vazquez 
271*d5299b67SRoman Gushchin /* Please, do not use this function outside from the map creation path
272*d5299b67SRoman Gushchin  * (e.g. in map update path) without taking care of setting the active
273*d5299b67SRoman Gushchin  * memory cgroup (see at bpf_map_kmalloc_node() for example).
274*d5299b67SRoman Gushchin  */
275196e8ca7SDaniel Borkmann static void *__bpf_map_area_alloc(u64 size, int numa_node, bool mmapable)
276d407bd25SDaniel Borkmann {
277f01a7dbeSMartynas Pumputis 	/* We really just want to fail instead of triggering OOM killer
278f01a7dbeSMartynas Pumputis 	 * under memory pressure, therefore we set __GFP_NORETRY to kmalloc,
279f01a7dbeSMartynas Pumputis 	 * which is used for lower order allocation requests.
280f01a7dbeSMartynas Pumputis 	 *
281f01a7dbeSMartynas Pumputis 	 * It has been observed that higher order allocation requests done by
282f01a7dbeSMartynas Pumputis 	 * vmalloc with __GFP_NORETRY being set might fail due to not trying
283f01a7dbeSMartynas Pumputis 	 * to reclaim memory from the page cache, thus we set
284f01a7dbeSMartynas Pumputis 	 * __GFP_RETRY_MAYFAIL to avoid such situations.
285d407bd25SDaniel Borkmann 	 */
286f01a7dbeSMartynas Pumputis 
287*d5299b67SRoman Gushchin 	const gfp_t gfp = __GFP_NOWARN | __GFP_ZERO | __GFP_ACCOUNT;
288041de93fSChristoph Hellwig 	unsigned int flags = 0;
289041de93fSChristoph Hellwig 	unsigned long align = 1;
290d407bd25SDaniel Borkmann 	void *area;
291d407bd25SDaniel Borkmann 
292196e8ca7SDaniel Borkmann 	if (size >= SIZE_MAX)
293196e8ca7SDaniel Borkmann 		return NULL;
294196e8ca7SDaniel Borkmann 
295fc970227SAndrii Nakryiko 	/* kmalloc()'ed memory can't be mmap()'ed */
296041de93fSChristoph Hellwig 	if (mmapable) {
297041de93fSChristoph Hellwig 		BUG_ON(!PAGE_ALIGNED(size));
298041de93fSChristoph Hellwig 		align = SHMLBA;
299041de93fSChristoph Hellwig 		flags = VM_USERMAP;
300041de93fSChristoph Hellwig 	} else if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
301041de93fSChristoph Hellwig 		area = kmalloc_node(size, gfp | GFP_USER | __GFP_NORETRY,
302f01a7dbeSMartynas Pumputis 				    numa_node);
303d407bd25SDaniel Borkmann 		if (area != NULL)
304d407bd25SDaniel Borkmann 			return area;
305d407bd25SDaniel Borkmann 	}
306041de93fSChristoph Hellwig 
307041de93fSChristoph Hellwig 	return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END,
308041de93fSChristoph Hellwig 			gfp | GFP_KERNEL | __GFP_RETRY_MAYFAIL, PAGE_KERNEL,
309041de93fSChristoph Hellwig 			flags, numa_node, __builtin_return_address(0));
310d407bd25SDaniel Borkmann }
311d407bd25SDaniel Borkmann 
312196e8ca7SDaniel Borkmann void *bpf_map_area_alloc(u64 size, int numa_node)
313fc970227SAndrii Nakryiko {
314fc970227SAndrii Nakryiko 	return __bpf_map_area_alloc(size, numa_node, false);
315fc970227SAndrii Nakryiko }
316fc970227SAndrii Nakryiko 
317196e8ca7SDaniel Borkmann void *bpf_map_area_mmapable_alloc(u64 size, int numa_node)
318fc970227SAndrii Nakryiko {
319fc970227SAndrii Nakryiko 	return __bpf_map_area_alloc(size, numa_node, true);
320fc970227SAndrii Nakryiko }
321fc970227SAndrii Nakryiko 
322d407bd25SDaniel Borkmann void bpf_map_area_free(void *area)
323d407bd25SDaniel Borkmann {
324d407bd25SDaniel Borkmann 	kvfree(area);
325d407bd25SDaniel Borkmann }
326d407bd25SDaniel Borkmann 
327be70bcd5SDaniel Borkmann static u32 bpf_map_flags_retain_permanent(u32 flags)
328be70bcd5SDaniel Borkmann {
329be70bcd5SDaniel Borkmann 	/* Some map creation flags are not tied to the map object but
330be70bcd5SDaniel Borkmann 	 * rather to the map fd instead, so they have no meaning upon
331be70bcd5SDaniel Borkmann 	 * map object inspection since multiple file descriptors with
332be70bcd5SDaniel Borkmann 	 * different (access) properties can exist here. Thus, given
333be70bcd5SDaniel Borkmann 	 * this has zero meaning for the map itself, lets clear these
334be70bcd5SDaniel Borkmann 	 * from here.
335be70bcd5SDaniel Borkmann 	 */
336be70bcd5SDaniel Borkmann 	return flags & ~(BPF_F_RDONLY | BPF_F_WRONLY);
337be70bcd5SDaniel Borkmann }
338be70bcd5SDaniel Borkmann 
339bd475643SJakub Kicinski void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr)
340bd475643SJakub Kicinski {
341bd475643SJakub Kicinski 	map->map_type = attr->map_type;
342bd475643SJakub Kicinski 	map->key_size = attr->key_size;
343bd475643SJakub Kicinski 	map->value_size = attr->value_size;
344bd475643SJakub Kicinski 	map->max_entries = attr->max_entries;
345be70bcd5SDaniel Borkmann 	map->map_flags = bpf_map_flags_retain_permanent(attr->map_flags);
346bd475643SJakub Kicinski 	map->numa_node = bpf_map_attr_numa_node(attr);
347bd475643SJakub Kicinski }
348bd475643SJakub Kicinski 
3490a4c58f5SRoman Gushchin static int bpf_charge_memlock(struct user_struct *user, u32 pages)
350aaac3ba9SAlexei Starovoitov {
3510a4c58f5SRoman Gushchin 	unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
352aaac3ba9SAlexei Starovoitov 
3530a4c58f5SRoman Gushchin 	if (atomic_long_add_return(pages, &user->locked_vm) > memlock_limit) {
3540a4c58f5SRoman Gushchin 		atomic_long_sub(pages, &user->locked_vm);
355aaac3ba9SAlexei Starovoitov 		return -EPERM;
356aaac3ba9SAlexei Starovoitov 	}
357aaac3ba9SAlexei Starovoitov 	return 0;
358aaac3ba9SAlexei Starovoitov }
359aaac3ba9SAlexei Starovoitov 
3600a4c58f5SRoman Gushchin static void bpf_uncharge_memlock(struct user_struct *user, u32 pages)
3610a4c58f5SRoman Gushchin {
362b936ca64SRoman Gushchin 	if (user)
3630a4c58f5SRoman Gushchin 		atomic_long_sub(pages, &user->locked_vm);
3640a4c58f5SRoman Gushchin }
3650a4c58f5SRoman Gushchin 
366196e8ca7SDaniel Borkmann int bpf_map_charge_init(struct bpf_map_memory *mem, u64 size)
3670a4c58f5SRoman Gushchin {
368c85d6913SRoman Gushchin 	u32 pages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT;
369c85d6913SRoman Gushchin 	struct user_struct *user;
3700a4c58f5SRoman Gushchin 	int ret;
3710a4c58f5SRoman Gushchin 
372c85d6913SRoman Gushchin 	if (size >= U32_MAX - PAGE_SIZE)
373c85d6913SRoman Gushchin 		return -E2BIG;
374c85d6913SRoman Gushchin 
375c85d6913SRoman Gushchin 	user = get_current_user();
376b936ca64SRoman Gushchin 	ret = bpf_charge_memlock(user, pages);
3770a4c58f5SRoman Gushchin 	if (ret) {
3780a4c58f5SRoman Gushchin 		free_uid(user);
3790a4c58f5SRoman Gushchin 		return ret;
3800a4c58f5SRoman Gushchin 	}
381b936ca64SRoman Gushchin 
382b936ca64SRoman Gushchin 	mem->pages = pages;
383b936ca64SRoman Gushchin 	mem->user = user;
384b936ca64SRoman Gushchin 
385b936ca64SRoman Gushchin 	return 0;
3860a4c58f5SRoman Gushchin }
3870a4c58f5SRoman Gushchin 
388b936ca64SRoman Gushchin void bpf_map_charge_finish(struct bpf_map_memory *mem)
389aaac3ba9SAlexei Starovoitov {
390b936ca64SRoman Gushchin 	bpf_uncharge_memlock(mem->user, mem->pages);
391b936ca64SRoman Gushchin 	free_uid(mem->user);
392b936ca64SRoman Gushchin }
3933539b96eSRoman Gushchin 
394b936ca64SRoman Gushchin void bpf_map_charge_move(struct bpf_map_memory *dst,
395b936ca64SRoman Gushchin 			 struct bpf_map_memory *src)
396b936ca64SRoman Gushchin {
397b936ca64SRoman Gushchin 	*dst = *src;
398b936ca64SRoman Gushchin 
399b936ca64SRoman Gushchin 	/* Make sure src will not be used for the redundant uncharging. */
400b936ca64SRoman Gushchin 	memset(src, 0, sizeof(struct bpf_map_memory));
401aaac3ba9SAlexei Starovoitov }
402aaac3ba9SAlexei Starovoitov 
4030a4c58f5SRoman Gushchin int bpf_map_charge_memlock(struct bpf_map *map, u32 pages)
4040a4c58f5SRoman Gushchin {
4050a4c58f5SRoman Gushchin 	int ret;
4060a4c58f5SRoman Gushchin 
4073539b96eSRoman Gushchin 	ret = bpf_charge_memlock(map->memory.user, pages);
4080a4c58f5SRoman Gushchin 	if (ret)
4090a4c58f5SRoman Gushchin 		return ret;
4103539b96eSRoman Gushchin 	map->memory.pages += pages;
4110a4c58f5SRoman Gushchin 	return ret;
4120a4c58f5SRoman Gushchin }
4130a4c58f5SRoman Gushchin 
4140a4c58f5SRoman Gushchin void bpf_map_uncharge_memlock(struct bpf_map *map, u32 pages)
4150a4c58f5SRoman Gushchin {
4163539b96eSRoman Gushchin 	bpf_uncharge_memlock(map->memory.user, pages);
4173539b96eSRoman Gushchin 	map->memory.pages -= pages;
4180a4c58f5SRoman Gushchin }
4190a4c58f5SRoman Gushchin 
420f3f1c054SMartin KaFai Lau static int bpf_map_alloc_id(struct bpf_map *map)
421f3f1c054SMartin KaFai Lau {
422f3f1c054SMartin KaFai Lau 	int id;
423f3f1c054SMartin KaFai Lau 
424b76354cdSShaohua Li 	idr_preload(GFP_KERNEL);
425f3f1c054SMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
426f3f1c054SMartin KaFai Lau 	id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC);
427f3f1c054SMartin KaFai Lau 	if (id > 0)
428f3f1c054SMartin KaFai Lau 		map->id = id;
429f3f1c054SMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
430b76354cdSShaohua Li 	idr_preload_end();
431f3f1c054SMartin KaFai Lau 
432f3f1c054SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
433f3f1c054SMartin KaFai Lau 		return -ENOSPC;
434f3f1c054SMartin KaFai Lau 
435f3f1c054SMartin KaFai Lau 	return id > 0 ? 0 : id;
436f3f1c054SMartin KaFai Lau }
437f3f1c054SMartin KaFai Lau 
438a3884572SJakub Kicinski void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock)
439f3f1c054SMartin KaFai Lau {
440930651a7SEric Dumazet 	unsigned long flags;
441930651a7SEric Dumazet 
442a3884572SJakub Kicinski 	/* Offloaded maps are removed from the IDR store when their device
443a3884572SJakub Kicinski 	 * disappears - even if someone holds an fd to them they are unusable,
444a3884572SJakub Kicinski 	 * the memory is gone, all ops will fail; they are simply waiting for
445a3884572SJakub Kicinski 	 * refcnt to drop to be freed.
446a3884572SJakub Kicinski 	 */
447a3884572SJakub Kicinski 	if (!map->id)
448a3884572SJakub Kicinski 		return;
449a3884572SJakub Kicinski 
450bd5f5f4eSMartin KaFai Lau 	if (do_idr_lock)
451930651a7SEric Dumazet 		spin_lock_irqsave(&map_idr_lock, flags);
452bd5f5f4eSMartin KaFai Lau 	else
453bd5f5f4eSMartin KaFai Lau 		__acquire(&map_idr_lock);
454bd5f5f4eSMartin KaFai Lau 
455f3f1c054SMartin KaFai Lau 	idr_remove(&map_idr, map->id);
456a3884572SJakub Kicinski 	map->id = 0;
457bd5f5f4eSMartin KaFai Lau 
458bd5f5f4eSMartin KaFai Lau 	if (do_idr_lock)
459930651a7SEric Dumazet 		spin_unlock_irqrestore(&map_idr_lock, flags);
460bd5f5f4eSMartin KaFai Lau 	else
461bd5f5f4eSMartin KaFai Lau 		__release(&map_idr_lock);
462f3f1c054SMartin KaFai Lau }
463f3f1c054SMartin KaFai Lau 
46448edc1f7SRoman Gushchin #ifdef CONFIG_MEMCG_KMEM
46548edc1f7SRoman Gushchin static void bpf_map_save_memcg(struct bpf_map *map)
46648edc1f7SRoman Gushchin {
46748edc1f7SRoman Gushchin 	map->memcg = get_mem_cgroup_from_mm(current->mm);
46848edc1f7SRoman Gushchin }
46948edc1f7SRoman Gushchin 
47048edc1f7SRoman Gushchin static void bpf_map_release_memcg(struct bpf_map *map)
47148edc1f7SRoman Gushchin {
47248edc1f7SRoman Gushchin 	mem_cgroup_put(map->memcg);
47348edc1f7SRoman Gushchin }
47448edc1f7SRoman Gushchin 
47548edc1f7SRoman Gushchin void *bpf_map_kmalloc_node(const struct bpf_map *map, size_t size, gfp_t flags,
47648edc1f7SRoman Gushchin 			   int node)
47748edc1f7SRoman Gushchin {
47848edc1f7SRoman Gushchin 	struct mem_cgroup *old_memcg;
47948edc1f7SRoman Gushchin 	void *ptr;
48048edc1f7SRoman Gushchin 
48148edc1f7SRoman Gushchin 	old_memcg = set_active_memcg(map->memcg);
48248edc1f7SRoman Gushchin 	ptr = kmalloc_node(size, flags | __GFP_ACCOUNT, node);
48348edc1f7SRoman Gushchin 	set_active_memcg(old_memcg);
48448edc1f7SRoman Gushchin 
48548edc1f7SRoman Gushchin 	return ptr;
48648edc1f7SRoman Gushchin }
48748edc1f7SRoman Gushchin 
48848edc1f7SRoman Gushchin void *bpf_map_kzalloc(const struct bpf_map *map, size_t size, gfp_t flags)
48948edc1f7SRoman Gushchin {
49048edc1f7SRoman Gushchin 	struct mem_cgroup *old_memcg;
49148edc1f7SRoman Gushchin 	void *ptr;
49248edc1f7SRoman Gushchin 
49348edc1f7SRoman Gushchin 	old_memcg = set_active_memcg(map->memcg);
49448edc1f7SRoman Gushchin 	ptr = kzalloc(size, flags | __GFP_ACCOUNT);
49548edc1f7SRoman Gushchin 	set_active_memcg(old_memcg);
49648edc1f7SRoman Gushchin 
49748edc1f7SRoman Gushchin 	return ptr;
49848edc1f7SRoman Gushchin }
49948edc1f7SRoman Gushchin 
50048edc1f7SRoman Gushchin void __percpu *bpf_map_alloc_percpu(const struct bpf_map *map, size_t size,
50148edc1f7SRoman Gushchin 				    size_t align, gfp_t flags)
50248edc1f7SRoman Gushchin {
50348edc1f7SRoman Gushchin 	struct mem_cgroup *old_memcg;
50448edc1f7SRoman Gushchin 	void __percpu *ptr;
50548edc1f7SRoman Gushchin 
50648edc1f7SRoman Gushchin 	old_memcg = set_active_memcg(map->memcg);
50748edc1f7SRoman Gushchin 	ptr = __alloc_percpu_gfp(size, align, flags | __GFP_ACCOUNT);
50848edc1f7SRoman Gushchin 	set_active_memcg(old_memcg);
50948edc1f7SRoman Gushchin 
51048edc1f7SRoman Gushchin 	return ptr;
51148edc1f7SRoman Gushchin }
51248edc1f7SRoman Gushchin 
51348edc1f7SRoman Gushchin #else
51448edc1f7SRoman Gushchin static void bpf_map_save_memcg(struct bpf_map *map)
51548edc1f7SRoman Gushchin {
51648edc1f7SRoman Gushchin }
51748edc1f7SRoman Gushchin 
51848edc1f7SRoman Gushchin static void bpf_map_release_memcg(struct bpf_map *map)
51948edc1f7SRoman Gushchin {
52048edc1f7SRoman Gushchin }
52148edc1f7SRoman Gushchin #endif
52248edc1f7SRoman Gushchin 
52399c55f7dSAlexei Starovoitov /* called from workqueue */
52499c55f7dSAlexei Starovoitov static void bpf_map_free_deferred(struct work_struct *work)
52599c55f7dSAlexei Starovoitov {
52699c55f7dSAlexei Starovoitov 	struct bpf_map *map = container_of(work, struct bpf_map, work);
527b936ca64SRoman Gushchin 	struct bpf_map_memory mem;
52899c55f7dSAlexei Starovoitov 
529b936ca64SRoman Gushchin 	bpf_map_charge_move(&mem, &map->memory);
530afdb09c7SChenbo Feng 	security_bpf_map_free(map);
53148edc1f7SRoman Gushchin 	bpf_map_release_memcg(map);
53299c55f7dSAlexei Starovoitov 	/* implementation dependent freeing */
53399c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
534b936ca64SRoman Gushchin 	bpf_map_charge_finish(&mem);
53599c55f7dSAlexei Starovoitov }
53699c55f7dSAlexei Starovoitov 
537c9da161cSDaniel Borkmann static void bpf_map_put_uref(struct bpf_map *map)
538c9da161cSDaniel Borkmann {
5391e0bd5a0SAndrii Nakryiko 	if (atomic64_dec_and_test(&map->usercnt)) {
540ba6b8de4SJohn Fastabend 		if (map->ops->map_release_uref)
541ba6b8de4SJohn Fastabend 			map->ops->map_release_uref(map);
542c9da161cSDaniel Borkmann 	}
543c9da161cSDaniel Borkmann }
544c9da161cSDaniel Borkmann 
54599c55f7dSAlexei Starovoitov /* decrement map refcnt and schedule it for freeing via workqueue
54699c55f7dSAlexei Starovoitov  * (unrelying map implementation ops->map_free() might sleep)
54799c55f7dSAlexei Starovoitov  */
548bd5f5f4eSMartin KaFai Lau static void __bpf_map_put(struct bpf_map *map, bool do_idr_lock)
54999c55f7dSAlexei Starovoitov {
5501e0bd5a0SAndrii Nakryiko 	if (atomic64_dec_and_test(&map->refcnt)) {
55134ad5580SMartin KaFai Lau 		/* bpf_map_free_id() must be called first */
552bd5f5f4eSMartin KaFai Lau 		bpf_map_free_id(map, do_idr_lock);
55378958fcaSMartin KaFai Lau 		btf_put(map->btf);
55499c55f7dSAlexei Starovoitov 		INIT_WORK(&map->work, bpf_map_free_deferred);
55599c55f7dSAlexei Starovoitov 		schedule_work(&map->work);
55699c55f7dSAlexei Starovoitov 	}
55799c55f7dSAlexei Starovoitov }
55899c55f7dSAlexei Starovoitov 
559bd5f5f4eSMartin KaFai Lau void bpf_map_put(struct bpf_map *map)
560bd5f5f4eSMartin KaFai Lau {
561bd5f5f4eSMartin KaFai Lau 	__bpf_map_put(map, true);
562bd5f5f4eSMartin KaFai Lau }
563630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_put);
564bd5f5f4eSMartin KaFai Lau 
565c9da161cSDaniel Borkmann void bpf_map_put_with_uref(struct bpf_map *map)
566c9da161cSDaniel Borkmann {
567c9da161cSDaniel Borkmann 	bpf_map_put_uref(map);
568c9da161cSDaniel Borkmann 	bpf_map_put(map);
569c9da161cSDaniel Borkmann }
570c9da161cSDaniel Borkmann 
57199c55f7dSAlexei Starovoitov static int bpf_map_release(struct inode *inode, struct file *filp)
57299c55f7dSAlexei Starovoitov {
57361d1b6a4SDaniel Borkmann 	struct bpf_map *map = filp->private_data;
57461d1b6a4SDaniel Borkmann 
57561d1b6a4SDaniel Borkmann 	if (map->ops->map_release)
57661d1b6a4SDaniel Borkmann 		map->ops->map_release(map, filp);
57761d1b6a4SDaniel Borkmann 
57861d1b6a4SDaniel Borkmann 	bpf_map_put_with_uref(map);
57999c55f7dSAlexei Starovoitov 	return 0;
58099c55f7dSAlexei Starovoitov }
58199c55f7dSAlexei Starovoitov 
58287df15deSDaniel Borkmann static fmode_t map_get_sys_perms(struct bpf_map *map, struct fd f)
58387df15deSDaniel Borkmann {
58487df15deSDaniel Borkmann 	fmode_t mode = f.file->f_mode;
58587df15deSDaniel Borkmann 
58687df15deSDaniel Borkmann 	/* Our file permissions may have been overridden by global
58787df15deSDaniel Borkmann 	 * map permissions facing syscall side.
58887df15deSDaniel Borkmann 	 */
58987df15deSDaniel Borkmann 	if (READ_ONCE(map->frozen))
59087df15deSDaniel Borkmann 		mode &= ~FMODE_CAN_WRITE;
59187df15deSDaniel Borkmann 	return mode;
59287df15deSDaniel Borkmann }
59387df15deSDaniel Borkmann 
594f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
595f99bf205SDaniel Borkmann static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)
596f99bf205SDaniel Borkmann {
597f99bf205SDaniel Borkmann 	const struct bpf_map *map = filp->private_data;
59821116b70SDaniel Borkmann 	const struct bpf_array *array;
5992beee5f5SDaniel Borkmann 	u32 type = 0, jited = 0;
60021116b70SDaniel Borkmann 
60121116b70SDaniel Borkmann 	if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) {
60221116b70SDaniel Borkmann 		array = container_of(map, struct bpf_array, map);
6032beee5f5SDaniel Borkmann 		type  = array->aux->type;
6042beee5f5SDaniel Borkmann 		jited = array->aux->jited;
60521116b70SDaniel Borkmann 	}
606f99bf205SDaniel Borkmann 
607f99bf205SDaniel Borkmann 	seq_printf(m,
608f99bf205SDaniel Borkmann 		   "map_type:\t%u\n"
609f99bf205SDaniel Borkmann 		   "key_size:\t%u\n"
610f99bf205SDaniel Borkmann 		   "value_size:\t%u\n"
611322cea2fSDaniel Borkmann 		   "max_entries:\t%u\n"
61221116b70SDaniel Borkmann 		   "map_flags:\t%#x\n"
6134316b409SDaniel Borkmann 		   "memlock:\t%llu\n"
61487df15deSDaniel Borkmann 		   "map_id:\t%u\n"
61587df15deSDaniel Borkmann 		   "frozen:\t%u\n",
616f99bf205SDaniel Borkmann 		   map->map_type,
617f99bf205SDaniel Borkmann 		   map->key_size,
618f99bf205SDaniel Borkmann 		   map->value_size,
619322cea2fSDaniel Borkmann 		   map->max_entries,
62021116b70SDaniel Borkmann 		   map->map_flags,
6213539b96eSRoman Gushchin 		   map->memory.pages * 1ULL << PAGE_SHIFT,
62287df15deSDaniel Borkmann 		   map->id,
62387df15deSDaniel Borkmann 		   READ_ONCE(map->frozen));
6242beee5f5SDaniel Borkmann 	if (type) {
6252beee5f5SDaniel Borkmann 		seq_printf(m, "owner_prog_type:\t%u\n", type);
6262beee5f5SDaniel Borkmann 		seq_printf(m, "owner_jited:\t%u\n", jited);
6279780c0abSDaniel Borkmann 	}
628f99bf205SDaniel Borkmann }
629f99bf205SDaniel Borkmann #endif
630f99bf205SDaniel Borkmann 
6316e71b04aSChenbo Feng static ssize_t bpf_dummy_read(struct file *filp, char __user *buf, size_t siz,
6326e71b04aSChenbo Feng 			      loff_t *ppos)
6336e71b04aSChenbo Feng {
6346e71b04aSChenbo Feng 	/* We need this handler such that alloc_file() enables
6356e71b04aSChenbo Feng 	 * f_mode with FMODE_CAN_READ.
6366e71b04aSChenbo Feng 	 */
6376e71b04aSChenbo Feng 	return -EINVAL;
6386e71b04aSChenbo Feng }
6396e71b04aSChenbo Feng 
6406e71b04aSChenbo Feng static ssize_t bpf_dummy_write(struct file *filp, const char __user *buf,
6416e71b04aSChenbo Feng 			       size_t siz, loff_t *ppos)
6426e71b04aSChenbo Feng {
6436e71b04aSChenbo Feng 	/* We need this handler such that alloc_file() enables
6446e71b04aSChenbo Feng 	 * f_mode with FMODE_CAN_WRITE.
6456e71b04aSChenbo Feng 	 */
6466e71b04aSChenbo Feng 	return -EINVAL;
6476e71b04aSChenbo Feng }
6486e71b04aSChenbo Feng 
649fc970227SAndrii Nakryiko /* called for any extra memory-mapped regions (except initial) */
650fc970227SAndrii Nakryiko static void bpf_map_mmap_open(struct vm_area_struct *vma)
651fc970227SAndrii Nakryiko {
652fc970227SAndrii Nakryiko 	struct bpf_map *map = vma->vm_file->private_data;
653fc970227SAndrii Nakryiko 
6541f6cb19bSAndrii Nakryiko 	if (vma->vm_flags & VM_MAYWRITE) {
655fc970227SAndrii Nakryiko 		mutex_lock(&map->freeze_mutex);
656fc970227SAndrii Nakryiko 		map->writecnt++;
657fc970227SAndrii Nakryiko 		mutex_unlock(&map->freeze_mutex);
658fc970227SAndrii Nakryiko 	}
659fc970227SAndrii Nakryiko }
660fc970227SAndrii Nakryiko 
661fc970227SAndrii Nakryiko /* called for all unmapped memory region (including initial) */
662fc970227SAndrii Nakryiko static void bpf_map_mmap_close(struct vm_area_struct *vma)
663fc970227SAndrii Nakryiko {
664fc970227SAndrii Nakryiko 	struct bpf_map *map = vma->vm_file->private_data;
665fc970227SAndrii Nakryiko 
6661f6cb19bSAndrii Nakryiko 	if (vma->vm_flags & VM_MAYWRITE) {
667fc970227SAndrii Nakryiko 		mutex_lock(&map->freeze_mutex);
668fc970227SAndrii Nakryiko 		map->writecnt--;
669fc970227SAndrii Nakryiko 		mutex_unlock(&map->freeze_mutex);
670fc970227SAndrii Nakryiko 	}
671fc970227SAndrii Nakryiko }
672fc970227SAndrii Nakryiko 
673fc970227SAndrii Nakryiko static const struct vm_operations_struct bpf_map_default_vmops = {
674fc970227SAndrii Nakryiko 	.open		= bpf_map_mmap_open,
675fc970227SAndrii Nakryiko 	.close		= bpf_map_mmap_close,
676fc970227SAndrii Nakryiko };
677fc970227SAndrii Nakryiko 
678fc970227SAndrii Nakryiko static int bpf_map_mmap(struct file *filp, struct vm_area_struct *vma)
679fc970227SAndrii Nakryiko {
680fc970227SAndrii Nakryiko 	struct bpf_map *map = filp->private_data;
681fc970227SAndrii Nakryiko 	int err;
682fc970227SAndrii Nakryiko 
683fc970227SAndrii Nakryiko 	if (!map->ops->map_mmap || map_value_has_spin_lock(map))
684fc970227SAndrii Nakryiko 		return -ENOTSUPP;
685fc970227SAndrii Nakryiko 
686fc970227SAndrii Nakryiko 	if (!(vma->vm_flags & VM_SHARED))
687fc970227SAndrii Nakryiko 		return -EINVAL;
688fc970227SAndrii Nakryiko 
689fc970227SAndrii Nakryiko 	mutex_lock(&map->freeze_mutex);
690fc970227SAndrii Nakryiko 
691dfeb376dSAndrii Nakryiko 	if (vma->vm_flags & VM_WRITE) {
692dfeb376dSAndrii Nakryiko 		if (map->frozen) {
693fc970227SAndrii Nakryiko 			err = -EPERM;
694fc970227SAndrii Nakryiko 			goto out;
695fc970227SAndrii Nakryiko 		}
696dfeb376dSAndrii Nakryiko 		/* map is meant to be read-only, so do not allow mapping as
697dfeb376dSAndrii Nakryiko 		 * writable, because it's possible to leak a writable page
698dfeb376dSAndrii Nakryiko 		 * reference and allows user-space to still modify it after
699dfeb376dSAndrii Nakryiko 		 * freezing, while verifier will assume contents do not change
700dfeb376dSAndrii Nakryiko 		 */
701dfeb376dSAndrii Nakryiko 		if (map->map_flags & BPF_F_RDONLY_PROG) {
702dfeb376dSAndrii Nakryiko 			err = -EACCES;
703dfeb376dSAndrii Nakryiko 			goto out;
704dfeb376dSAndrii Nakryiko 		}
705dfeb376dSAndrii Nakryiko 	}
706fc970227SAndrii Nakryiko 
707fc970227SAndrii Nakryiko 	/* set default open/close callbacks */
708fc970227SAndrii Nakryiko 	vma->vm_ops = &bpf_map_default_vmops;
709fc970227SAndrii Nakryiko 	vma->vm_private_data = map;
7101f6cb19bSAndrii Nakryiko 	vma->vm_flags &= ~VM_MAYEXEC;
7111f6cb19bSAndrii Nakryiko 	if (!(vma->vm_flags & VM_WRITE))
7121f6cb19bSAndrii Nakryiko 		/* disallow re-mapping with PROT_WRITE */
7131f6cb19bSAndrii Nakryiko 		vma->vm_flags &= ~VM_MAYWRITE;
714fc970227SAndrii Nakryiko 
715fc970227SAndrii Nakryiko 	err = map->ops->map_mmap(map, vma);
716fc970227SAndrii Nakryiko 	if (err)
717fc970227SAndrii Nakryiko 		goto out;
718fc970227SAndrii Nakryiko 
7191f6cb19bSAndrii Nakryiko 	if (vma->vm_flags & VM_MAYWRITE)
720fc970227SAndrii Nakryiko 		map->writecnt++;
721fc970227SAndrii Nakryiko out:
722fc970227SAndrii Nakryiko 	mutex_unlock(&map->freeze_mutex);
723fc970227SAndrii Nakryiko 	return err;
724fc970227SAndrii Nakryiko }
725fc970227SAndrii Nakryiko 
726457f4436SAndrii Nakryiko static __poll_t bpf_map_poll(struct file *filp, struct poll_table_struct *pts)
727457f4436SAndrii Nakryiko {
728457f4436SAndrii Nakryiko 	struct bpf_map *map = filp->private_data;
729457f4436SAndrii Nakryiko 
730457f4436SAndrii Nakryiko 	if (map->ops->map_poll)
731457f4436SAndrii Nakryiko 		return map->ops->map_poll(map, filp, pts);
732457f4436SAndrii Nakryiko 
733457f4436SAndrii Nakryiko 	return EPOLLERR;
734457f4436SAndrii Nakryiko }
735457f4436SAndrii Nakryiko 
736f66e448cSChenbo Feng const struct file_operations bpf_map_fops = {
737f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
738f99bf205SDaniel Borkmann 	.show_fdinfo	= bpf_map_show_fdinfo,
739f99bf205SDaniel Borkmann #endif
74099c55f7dSAlexei Starovoitov 	.release	= bpf_map_release,
7416e71b04aSChenbo Feng 	.read		= bpf_dummy_read,
7426e71b04aSChenbo Feng 	.write		= bpf_dummy_write,
743fc970227SAndrii Nakryiko 	.mmap		= bpf_map_mmap,
744457f4436SAndrii Nakryiko 	.poll		= bpf_map_poll,
74599c55f7dSAlexei Starovoitov };
74699c55f7dSAlexei Starovoitov 
7476e71b04aSChenbo Feng int bpf_map_new_fd(struct bpf_map *map, int flags)
748aa79781bSDaniel Borkmann {
749afdb09c7SChenbo Feng 	int ret;
750afdb09c7SChenbo Feng 
751afdb09c7SChenbo Feng 	ret = security_bpf_map(map, OPEN_FMODE(flags));
752afdb09c7SChenbo Feng 	if (ret < 0)
753afdb09c7SChenbo Feng 		return ret;
754afdb09c7SChenbo Feng 
755aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-map", &bpf_map_fops, map,
7566e71b04aSChenbo Feng 				flags | O_CLOEXEC);
7576e71b04aSChenbo Feng }
7586e71b04aSChenbo Feng 
7596e71b04aSChenbo Feng int bpf_get_file_flag(int flags)
7606e71b04aSChenbo Feng {
7616e71b04aSChenbo Feng 	if ((flags & BPF_F_RDONLY) && (flags & BPF_F_WRONLY))
7626e71b04aSChenbo Feng 		return -EINVAL;
7636e71b04aSChenbo Feng 	if (flags & BPF_F_RDONLY)
7646e71b04aSChenbo Feng 		return O_RDONLY;
7656e71b04aSChenbo Feng 	if (flags & BPF_F_WRONLY)
7666e71b04aSChenbo Feng 		return O_WRONLY;
7676e71b04aSChenbo Feng 	return O_RDWR;
768aa79781bSDaniel Borkmann }
769aa79781bSDaniel Borkmann 
77099c55f7dSAlexei Starovoitov /* helper macro to check that unused fields 'union bpf_attr' are zero */
77199c55f7dSAlexei Starovoitov #define CHECK_ATTR(CMD) \
77299c55f7dSAlexei Starovoitov 	memchr_inv((void *) &attr->CMD##_LAST_FIELD + \
77399c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD), 0, \
77499c55f7dSAlexei Starovoitov 		   sizeof(*attr) - \
77599c55f7dSAlexei Starovoitov 		   offsetof(union bpf_attr, CMD##_LAST_FIELD) - \
77699c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD)) != NULL
77799c55f7dSAlexei Starovoitov 
7788e7ae251SMartin KaFai Lau /* dst and src must have at least "size" number of bytes.
7798e7ae251SMartin KaFai Lau  * Return strlen on success and < 0 on error.
780cb4d2b3fSMartin KaFai Lau  */
7818e7ae251SMartin KaFai Lau int bpf_obj_name_cpy(char *dst, const char *src, unsigned int size)
782cb4d2b3fSMartin KaFai Lau {
7838e7ae251SMartin KaFai Lau 	const char *end = src + size;
7848e7ae251SMartin KaFai Lau 	const char *orig_src = src;
785cb4d2b3fSMartin KaFai Lau 
7868e7ae251SMartin KaFai Lau 	memset(dst, 0, size);
7873e0ddc4fSDaniel Borkmann 	/* Copy all isalnum(), '_' and '.' chars. */
788cb4d2b3fSMartin KaFai Lau 	while (src < end && *src) {
7893e0ddc4fSDaniel Borkmann 		if (!isalnum(*src) &&
7903e0ddc4fSDaniel Borkmann 		    *src != '_' && *src != '.')
791cb4d2b3fSMartin KaFai Lau 			return -EINVAL;
792cb4d2b3fSMartin KaFai Lau 		*dst++ = *src++;
793cb4d2b3fSMartin KaFai Lau 	}
794cb4d2b3fSMartin KaFai Lau 
7958e7ae251SMartin KaFai Lau 	/* No '\0' found in "size" number of bytes */
796cb4d2b3fSMartin KaFai Lau 	if (src == end)
797cb4d2b3fSMartin KaFai Lau 		return -EINVAL;
798cb4d2b3fSMartin KaFai Lau 
7998e7ae251SMartin KaFai Lau 	return src - orig_src;
800cb4d2b3fSMartin KaFai Lau }
801cb4d2b3fSMartin KaFai Lau 
802e8d2bec0SDaniel Borkmann int map_check_no_btf(const struct bpf_map *map,
8031b2b234bSRoman Gushchin 		     const struct btf *btf,
804e8d2bec0SDaniel Borkmann 		     const struct btf_type *key_type,
805e8d2bec0SDaniel Borkmann 		     const struct btf_type *value_type)
806e8d2bec0SDaniel Borkmann {
807e8d2bec0SDaniel Borkmann 	return -ENOTSUPP;
808e8d2bec0SDaniel Borkmann }
809e8d2bec0SDaniel Borkmann 
810d83525caSAlexei Starovoitov static int map_check_btf(struct bpf_map *map, const struct btf *btf,
811e8d2bec0SDaniel Borkmann 			 u32 btf_key_id, u32 btf_value_id)
812e8d2bec0SDaniel Borkmann {
813e8d2bec0SDaniel Borkmann 	const struct btf_type *key_type, *value_type;
814e8d2bec0SDaniel Borkmann 	u32 key_size, value_size;
815e8d2bec0SDaniel Borkmann 	int ret = 0;
816e8d2bec0SDaniel Borkmann 
8172824ecb7SDaniel Borkmann 	/* Some maps allow key to be unspecified. */
8182824ecb7SDaniel Borkmann 	if (btf_key_id) {
819e8d2bec0SDaniel Borkmann 		key_type = btf_type_id_size(btf, &btf_key_id, &key_size);
820e8d2bec0SDaniel Borkmann 		if (!key_type || key_size != map->key_size)
821e8d2bec0SDaniel Borkmann 			return -EINVAL;
8222824ecb7SDaniel Borkmann 	} else {
8232824ecb7SDaniel Borkmann 		key_type = btf_type_by_id(btf, 0);
8242824ecb7SDaniel Borkmann 		if (!map->ops->map_check_btf)
8252824ecb7SDaniel Borkmann 			return -EINVAL;
8262824ecb7SDaniel Borkmann 	}
827e8d2bec0SDaniel Borkmann 
828e8d2bec0SDaniel Borkmann 	value_type = btf_type_id_size(btf, &btf_value_id, &value_size);
829e8d2bec0SDaniel Borkmann 	if (!value_type || value_size != map->value_size)
830e8d2bec0SDaniel Borkmann 		return -EINVAL;
831e8d2bec0SDaniel Borkmann 
832d83525caSAlexei Starovoitov 	map->spin_lock_off = btf_find_spin_lock(btf, value_type);
833d83525caSAlexei Starovoitov 
834d83525caSAlexei Starovoitov 	if (map_value_has_spin_lock(map)) {
835591fe988SDaniel Borkmann 		if (map->map_flags & BPF_F_RDONLY_PROG)
836591fe988SDaniel Borkmann 			return -EACCES;
837d83525caSAlexei Starovoitov 		if (map->map_type != BPF_MAP_TYPE_HASH &&
838e16d2f1aSAlexei Starovoitov 		    map->map_type != BPF_MAP_TYPE_ARRAY &&
8396ac99e8fSMartin KaFai Lau 		    map->map_type != BPF_MAP_TYPE_CGROUP_STORAGE &&
8408ea63684SKP Singh 		    map->map_type != BPF_MAP_TYPE_SK_STORAGE &&
8414cf1bc1fSKP Singh 		    map->map_type != BPF_MAP_TYPE_INODE_STORAGE &&
8424cf1bc1fSKP Singh 		    map->map_type != BPF_MAP_TYPE_TASK_STORAGE)
843d83525caSAlexei Starovoitov 			return -ENOTSUPP;
844d83525caSAlexei Starovoitov 		if (map->spin_lock_off + sizeof(struct bpf_spin_lock) >
845d83525caSAlexei Starovoitov 		    map->value_size) {
846d83525caSAlexei Starovoitov 			WARN_ONCE(1,
847d83525caSAlexei Starovoitov 				  "verifier bug spin_lock_off %d value_size %d\n",
848d83525caSAlexei Starovoitov 				  map->spin_lock_off, map->value_size);
849d83525caSAlexei Starovoitov 			return -EFAULT;
850d83525caSAlexei Starovoitov 		}
851d83525caSAlexei Starovoitov 	}
852d83525caSAlexei Starovoitov 
853e8d2bec0SDaniel Borkmann 	if (map->ops->map_check_btf)
8541b2b234bSRoman Gushchin 		ret = map->ops->map_check_btf(map, btf, key_type, value_type);
855e8d2bec0SDaniel Borkmann 
856e8d2bec0SDaniel Borkmann 	return ret;
857e8d2bec0SDaniel Borkmann }
858e8d2bec0SDaniel Borkmann 
85985d33df3SMartin KaFai Lau #define BPF_MAP_CREATE_LAST_FIELD btf_vmlinux_value_type_id
86099c55f7dSAlexei Starovoitov /* called via syscall */
86199c55f7dSAlexei Starovoitov static int map_create(union bpf_attr *attr)
86299c55f7dSAlexei Starovoitov {
86396eabe7aSMartin KaFai Lau 	int numa_node = bpf_map_attr_numa_node(attr);
864b936ca64SRoman Gushchin 	struct bpf_map_memory mem;
86599c55f7dSAlexei Starovoitov 	struct bpf_map *map;
8666e71b04aSChenbo Feng 	int f_flags;
86799c55f7dSAlexei Starovoitov 	int err;
86899c55f7dSAlexei Starovoitov 
86999c55f7dSAlexei Starovoitov 	err = CHECK_ATTR(BPF_MAP_CREATE);
87099c55f7dSAlexei Starovoitov 	if (err)
87199c55f7dSAlexei Starovoitov 		return -EINVAL;
87299c55f7dSAlexei Starovoitov 
87385d33df3SMartin KaFai Lau 	if (attr->btf_vmlinux_value_type_id) {
87485d33df3SMartin KaFai Lau 		if (attr->map_type != BPF_MAP_TYPE_STRUCT_OPS ||
87585d33df3SMartin KaFai Lau 		    attr->btf_key_type_id || attr->btf_value_type_id)
87685d33df3SMartin KaFai Lau 			return -EINVAL;
87785d33df3SMartin KaFai Lau 	} else if (attr->btf_key_type_id && !attr->btf_value_type_id) {
87885d33df3SMartin KaFai Lau 		return -EINVAL;
87985d33df3SMartin KaFai Lau 	}
88085d33df3SMartin KaFai Lau 
8816e71b04aSChenbo Feng 	f_flags = bpf_get_file_flag(attr->map_flags);
8826e71b04aSChenbo Feng 	if (f_flags < 0)
8836e71b04aSChenbo Feng 		return f_flags;
8846e71b04aSChenbo Feng 
88596eabe7aSMartin KaFai Lau 	if (numa_node != NUMA_NO_NODE &&
88696e5ae4eSEric Dumazet 	    ((unsigned int)numa_node >= nr_node_ids ||
88796e5ae4eSEric Dumazet 	     !node_online(numa_node)))
88896eabe7aSMartin KaFai Lau 		return -EINVAL;
88996eabe7aSMartin KaFai Lau 
89099c55f7dSAlexei Starovoitov 	/* find map type and init map: hashtable vs rbtree vs bloom vs ... */
89199c55f7dSAlexei Starovoitov 	map = find_and_alloc_map(attr);
89299c55f7dSAlexei Starovoitov 	if (IS_ERR(map))
89399c55f7dSAlexei Starovoitov 		return PTR_ERR(map);
89499c55f7dSAlexei Starovoitov 
8958e7ae251SMartin KaFai Lau 	err = bpf_obj_name_cpy(map->name, attr->map_name,
8968e7ae251SMartin KaFai Lau 			       sizeof(attr->map_name));
8978e7ae251SMartin KaFai Lau 	if (err < 0)
898b936ca64SRoman Gushchin 		goto free_map;
899ad5b177bSMartin KaFai Lau 
9001e0bd5a0SAndrii Nakryiko 	atomic64_set(&map->refcnt, 1);
9011e0bd5a0SAndrii Nakryiko 	atomic64_set(&map->usercnt, 1);
902fc970227SAndrii Nakryiko 	mutex_init(&map->freeze_mutex);
90399c55f7dSAlexei Starovoitov 
90485d33df3SMartin KaFai Lau 	map->spin_lock_off = -EINVAL;
90585d33df3SMartin KaFai Lau 	if (attr->btf_key_type_id || attr->btf_value_type_id ||
90685d33df3SMartin KaFai Lau 	    /* Even the map's value is a kernel's struct,
90785d33df3SMartin KaFai Lau 	     * the bpf_prog.o must have BTF to begin with
90885d33df3SMartin KaFai Lau 	     * to figure out the corresponding kernel's
90985d33df3SMartin KaFai Lau 	     * counter part.  Thus, attr->btf_fd has
91085d33df3SMartin KaFai Lau 	     * to be valid also.
91185d33df3SMartin KaFai Lau 	     */
91285d33df3SMartin KaFai Lau 	    attr->btf_vmlinux_value_type_id) {
913a26ca7c9SMartin KaFai Lau 		struct btf *btf;
914a26ca7c9SMartin KaFai Lau 
915a26ca7c9SMartin KaFai Lau 		btf = btf_get_by_fd(attr->btf_fd);
916a26ca7c9SMartin KaFai Lau 		if (IS_ERR(btf)) {
917a26ca7c9SMartin KaFai Lau 			err = PTR_ERR(btf);
918b936ca64SRoman Gushchin 			goto free_map;
919a26ca7c9SMartin KaFai Lau 		}
92085d33df3SMartin KaFai Lau 		map->btf = btf;
921a26ca7c9SMartin KaFai Lau 
92285d33df3SMartin KaFai Lau 		if (attr->btf_value_type_id) {
923e8d2bec0SDaniel Borkmann 			err = map_check_btf(map, btf, attr->btf_key_type_id,
9249b2cf328SMartin KaFai Lau 					    attr->btf_value_type_id);
92585d33df3SMartin KaFai Lau 			if (err)
926b936ca64SRoman Gushchin 				goto free_map;
927a26ca7c9SMartin KaFai Lau 		}
928a26ca7c9SMartin KaFai Lau 
9299b2cf328SMartin KaFai Lau 		map->btf_key_type_id = attr->btf_key_type_id;
9309b2cf328SMartin KaFai Lau 		map->btf_value_type_id = attr->btf_value_type_id;
93185d33df3SMartin KaFai Lau 		map->btf_vmlinux_value_type_id =
93285d33df3SMartin KaFai Lau 			attr->btf_vmlinux_value_type_id;
933a26ca7c9SMartin KaFai Lau 	}
934a26ca7c9SMartin KaFai Lau 
935afdb09c7SChenbo Feng 	err = security_bpf_map_alloc(map);
936aaac3ba9SAlexei Starovoitov 	if (err)
937b936ca64SRoman Gushchin 		goto free_map;
938afdb09c7SChenbo Feng 
939f3f1c054SMartin KaFai Lau 	err = bpf_map_alloc_id(map);
940f3f1c054SMartin KaFai Lau 	if (err)
941b936ca64SRoman Gushchin 		goto free_map_sec;
942f3f1c054SMartin KaFai Lau 
94348edc1f7SRoman Gushchin 	bpf_map_save_memcg(map);
94448edc1f7SRoman Gushchin 
9456e71b04aSChenbo Feng 	err = bpf_map_new_fd(map, f_flags);
946bd5f5f4eSMartin KaFai Lau 	if (err < 0) {
947bd5f5f4eSMartin KaFai Lau 		/* failed to allocate fd.
948352d20d6SPeng Sun 		 * bpf_map_put_with_uref() is needed because the above
949bd5f5f4eSMartin KaFai Lau 		 * bpf_map_alloc_id() has published the map
950bd5f5f4eSMartin KaFai Lau 		 * to the userspace and the userspace may
951bd5f5f4eSMartin KaFai Lau 		 * have refcnt-ed it through BPF_MAP_GET_FD_BY_ID.
952bd5f5f4eSMartin KaFai Lau 		 */
953352d20d6SPeng Sun 		bpf_map_put_with_uref(map);
954bd5f5f4eSMartin KaFai Lau 		return err;
955bd5f5f4eSMartin KaFai Lau 	}
95699c55f7dSAlexei Starovoitov 
95799c55f7dSAlexei Starovoitov 	return err;
95899c55f7dSAlexei Starovoitov 
959afdb09c7SChenbo Feng free_map_sec:
960afdb09c7SChenbo Feng 	security_bpf_map_free(map);
961b936ca64SRoman Gushchin free_map:
962a26ca7c9SMartin KaFai Lau 	btf_put(map->btf);
963b936ca64SRoman Gushchin 	bpf_map_charge_move(&mem, &map->memory);
96499c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
965b936ca64SRoman Gushchin 	bpf_map_charge_finish(&mem);
96699c55f7dSAlexei Starovoitov 	return err;
96799c55f7dSAlexei Starovoitov }
96899c55f7dSAlexei Starovoitov 
969db20fd2bSAlexei Starovoitov /* if error is returned, fd is released.
970db20fd2bSAlexei Starovoitov  * On success caller should complete fd access with matching fdput()
971db20fd2bSAlexei Starovoitov  */
972c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f)
973db20fd2bSAlexei Starovoitov {
974db20fd2bSAlexei Starovoitov 	if (!f.file)
975db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EBADF);
976db20fd2bSAlexei Starovoitov 	if (f.file->f_op != &bpf_map_fops) {
977db20fd2bSAlexei Starovoitov 		fdput(f);
978db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EINVAL);
979db20fd2bSAlexei Starovoitov 	}
980db20fd2bSAlexei Starovoitov 
981c2101297SDaniel Borkmann 	return f.file->private_data;
982c2101297SDaniel Borkmann }
983c2101297SDaniel Borkmann 
9841e0bd5a0SAndrii Nakryiko void bpf_map_inc(struct bpf_map *map)
985c9da161cSDaniel Borkmann {
9861e0bd5a0SAndrii Nakryiko 	atomic64_inc(&map->refcnt);
987c9da161cSDaniel Borkmann }
988630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_inc);
989c9da161cSDaniel Borkmann 
9901e0bd5a0SAndrii Nakryiko void bpf_map_inc_with_uref(struct bpf_map *map)
9911e0bd5a0SAndrii Nakryiko {
9921e0bd5a0SAndrii Nakryiko 	atomic64_inc(&map->refcnt);
9931e0bd5a0SAndrii Nakryiko 	atomic64_inc(&map->usercnt);
9941e0bd5a0SAndrii Nakryiko }
9951e0bd5a0SAndrii Nakryiko EXPORT_SYMBOL_GPL(bpf_map_inc_with_uref);
9961e0bd5a0SAndrii Nakryiko 
9971ed4d924SMartin KaFai Lau struct bpf_map *bpf_map_get(u32 ufd)
9981ed4d924SMartin KaFai Lau {
9991ed4d924SMartin KaFai Lau 	struct fd f = fdget(ufd);
10001ed4d924SMartin KaFai Lau 	struct bpf_map *map;
10011ed4d924SMartin KaFai Lau 
10021ed4d924SMartin KaFai Lau 	map = __bpf_map_get(f);
10031ed4d924SMartin KaFai Lau 	if (IS_ERR(map))
10041ed4d924SMartin KaFai Lau 		return map;
10051ed4d924SMartin KaFai Lau 
10061ed4d924SMartin KaFai Lau 	bpf_map_inc(map);
10071ed4d924SMartin KaFai Lau 	fdput(f);
10081ed4d924SMartin KaFai Lau 
10091ed4d924SMartin KaFai Lau 	return map;
10101ed4d924SMartin KaFai Lau }
10111ed4d924SMartin KaFai Lau 
1012c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd)
1013c2101297SDaniel Borkmann {
1014c2101297SDaniel Borkmann 	struct fd f = fdget(ufd);
1015c2101297SDaniel Borkmann 	struct bpf_map *map;
1016c2101297SDaniel Borkmann 
1017c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1018c2101297SDaniel Borkmann 	if (IS_ERR(map))
1019c2101297SDaniel Borkmann 		return map;
1020c2101297SDaniel Borkmann 
10211e0bd5a0SAndrii Nakryiko 	bpf_map_inc_with_uref(map);
1022c2101297SDaniel Borkmann 	fdput(f);
1023db20fd2bSAlexei Starovoitov 
1024db20fd2bSAlexei Starovoitov 	return map;
1025db20fd2bSAlexei Starovoitov }
1026db20fd2bSAlexei Starovoitov 
1027bd5f5f4eSMartin KaFai Lau /* map_idr_lock should have been held */
10281e0bd5a0SAndrii Nakryiko static struct bpf_map *__bpf_map_inc_not_zero(struct bpf_map *map, bool uref)
1029bd5f5f4eSMartin KaFai Lau {
1030bd5f5f4eSMartin KaFai Lau 	int refold;
1031bd5f5f4eSMartin KaFai Lau 
10321e0bd5a0SAndrii Nakryiko 	refold = atomic64_fetch_add_unless(&map->refcnt, 1, 0);
1033bd5f5f4eSMartin KaFai Lau 	if (!refold)
1034bd5f5f4eSMartin KaFai Lau 		return ERR_PTR(-ENOENT);
1035bd5f5f4eSMartin KaFai Lau 	if (uref)
10361e0bd5a0SAndrii Nakryiko 		atomic64_inc(&map->usercnt);
1037bd5f5f4eSMartin KaFai Lau 
1038bd5f5f4eSMartin KaFai Lau 	return map;
1039bd5f5f4eSMartin KaFai Lau }
1040bd5f5f4eSMartin KaFai Lau 
10411e0bd5a0SAndrii Nakryiko struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map)
1042b0e4701cSStanislav Fomichev {
1043b0e4701cSStanislav Fomichev 	spin_lock_bh(&map_idr_lock);
10441e0bd5a0SAndrii Nakryiko 	map = __bpf_map_inc_not_zero(map, false);
1045b0e4701cSStanislav Fomichev 	spin_unlock_bh(&map_idr_lock);
1046b0e4701cSStanislav Fomichev 
1047b0e4701cSStanislav Fomichev 	return map;
1048b0e4701cSStanislav Fomichev }
1049b0e4701cSStanislav Fomichev EXPORT_SYMBOL_GPL(bpf_map_inc_not_zero);
1050b0e4701cSStanislav Fomichev 
1051b8cdc051SAlexei Starovoitov int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
1052b8cdc051SAlexei Starovoitov {
1053b8cdc051SAlexei Starovoitov 	return -ENOTSUPP;
1054b8cdc051SAlexei Starovoitov }
1055b8cdc051SAlexei Starovoitov 
1056c9d29f46SMauricio Vasquez B static void *__bpf_copy_key(void __user *ukey, u64 key_size)
1057c9d29f46SMauricio Vasquez B {
1058c9d29f46SMauricio Vasquez B 	if (key_size)
1059c9d29f46SMauricio Vasquez B 		return memdup_user(ukey, key_size);
1060c9d29f46SMauricio Vasquez B 
1061c9d29f46SMauricio Vasquez B 	if (ukey)
1062c9d29f46SMauricio Vasquez B 		return ERR_PTR(-EINVAL);
1063c9d29f46SMauricio Vasquez B 
1064c9d29f46SMauricio Vasquez B 	return NULL;
1065c9d29f46SMauricio Vasquez B }
1066c9d29f46SMauricio Vasquez B 
1067db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
106896049f3aSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD flags
1069db20fd2bSAlexei Starovoitov 
1070db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr)
1071db20fd2bSAlexei Starovoitov {
1072535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
1073535e7b4bSMickaël Salaün 	void __user *uvalue = u64_to_user_ptr(attr->value);
1074db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1075db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
107615c14a3dSBrian Vazquez 	void *key, *value;
107715a07b33SAlexei Starovoitov 	u32 value_size;
1078592867bfSDaniel Borkmann 	struct fd f;
1079db20fd2bSAlexei Starovoitov 	int err;
1080db20fd2bSAlexei Starovoitov 
1081db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
1082db20fd2bSAlexei Starovoitov 		return -EINVAL;
1083db20fd2bSAlexei Starovoitov 
108496049f3aSAlexei Starovoitov 	if (attr->flags & ~BPF_F_LOCK)
108596049f3aSAlexei Starovoitov 		return -EINVAL;
108696049f3aSAlexei Starovoitov 
1087592867bfSDaniel Borkmann 	f = fdget(ufd);
1088c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1089db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1090db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
109187df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
10926e71b04aSChenbo Feng 		err = -EPERM;
10936e71b04aSChenbo Feng 		goto err_put;
10946e71b04aSChenbo Feng 	}
10956e71b04aSChenbo Feng 
109696049f3aSAlexei Starovoitov 	if ((attr->flags & BPF_F_LOCK) &&
109796049f3aSAlexei Starovoitov 	    !map_value_has_spin_lock(map)) {
109896049f3aSAlexei Starovoitov 		err = -EINVAL;
109996049f3aSAlexei Starovoitov 		goto err_put;
110096049f3aSAlexei Starovoitov 	}
110196049f3aSAlexei Starovoitov 
1102c9d29f46SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
1103e4448ed8SAl Viro 	if (IS_ERR(key)) {
1104e4448ed8SAl Viro 		err = PTR_ERR(key);
1105db20fd2bSAlexei Starovoitov 		goto err_put;
1106e4448ed8SAl Viro 	}
1107db20fd2bSAlexei Starovoitov 
110815c14a3dSBrian Vazquez 	value_size = bpf_map_value_size(map);
110915a07b33SAlexei Starovoitov 
11108ebe667cSAlexei Starovoitov 	err = -ENOMEM;
111115a07b33SAlexei Starovoitov 	value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
1112db20fd2bSAlexei Starovoitov 	if (!value)
11138ebe667cSAlexei Starovoitov 		goto free_key;
11148ebe667cSAlexei Starovoitov 
111515c14a3dSBrian Vazquez 	err = bpf_map_copy_value(map, key, value, attr->flags);
111615a07b33SAlexei Starovoitov 	if (err)
11178ebe667cSAlexei Starovoitov 		goto free_value;
1118db20fd2bSAlexei Starovoitov 
1119db20fd2bSAlexei Starovoitov 	err = -EFAULT;
112015a07b33SAlexei Starovoitov 	if (copy_to_user(uvalue, value, value_size) != 0)
11218ebe667cSAlexei Starovoitov 		goto free_value;
1122db20fd2bSAlexei Starovoitov 
1123db20fd2bSAlexei Starovoitov 	err = 0;
1124db20fd2bSAlexei Starovoitov 
11258ebe667cSAlexei Starovoitov free_value:
11268ebe667cSAlexei Starovoitov 	kfree(value);
1127db20fd2bSAlexei Starovoitov free_key:
1128db20fd2bSAlexei Starovoitov 	kfree(key);
1129db20fd2bSAlexei Starovoitov err_put:
1130db20fd2bSAlexei Starovoitov 	fdput(f);
1131db20fd2bSAlexei Starovoitov 	return err;
1132db20fd2bSAlexei Starovoitov }
1133db20fd2bSAlexei Starovoitov 
11341ae80cf3SDaniel Colascione 
11353274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags
1136db20fd2bSAlexei Starovoitov 
1137db20fd2bSAlexei Starovoitov static int map_update_elem(union bpf_attr *attr)
1138db20fd2bSAlexei Starovoitov {
1139535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
1140535e7b4bSMickaël Salaün 	void __user *uvalue = u64_to_user_ptr(attr->value);
1141db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1142db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
1143db20fd2bSAlexei Starovoitov 	void *key, *value;
114415a07b33SAlexei Starovoitov 	u32 value_size;
1145592867bfSDaniel Borkmann 	struct fd f;
1146db20fd2bSAlexei Starovoitov 	int err;
1147db20fd2bSAlexei Starovoitov 
1148db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM))
1149db20fd2bSAlexei Starovoitov 		return -EINVAL;
1150db20fd2bSAlexei Starovoitov 
1151592867bfSDaniel Borkmann 	f = fdget(ufd);
1152c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1153db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1154db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
115587df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
11566e71b04aSChenbo Feng 		err = -EPERM;
11576e71b04aSChenbo Feng 		goto err_put;
11586e71b04aSChenbo Feng 	}
11596e71b04aSChenbo Feng 
116096049f3aSAlexei Starovoitov 	if ((attr->flags & BPF_F_LOCK) &&
116196049f3aSAlexei Starovoitov 	    !map_value_has_spin_lock(map)) {
116296049f3aSAlexei Starovoitov 		err = -EINVAL;
116396049f3aSAlexei Starovoitov 		goto err_put;
116496049f3aSAlexei Starovoitov 	}
116596049f3aSAlexei Starovoitov 
1166c9d29f46SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
1167e4448ed8SAl Viro 	if (IS_ERR(key)) {
1168e4448ed8SAl Viro 		err = PTR_ERR(key);
1169db20fd2bSAlexei Starovoitov 		goto err_put;
1170e4448ed8SAl Viro 	}
1171db20fd2bSAlexei Starovoitov 
117215a07b33SAlexei Starovoitov 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
11738f844938SMartin KaFai Lau 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
1174b741f163SRoman Gushchin 	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY ||
1175b741f163SRoman Gushchin 	    map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE)
117615a07b33SAlexei Starovoitov 		value_size = round_up(map->value_size, 8) * num_possible_cpus();
117715a07b33SAlexei Starovoitov 	else
117815a07b33SAlexei Starovoitov 		value_size = map->value_size;
117915a07b33SAlexei Starovoitov 
1180db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
118115a07b33SAlexei Starovoitov 	value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
1182db20fd2bSAlexei Starovoitov 	if (!value)
1183db20fd2bSAlexei Starovoitov 		goto free_key;
1184db20fd2bSAlexei Starovoitov 
1185db20fd2bSAlexei Starovoitov 	err = -EFAULT;
118615a07b33SAlexei Starovoitov 	if (copy_from_user(value, uvalue, value_size) != 0)
1187db20fd2bSAlexei Starovoitov 		goto free_value;
1188db20fd2bSAlexei Starovoitov 
118915c14a3dSBrian Vazquez 	err = bpf_map_update_value(map, f, key, value, attr->flags);
11906710e112SJesper Dangaard Brouer 
1191db20fd2bSAlexei Starovoitov free_value:
1192db20fd2bSAlexei Starovoitov 	kfree(value);
1193db20fd2bSAlexei Starovoitov free_key:
1194db20fd2bSAlexei Starovoitov 	kfree(key);
1195db20fd2bSAlexei Starovoitov err_put:
1196db20fd2bSAlexei Starovoitov 	fdput(f);
1197db20fd2bSAlexei Starovoitov 	return err;
1198db20fd2bSAlexei Starovoitov }
1199db20fd2bSAlexei Starovoitov 
1200db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key
1201db20fd2bSAlexei Starovoitov 
1202db20fd2bSAlexei Starovoitov static int map_delete_elem(union bpf_attr *attr)
1203db20fd2bSAlexei Starovoitov {
1204535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
1205db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1206db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
1207592867bfSDaniel Borkmann 	struct fd f;
1208db20fd2bSAlexei Starovoitov 	void *key;
1209db20fd2bSAlexei Starovoitov 	int err;
1210db20fd2bSAlexei Starovoitov 
1211db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_DELETE_ELEM))
1212db20fd2bSAlexei Starovoitov 		return -EINVAL;
1213db20fd2bSAlexei Starovoitov 
1214592867bfSDaniel Borkmann 	f = fdget(ufd);
1215c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1216db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1217db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
121887df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
12196e71b04aSChenbo Feng 		err = -EPERM;
12206e71b04aSChenbo Feng 		goto err_put;
12216e71b04aSChenbo Feng 	}
12226e71b04aSChenbo Feng 
1223c9d29f46SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
1224e4448ed8SAl Viro 	if (IS_ERR(key)) {
1225e4448ed8SAl Viro 		err = PTR_ERR(key);
1226db20fd2bSAlexei Starovoitov 		goto err_put;
1227e4448ed8SAl Viro 	}
1228db20fd2bSAlexei Starovoitov 
1229a3884572SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
1230a3884572SJakub Kicinski 		err = bpf_map_offload_delete_elem(map, key);
1231a3884572SJakub Kicinski 		goto out;
123285d33df3SMartin KaFai Lau 	} else if (IS_FD_PROG_ARRAY(map) ||
123385d33df3SMartin KaFai Lau 		   map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
123485d33df3SMartin KaFai Lau 		/* These maps require sleepable context */
1235da765a2fSDaniel Borkmann 		err = map->ops->map_delete_elem(map, key);
1236da765a2fSDaniel Borkmann 		goto out;
1237a3884572SJakub Kicinski 	}
1238a3884572SJakub Kicinski 
1239b6e5dae1SThomas Gleixner 	bpf_disable_instrumentation();
1240db20fd2bSAlexei Starovoitov 	rcu_read_lock();
1241db20fd2bSAlexei Starovoitov 	err = map->ops->map_delete_elem(map, key);
1242db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
1243b6e5dae1SThomas Gleixner 	bpf_enable_instrumentation();
12441ae80cf3SDaniel Colascione 	maybe_wait_bpf_programs(map);
1245a3884572SJakub Kicinski out:
1246db20fd2bSAlexei Starovoitov 	kfree(key);
1247db20fd2bSAlexei Starovoitov err_put:
1248db20fd2bSAlexei Starovoitov 	fdput(f);
1249db20fd2bSAlexei Starovoitov 	return err;
1250db20fd2bSAlexei Starovoitov }
1251db20fd2bSAlexei Starovoitov 
1252db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
1253db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key
1254db20fd2bSAlexei Starovoitov 
1255db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr)
1256db20fd2bSAlexei Starovoitov {
1257535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
1258535e7b4bSMickaël Salaün 	void __user *unext_key = u64_to_user_ptr(attr->next_key);
1259db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1260db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
1261db20fd2bSAlexei Starovoitov 	void *key, *next_key;
1262592867bfSDaniel Borkmann 	struct fd f;
1263db20fd2bSAlexei Starovoitov 	int err;
1264db20fd2bSAlexei Starovoitov 
1265db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY))
1266db20fd2bSAlexei Starovoitov 		return -EINVAL;
1267db20fd2bSAlexei Starovoitov 
1268592867bfSDaniel Borkmann 	f = fdget(ufd);
1269c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1270db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1271db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
127287df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
12736e71b04aSChenbo Feng 		err = -EPERM;
12746e71b04aSChenbo Feng 		goto err_put;
12756e71b04aSChenbo Feng 	}
12766e71b04aSChenbo Feng 
12778fe45924STeng Qin 	if (ukey) {
1278c9d29f46SMauricio Vasquez B 		key = __bpf_copy_key(ukey, map->key_size);
1279e4448ed8SAl Viro 		if (IS_ERR(key)) {
1280e4448ed8SAl Viro 			err = PTR_ERR(key);
1281db20fd2bSAlexei Starovoitov 			goto err_put;
1282e4448ed8SAl Viro 		}
12838fe45924STeng Qin 	} else {
12848fe45924STeng Qin 		key = NULL;
12858fe45924STeng Qin 	}
1286db20fd2bSAlexei Starovoitov 
1287db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
1288db20fd2bSAlexei Starovoitov 	next_key = kmalloc(map->key_size, GFP_USER);
1289db20fd2bSAlexei Starovoitov 	if (!next_key)
1290db20fd2bSAlexei Starovoitov 		goto free_key;
1291db20fd2bSAlexei Starovoitov 
1292a3884572SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
1293a3884572SJakub Kicinski 		err = bpf_map_offload_get_next_key(map, key, next_key);
1294a3884572SJakub Kicinski 		goto out;
1295a3884572SJakub Kicinski 	}
1296a3884572SJakub Kicinski 
1297db20fd2bSAlexei Starovoitov 	rcu_read_lock();
1298db20fd2bSAlexei Starovoitov 	err = map->ops->map_get_next_key(map, key, next_key);
1299db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
1300a3884572SJakub Kicinski out:
1301db20fd2bSAlexei Starovoitov 	if (err)
1302db20fd2bSAlexei Starovoitov 		goto free_next_key;
1303db20fd2bSAlexei Starovoitov 
1304db20fd2bSAlexei Starovoitov 	err = -EFAULT;
1305db20fd2bSAlexei Starovoitov 	if (copy_to_user(unext_key, next_key, map->key_size) != 0)
1306db20fd2bSAlexei Starovoitov 		goto free_next_key;
1307db20fd2bSAlexei Starovoitov 
1308db20fd2bSAlexei Starovoitov 	err = 0;
1309db20fd2bSAlexei Starovoitov 
1310db20fd2bSAlexei Starovoitov free_next_key:
1311db20fd2bSAlexei Starovoitov 	kfree(next_key);
1312db20fd2bSAlexei Starovoitov free_key:
1313db20fd2bSAlexei Starovoitov 	kfree(key);
1314db20fd2bSAlexei Starovoitov err_put:
1315db20fd2bSAlexei Starovoitov 	fdput(f);
1316db20fd2bSAlexei Starovoitov 	return err;
1317db20fd2bSAlexei Starovoitov }
1318db20fd2bSAlexei Starovoitov 
1319aa2e93b8SBrian Vazquez int generic_map_delete_batch(struct bpf_map *map,
1320aa2e93b8SBrian Vazquez 			     const union bpf_attr *attr,
1321aa2e93b8SBrian Vazquez 			     union bpf_attr __user *uattr)
1322aa2e93b8SBrian Vazquez {
1323aa2e93b8SBrian Vazquez 	void __user *keys = u64_to_user_ptr(attr->batch.keys);
1324aa2e93b8SBrian Vazquez 	u32 cp, max_count;
1325aa2e93b8SBrian Vazquez 	int err = 0;
1326aa2e93b8SBrian Vazquez 	void *key;
1327aa2e93b8SBrian Vazquez 
1328aa2e93b8SBrian Vazquez 	if (attr->batch.elem_flags & ~BPF_F_LOCK)
1329aa2e93b8SBrian Vazquez 		return -EINVAL;
1330aa2e93b8SBrian Vazquez 
1331aa2e93b8SBrian Vazquez 	if ((attr->batch.elem_flags & BPF_F_LOCK) &&
1332aa2e93b8SBrian Vazquez 	    !map_value_has_spin_lock(map)) {
1333aa2e93b8SBrian Vazquez 		return -EINVAL;
1334aa2e93b8SBrian Vazquez 	}
1335aa2e93b8SBrian Vazquez 
1336aa2e93b8SBrian Vazquez 	max_count = attr->batch.count;
1337aa2e93b8SBrian Vazquez 	if (!max_count)
1338aa2e93b8SBrian Vazquez 		return 0;
1339aa2e93b8SBrian Vazquez 
13402e3a94aaSBrian Vazquez 	key = kmalloc(map->key_size, GFP_USER | __GFP_NOWARN);
13412e3a94aaSBrian Vazquez 	if (!key)
13422e3a94aaSBrian Vazquez 		return -ENOMEM;
13432e3a94aaSBrian Vazquez 
1344aa2e93b8SBrian Vazquez 	for (cp = 0; cp < max_count; cp++) {
13452e3a94aaSBrian Vazquez 		err = -EFAULT;
13462e3a94aaSBrian Vazquez 		if (copy_from_user(key, keys + cp * map->key_size,
13472e3a94aaSBrian Vazquez 				   map->key_size))
1348aa2e93b8SBrian Vazquez 			break;
1349aa2e93b8SBrian Vazquez 
1350aa2e93b8SBrian Vazquez 		if (bpf_map_is_dev_bound(map)) {
1351aa2e93b8SBrian Vazquez 			err = bpf_map_offload_delete_elem(map, key);
1352aa2e93b8SBrian Vazquez 			break;
1353aa2e93b8SBrian Vazquez 		}
1354aa2e93b8SBrian Vazquez 
1355b6e5dae1SThomas Gleixner 		bpf_disable_instrumentation();
1356aa2e93b8SBrian Vazquez 		rcu_read_lock();
1357aa2e93b8SBrian Vazquez 		err = map->ops->map_delete_elem(map, key);
1358aa2e93b8SBrian Vazquez 		rcu_read_unlock();
1359b6e5dae1SThomas Gleixner 		bpf_enable_instrumentation();
1360aa2e93b8SBrian Vazquez 		maybe_wait_bpf_programs(map);
1361aa2e93b8SBrian Vazquez 		if (err)
1362aa2e93b8SBrian Vazquez 			break;
1363aa2e93b8SBrian Vazquez 	}
1364aa2e93b8SBrian Vazquez 	if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp)))
1365aa2e93b8SBrian Vazquez 		err = -EFAULT;
13662e3a94aaSBrian Vazquez 
13672e3a94aaSBrian Vazquez 	kfree(key);
1368aa2e93b8SBrian Vazquez 	return err;
1369aa2e93b8SBrian Vazquez }
1370aa2e93b8SBrian Vazquez 
1371aa2e93b8SBrian Vazquez int generic_map_update_batch(struct bpf_map *map,
1372aa2e93b8SBrian Vazquez 			     const union bpf_attr *attr,
1373aa2e93b8SBrian Vazquez 			     union bpf_attr __user *uattr)
1374aa2e93b8SBrian Vazquez {
1375aa2e93b8SBrian Vazquez 	void __user *values = u64_to_user_ptr(attr->batch.values);
1376aa2e93b8SBrian Vazquez 	void __user *keys = u64_to_user_ptr(attr->batch.keys);
1377aa2e93b8SBrian Vazquez 	u32 value_size, cp, max_count;
1378aa2e93b8SBrian Vazquez 	int ufd = attr->map_fd;
1379aa2e93b8SBrian Vazquez 	void *key, *value;
1380aa2e93b8SBrian Vazquez 	struct fd f;
1381aa2e93b8SBrian Vazquez 	int err = 0;
1382aa2e93b8SBrian Vazquez 
1383aa2e93b8SBrian Vazquez 	f = fdget(ufd);
1384aa2e93b8SBrian Vazquez 	if (attr->batch.elem_flags & ~BPF_F_LOCK)
1385aa2e93b8SBrian Vazquez 		return -EINVAL;
1386aa2e93b8SBrian Vazquez 
1387aa2e93b8SBrian Vazquez 	if ((attr->batch.elem_flags & BPF_F_LOCK) &&
1388aa2e93b8SBrian Vazquez 	    !map_value_has_spin_lock(map)) {
1389aa2e93b8SBrian Vazquez 		return -EINVAL;
1390aa2e93b8SBrian Vazquez 	}
1391aa2e93b8SBrian Vazquez 
1392aa2e93b8SBrian Vazquez 	value_size = bpf_map_value_size(map);
1393aa2e93b8SBrian Vazquez 
1394aa2e93b8SBrian Vazquez 	max_count = attr->batch.count;
1395aa2e93b8SBrian Vazquez 	if (!max_count)
1396aa2e93b8SBrian Vazquez 		return 0;
1397aa2e93b8SBrian Vazquez 
13982e3a94aaSBrian Vazquez 	key = kmalloc(map->key_size, GFP_USER | __GFP_NOWARN);
13992e3a94aaSBrian Vazquez 	if (!key)
1400aa2e93b8SBrian Vazquez 		return -ENOMEM;
1401aa2e93b8SBrian Vazquez 
14022e3a94aaSBrian Vazquez 	value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
14032e3a94aaSBrian Vazquez 	if (!value) {
14042e3a94aaSBrian Vazquez 		kfree(key);
14052e3a94aaSBrian Vazquez 		return -ENOMEM;
1406aa2e93b8SBrian Vazquez 	}
14072e3a94aaSBrian Vazquez 
14082e3a94aaSBrian Vazquez 	for (cp = 0; cp < max_count; cp++) {
1409aa2e93b8SBrian Vazquez 		err = -EFAULT;
14102e3a94aaSBrian Vazquez 		if (copy_from_user(key, keys + cp * map->key_size,
14112e3a94aaSBrian Vazquez 		    map->key_size) ||
14122e3a94aaSBrian Vazquez 		    copy_from_user(value, values + cp * value_size, value_size))
1413aa2e93b8SBrian Vazquez 			break;
1414aa2e93b8SBrian Vazquez 
1415aa2e93b8SBrian Vazquez 		err = bpf_map_update_value(map, f, key, value,
1416aa2e93b8SBrian Vazquez 					   attr->batch.elem_flags);
1417aa2e93b8SBrian Vazquez 
1418aa2e93b8SBrian Vazquez 		if (err)
1419aa2e93b8SBrian Vazquez 			break;
1420aa2e93b8SBrian Vazquez 	}
1421aa2e93b8SBrian Vazquez 
1422aa2e93b8SBrian Vazquez 	if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp)))
1423aa2e93b8SBrian Vazquez 		err = -EFAULT;
1424aa2e93b8SBrian Vazquez 
1425aa2e93b8SBrian Vazquez 	kfree(value);
1426aa2e93b8SBrian Vazquez 	kfree(key);
1427aa2e93b8SBrian Vazquez 	return err;
1428aa2e93b8SBrian Vazquez }
1429aa2e93b8SBrian Vazquez 
1430cb4d03abSBrian Vazquez #define MAP_LOOKUP_RETRIES 3
1431cb4d03abSBrian Vazquez 
1432cb4d03abSBrian Vazquez int generic_map_lookup_batch(struct bpf_map *map,
1433cb4d03abSBrian Vazquez 				    const union bpf_attr *attr,
1434cb4d03abSBrian Vazquez 				    union bpf_attr __user *uattr)
1435cb4d03abSBrian Vazquez {
1436cb4d03abSBrian Vazquez 	void __user *uobatch = u64_to_user_ptr(attr->batch.out_batch);
1437cb4d03abSBrian Vazquez 	void __user *ubatch = u64_to_user_ptr(attr->batch.in_batch);
1438cb4d03abSBrian Vazquez 	void __user *values = u64_to_user_ptr(attr->batch.values);
1439cb4d03abSBrian Vazquez 	void __user *keys = u64_to_user_ptr(attr->batch.keys);
1440cb4d03abSBrian Vazquez 	void *buf, *buf_prevkey, *prev_key, *key, *value;
1441cb4d03abSBrian Vazquez 	int err, retry = MAP_LOOKUP_RETRIES;
1442cb4d03abSBrian Vazquez 	u32 value_size, cp, max_count;
1443cb4d03abSBrian Vazquez 
1444cb4d03abSBrian Vazquez 	if (attr->batch.elem_flags & ~BPF_F_LOCK)
1445cb4d03abSBrian Vazquez 		return -EINVAL;
1446cb4d03abSBrian Vazquez 
1447cb4d03abSBrian Vazquez 	if ((attr->batch.elem_flags & BPF_F_LOCK) &&
1448cb4d03abSBrian Vazquez 	    !map_value_has_spin_lock(map))
1449cb4d03abSBrian Vazquez 		return -EINVAL;
1450cb4d03abSBrian Vazquez 
1451cb4d03abSBrian Vazquez 	value_size = bpf_map_value_size(map);
1452cb4d03abSBrian Vazquez 
1453cb4d03abSBrian Vazquez 	max_count = attr->batch.count;
1454cb4d03abSBrian Vazquez 	if (!max_count)
1455cb4d03abSBrian Vazquez 		return 0;
1456cb4d03abSBrian Vazquez 
1457cb4d03abSBrian Vazquez 	if (put_user(0, &uattr->batch.count))
1458cb4d03abSBrian Vazquez 		return -EFAULT;
1459cb4d03abSBrian Vazquez 
1460cb4d03abSBrian Vazquez 	buf_prevkey = kmalloc(map->key_size, GFP_USER | __GFP_NOWARN);
1461cb4d03abSBrian Vazquez 	if (!buf_prevkey)
1462cb4d03abSBrian Vazquez 		return -ENOMEM;
1463cb4d03abSBrian Vazquez 
1464cb4d03abSBrian Vazquez 	buf = kmalloc(map->key_size + value_size, GFP_USER | __GFP_NOWARN);
1465cb4d03abSBrian Vazquez 	if (!buf) {
1466bb2359f4SDenis Efremov 		kfree(buf_prevkey);
1467cb4d03abSBrian Vazquez 		return -ENOMEM;
1468cb4d03abSBrian Vazquez 	}
1469cb4d03abSBrian Vazquez 
1470cb4d03abSBrian Vazquez 	err = -EFAULT;
1471cb4d03abSBrian Vazquez 	prev_key = NULL;
1472cb4d03abSBrian Vazquez 	if (ubatch && copy_from_user(buf_prevkey, ubatch, map->key_size))
1473cb4d03abSBrian Vazquez 		goto free_buf;
1474cb4d03abSBrian Vazquez 	key = buf;
1475cb4d03abSBrian Vazquez 	value = key + map->key_size;
1476cb4d03abSBrian Vazquez 	if (ubatch)
1477cb4d03abSBrian Vazquez 		prev_key = buf_prevkey;
1478cb4d03abSBrian Vazquez 
1479cb4d03abSBrian Vazquez 	for (cp = 0; cp < max_count;) {
1480cb4d03abSBrian Vazquez 		rcu_read_lock();
1481cb4d03abSBrian Vazquez 		err = map->ops->map_get_next_key(map, prev_key, key);
1482cb4d03abSBrian Vazquez 		rcu_read_unlock();
1483cb4d03abSBrian Vazquez 		if (err)
1484cb4d03abSBrian Vazquez 			break;
1485cb4d03abSBrian Vazquez 		err = bpf_map_copy_value(map, key, value,
1486cb4d03abSBrian Vazquez 					 attr->batch.elem_flags);
1487cb4d03abSBrian Vazquez 
1488cb4d03abSBrian Vazquez 		if (err == -ENOENT) {
1489cb4d03abSBrian Vazquez 			if (retry) {
1490cb4d03abSBrian Vazquez 				retry--;
1491cb4d03abSBrian Vazquez 				continue;
1492cb4d03abSBrian Vazquez 			}
1493cb4d03abSBrian Vazquez 			err = -EINTR;
1494cb4d03abSBrian Vazquez 			break;
1495cb4d03abSBrian Vazquez 		}
1496cb4d03abSBrian Vazquez 
1497cb4d03abSBrian Vazquez 		if (err)
1498cb4d03abSBrian Vazquez 			goto free_buf;
1499cb4d03abSBrian Vazquez 
1500cb4d03abSBrian Vazquez 		if (copy_to_user(keys + cp * map->key_size, key,
1501cb4d03abSBrian Vazquez 				 map->key_size)) {
1502cb4d03abSBrian Vazquez 			err = -EFAULT;
1503cb4d03abSBrian Vazquez 			goto free_buf;
1504cb4d03abSBrian Vazquez 		}
1505cb4d03abSBrian Vazquez 		if (copy_to_user(values + cp * value_size, value, value_size)) {
1506cb4d03abSBrian Vazquez 			err = -EFAULT;
1507cb4d03abSBrian Vazquez 			goto free_buf;
1508cb4d03abSBrian Vazquez 		}
1509cb4d03abSBrian Vazquez 
1510cb4d03abSBrian Vazquez 		if (!prev_key)
1511cb4d03abSBrian Vazquez 			prev_key = buf_prevkey;
1512cb4d03abSBrian Vazquez 
1513cb4d03abSBrian Vazquez 		swap(prev_key, key);
1514cb4d03abSBrian Vazquez 		retry = MAP_LOOKUP_RETRIES;
1515cb4d03abSBrian Vazquez 		cp++;
1516cb4d03abSBrian Vazquez 	}
1517cb4d03abSBrian Vazquez 
1518cb4d03abSBrian Vazquez 	if (err == -EFAULT)
1519cb4d03abSBrian Vazquez 		goto free_buf;
1520cb4d03abSBrian Vazquez 
1521cb4d03abSBrian Vazquez 	if ((copy_to_user(&uattr->batch.count, &cp, sizeof(cp)) ||
1522cb4d03abSBrian Vazquez 		    (cp && copy_to_user(uobatch, prev_key, map->key_size))))
1523cb4d03abSBrian Vazquez 		err = -EFAULT;
1524cb4d03abSBrian Vazquez 
1525cb4d03abSBrian Vazquez free_buf:
1526cb4d03abSBrian Vazquez 	kfree(buf_prevkey);
1527cb4d03abSBrian Vazquez 	kfree(buf);
1528cb4d03abSBrian Vazquez 	return err;
1529cb4d03abSBrian Vazquez }
1530cb4d03abSBrian Vazquez 
1531bd513cd0SMauricio Vasquez B #define BPF_MAP_LOOKUP_AND_DELETE_ELEM_LAST_FIELD value
1532bd513cd0SMauricio Vasquez B 
1533bd513cd0SMauricio Vasquez B static int map_lookup_and_delete_elem(union bpf_attr *attr)
1534bd513cd0SMauricio Vasquez B {
1535bd513cd0SMauricio Vasquez B 	void __user *ukey = u64_to_user_ptr(attr->key);
1536bd513cd0SMauricio Vasquez B 	void __user *uvalue = u64_to_user_ptr(attr->value);
1537bd513cd0SMauricio Vasquez B 	int ufd = attr->map_fd;
1538bd513cd0SMauricio Vasquez B 	struct bpf_map *map;
1539540fefc0SAlexei Starovoitov 	void *key, *value;
1540bd513cd0SMauricio Vasquez B 	u32 value_size;
1541bd513cd0SMauricio Vasquez B 	struct fd f;
1542bd513cd0SMauricio Vasquez B 	int err;
1543bd513cd0SMauricio Vasquez B 
1544bd513cd0SMauricio Vasquez B 	if (CHECK_ATTR(BPF_MAP_LOOKUP_AND_DELETE_ELEM))
1545bd513cd0SMauricio Vasquez B 		return -EINVAL;
1546bd513cd0SMauricio Vasquez B 
1547bd513cd0SMauricio Vasquez B 	f = fdget(ufd);
1548bd513cd0SMauricio Vasquez B 	map = __bpf_map_get(f);
1549bd513cd0SMauricio Vasquez B 	if (IS_ERR(map))
1550bd513cd0SMauricio Vasquez B 		return PTR_ERR(map);
15511ea0f912SAnton Protopopov 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ) ||
15521ea0f912SAnton Protopopov 	    !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
1553bd513cd0SMauricio Vasquez B 		err = -EPERM;
1554bd513cd0SMauricio Vasquez B 		goto err_put;
1555bd513cd0SMauricio Vasquez B 	}
1556bd513cd0SMauricio Vasquez B 
1557bd513cd0SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
1558bd513cd0SMauricio Vasquez B 	if (IS_ERR(key)) {
1559bd513cd0SMauricio Vasquez B 		err = PTR_ERR(key);
1560bd513cd0SMauricio Vasquez B 		goto err_put;
1561bd513cd0SMauricio Vasquez B 	}
1562bd513cd0SMauricio Vasquez B 
1563bd513cd0SMauricio Vasquez B 	value_size = map->value_size;
1564bd513cd0SMauricio Vasquez B 
1565bd513cd0SMauricio Vasquez B 	err = -ENOMEM;
1566bd513cd0SMauricio Vasquez B 	value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
1567bd513cd0SMauricio Vasquez B 	if (!value)
1568bd513cd0SMauricio Vasquez B 		goto free_key;
1569bd513cd0SMauricio Vasquez B 
1570bd513cd0SMauricio Vasquez B 	if (map->map_type == BPF_MAP_TYPE_QUEUE ||
1571bd513cd0SMauricio Vasquez B 	    map->map_type == BPF_MAP_TYPE_STACK) {
1572bd513cd0SMauricio Vasquez B 		err = map->ops->map_pop_elem(map, value);
1573bd513cd0SMauricio Vasquez B 	} else {
1574bd513cd0SMauricio Vasquez B 		err = -ENOTSUPP;
1575bd513cd0SMauricio Vasquez B 	}
1576bd513cd0SMauricio Vasquez B 
1577bd513cd0SMauricio Vasquez B 	if (err)
1578bd513cd0SMauricio Vasquez B 		goto free_value;
1579bd513cd0SMauricio Vasquez B 
15807f645462SWei Yongjun 	if (copy_to_user(uvalue, value, value_size) != 0) {
15817f645462SWei Yongjun 		err = -EFAULT;
1582bd513cd0SMauricio Vasquez B 		goto free_value;
15837f645462SWei Yongjun 	}
1584bd513cd0SMauricio Vasquez B 
1585bd513cd0SMauricio Vasquez B 	err = 0;
1586bd513cd0SMauricio Vasquez B 
1587bd513cd0SMauricio Vasquez B free_value:
1588bd513cd0SMauricio Vasquez B 	kfree(value);
1589bd513cd0SMauricio Vasquez B free_key:
1590bd513cd0SMauricio Vasquez B 	kfree(key);
1591bd513cd0SMauricio Vasquez B err_put:
1592bd513cd0SMauricio Vasquez B 	fdput(f);
1593bd513cd0SMauricio Vasquez B 	return err;
1594bd513cd0SMauricio Vasquez B }
1595bd513cd0SMauricio Vasquez B 
159687df15deSDaniel Borkmann #define BPF_MAP_FREEZE_LAST_FIELD map_fd
159787df15deSDaniel Borkmann 
159887df15deSDaniel Borkmann static int map_freeze(const union bpf_attr *attr)
159987df15deSDaniel Borkmann {
160087df15deSDaniel Borkmann 	int err = 0, ufd = attr->map_fd;
160187df15deSDaniel Borkmann 	struct bpf_map *map;
160287df15deSDaniel Borkmann 	struct fd f;
160387df15deSDaniel Borkmann 
160487df15deSDaniel Borkmann 	if (CHECK_ATTR(BPF_MAP_FREEZE))
160587df15deSDaniel Borkmann 		return -EINVAL;
160687df15deSDaniel Borkmann 
160787df15deSDaniel Borkmann 	f = fdget(ufd);
160887df15deSDaniel Borkmann 	map = __bpf_map_get(f);
160987df15deSDaniel Borkmann 	if (IS_ERR(map))
161087df15deSDaniel Borkmann 		return PTR_ERR(map);
1611fc970227SAndrii Nakryiko 
1612849b4d94SMartin KaFai Lau 	if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
1613849b4d94SMartin KaFai Lau 		fdput(f);
1614849b4d94SMartin KaFai Lau 		return -ENOTSUPP;
1615849b4d94SMartin KaFai Lau 	}
1616849b4d94SMartin KaFai Lau 
1617fc970227SAndrii Nakryiko 	mutex_lock(&map->freeze_mutex);
1618fc970227SAndrii Nakryiko 
1619fc970227SAndrii Nakryiko 	if (map->writecnt) {
1620fc970227SAndrii Nakryiko 		err = -EBUSY;
1621fc970227SAndrii Nakryiko 		goto err_put;
1622fc970227SAndrii Nakryiko 	}
162387df15deSDaniel Borkmann 	if (READ_ONCE(map->frozen)) {
162487df15deSDaniel Borkmann 		err = -EBUSY;
162587df15deSDaniel Borkmann 		goto err_put;
162687df15deSDaniel Borkmann 	}
16272c78ee89SAlexei Starovoitov 	if (!bpf_capable()) {
162887df15deSDaniel Borkmann 		err = -EPERM;
162987df15deSDaniel Borkmann 		goto err_put;
163087df15deSDaniel Borkmann 	}
163187df15deSDaniel Borkmann 
163287df15deSDaniel Borkmann 	WRITE_ONCE(map->frozen, true);
163387df15deSDaniel Borkmann err_put:
1634fc970227SAndrii Nakryiko 	mutex_unlock(&map->freeze_mutex);
163587df15deSDaniel Borkmann 	fdput(f);
163687df15deSDaniel Borkmann 	return err;
163787df15deSDaniel Borkmann }
163887df15deSDaniel Borkmann 
16397de16e3aSJakub Kicinski static const struct bpf_prog_ops * const bpf_prog_types[] = {
164091cc1a99SAlexei Starovoitov #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \
16417de16e3aSJakub Kicinski 	[_id] = & _name ## _prog_ops,
16427de16e3aSJakub Kicinski #define BPF_MAP_TYPE(_id, _ops)
1643f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name)
16447de16e3aSJakub Kicinski #include <linux/bpf_types.h>
16457de16e3aSJakub Kicinski #undef BPF_PROG_TYPE
16467de16e3aSJakub Kicinski #undef BPF_MAP_TYPE
1647f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE
16487de16e3aSJakub Kicinski };
16497de16e3aSJakub Kicinski 
165009756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
165109756af4SAlexei Starovoitov {
1652d0f1a451SDaniel Borkmann 	const struct bpf_prog_ops *ops;
1653d0f1a451SDaniel Borkmann 
1654d0f1a451SDaniel Borkmann 	if (type >= ARRAY_SIZE(bpf_prog_types))
1655d0f1a451SDaniel Borkmann 		return -EINVAL;
1656d0f1a451SDaniel Borkmann 	type = array_index_nospec(type, ARRAY_SIZE(bpf_prog_types));
1657d0f1a451SDaniel Borkmann 	ops = bpf_prog_types[type];
1658d0f1a451SDaniel Borkmann 	if (!ops)
1659be9370a7SJohannes Berg 		return -EINVAL;
166009756af4SAlexei Starovoitov 
1661ab3f0063SJakub Kicinski 	if (!bpf_prog_is_dev_bound(prog->aux))
1662d0f1a451SDaniel Borkmann 		prog->aux->ops = ops;
1663ab3f0063SJakub Kicinski 	else
1664ab3f0063SJakub Kicinski 		prog->aux->ops = &bpf_offload_prog_ops;
166524701eceSDaniel Borkmann 	prog->type = type;
166609756af4SAlexei Starovoitov 	return 0;
166709756af4SAlexei Starovoitov }
166809756af4SAlexei Starovoitov 
1669bae141f5SDaniel Borkmann enum bpf_audit {
1670bae141f5SDaniel Borkmann 	BPF_AUDIT_LOAD,
1671bae141f5SDaniel Borkmann 	BPF_AUDIT_UNLOAD,
1672bae141f5SDaniel Borkmann 	BPF_AUDIT_MAX,
1673bae141f5SDaniel Borkmann };
1674bae141f5SDaniel Borkmann 
1675bae141f5SDaniel Borkmann static const char * const bpf_audit_str[BPF_AUDIT_MAX] = {
1676bae141f5SDaniel Borkmann 	[BPF_AUDIT_LOAD]   = "LOAD",
1677bae141f5SDaniel Borkmann 	[BPF_AUDIT_UNLOAD] = "UNLOAD",
1678bae141f5SDaniel Borkmann };
1679bae141f5SDaniel Borkmann 
1680bae141f5SDaniel Borkmann static void bpf_audit_prog(const struct bpf_prog *prog, unsigned int op)
1681bae141f5SDaniel Borkmann {
1682bae141f5SDaniel Borkmann 	struct audit_context *ctx = NULL;
1683bae141f5SDaniel Borkmann 	struct audit_buffer *ab;
1684bae141f5SDaniel Borkmann 
1685bae141f5SDaniel Borkmann 	if (WARN_ON_ONCE(op >= BPF_AUDIT_MAX))
1686bae141f5SDaniel Borkmann 		return;
1687bae141f5SDaniel Borkmann 	if (audit_enabled == AUDIT_OFF)
1688bae141f5SDaniel Borkmann 		return;
1689bae141f5SDaniel Borkmann 	if (op == BPF_AUDIT_LOAD)
1690bae141f5SDaniel Borkmann 		ctx = audit_context();
1691bae141f5SDaniel Borkmann 	ab = audit_log_start(ctx, GFP_ATOMIC, AUDIT_BPF);
1692bae141f5SDaniel Borkmann 	if (unlikely(!ab))
1693bae141f5SDaniel Borkmann 		return;
1694bae141f5SDaniel Borkmann 	audit_log_format(ab, "prog-id=%u op=%s",
1695bae141f5SDaniel Borkmann 			 prog->aux->id, bpf_audit_str[op]);
1696bae141f5SDaniel Borkmann 	audit_log_end(ab);
1697bae141f5SDaniel Borkmann }
1698bae141f5SDaniel Borkmann 
16995ccb071eSDaniel Borkmann int __bpf_prog_charge(struct user_struct *user, u32 pages)
17005ccb071eSDaniel Borkmann {
17015ccb071eSDaniel Borkmann 	unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
17025ccb071eSDaniel Borkmann 	unsigned long user_bufs;
17035ccb071eSDaniel Borkmann 
17045ccb071eSDaniel Borkmann 	if (user) {
17055ccb071eSDaniel Borkmann 		user_bufs = atomic_long_add_return(pages, &user->locked_vm);
17065ccb071eSDaniel Borkmann 		if (user_bufs > memlock_limit) {
17075ccb071eSDaniel Borkmann 			atomic_long_sub(pages, &user->locked_vm);
17085ccb071eSDaniel Borkmann 			return -EPERM;
17095ccb071eSDaniel Borkmann 		}
17105ccb071eSDaniel Borkmann 	}
17115ccb071eSDaniel Borkmann 
17125ccb071eSDaniel Borkmann 	return 0;
17135ccb071eSDaniel Borkmann }
17145ccb071eSDaniel Borkmann 
17155ccb071eSDaniel Borkmann void __bpf_prog_uncharge(struct user_struct *user, u32 pages)
17165ccb071eSDaniel Borkmann {
17175ccb071eSDaniel Borkmann 	if (user)
17185ccb071eSDaniel Borkmann 		atomic_long_sub(pages, &user->locked_vm);
17195ccb071eSDaniel Borkmann }
17205ccb071eSDaniel Borkmann 
1721aaac3ba9SAlexei Starovoitov static int bpf_prog_charge_memlock(struct bpf_prog *prog)
1722aaac3ba9SAlexei Starovoitov {
1723aaac3ba9SAlexei Starovoitov 	struct user_struct *user = get_current_user();
17245ccb071eSDaniel Borkmann 	int ret;
1725aaac3ba9SAlexei Starovoitov 
17265ccb071eSDaniel Borkmann 	ret = __bpf_prog_charge(user, prog->pages);
17275ccb071eSDaniel Borkmann 	if (ret) {
1728aaac3ba9SAlexei Starovoitov 		free_uid(user);
17295ccb071eSDaniel Borkmann 		return ret;
1730aaac3ba9SAlexei Starovoitov 	}
17315ccb071eSDaniel Borkmann 
1732aaac3ba9SAlexei Starovoitov 	prog->aux->user = user;
1733aaac3ba9SAlexei Starovoitov 	return 0;
1734aaac3ba9SAlexei Starovoitov }
1735aaac3ba9SAlexei Starovoitov 
1736aaac3ba9SAlexei Starovoitov static void bpf_prog_uncharge_memlock(struct bpf_prog *prog)
1737aaac3ba9SAlexei Starovoitov {
1738aaac3ba9SAlexei Starovoitov 	struct user_struct *user = prog->aux->user;
1739aaac3ba9SAlexei Starovoitov 
17405ccb071eSDaniel Borkmann 	__bpf_prog_uncharge(user, prog->pages);
1741aaac3ba9SAlexei Starovoitov 	free_uid(user);
1742aaac3ba9SAlexei Starovoitov }
1743aaac3ba9SAlexei Starovoitov 
1744dc4bb0e2SMartin KaFai Lau static int bpf_prog_alloc_id(struct bpf_prog *prog)
1745dc4bb0e2SMartin KaFai Lau {
1746dc4bb0e2SMartin KaFai Lau 	int id;
1747dc4bb0e2SMartin KaFai Lau 
1748b76354cdSShaohua Li 	idr_preload(GFP_KERNEL);
1749dc4bb0e2SMartin KaFai Lau 	spin_lock_bh(&prog_idr_lock);
1750dc4bb0e2SMartin KaFai Lau 	id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC);
1751dc4bb0e2SMartin KaFai Lau 	if (id > 0)
1752dc4bb0e2SMartin KaFai Lau 		prog->aux->id = id;
1753dc4bb0e2SMartin KaFai Lau 	spin_unlock_bh(&prog_idr_lock);
1754b76354cdSShaohua Li 	idr_preload_end();
1755dc4bb0e2SMartin KaFai Lau 
1756dc4bb0e2SMartin KaFai Lau 	/* id is in [1, INT_MAX) */
1757dc4bb0e2SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
1758dc4bb0e2SMartin KaFai Lau 		return -ENOSPC;
1759dc4bb0e2SMartin KaFai Lau 
1760dc4bb0e2SMartin KaFai Lau 	return id > 0 ? 0 : id;
1761dc4bb0e2SMartin KaFai Lau }
1762dc4bb0e2SMartin KaFai Lau 
1763ad8ad79fSJakub Kicinski void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
1764dc4bb0e2SMartin KaFai Lau {
1765ad8ad79fSJakub Kicinski 	/* cBPF to eBPF migrations are currently not in the idr store.
1766ad8ad79fSJakub Kicinski 	 * Offloaded programs are removed from the store when their device
1767ad8ad79fSJakub Kicinski 	 * disappears - even if someone grabs an fd to them they are unusable,
1768ad8ad79fSJakub Kicinski 	 * simply waiting for refcnt to drop to be freed.
1769ad8ad79fSJakub Kicinski 	 */
1770dc4bb0e2SMartin KaFai Lau 	if (!prog->aux->id)
1771dc4bb0e2SMartin KaFai Lau 		return;
1772dc4bb0e2SMartin KaFai Lau 
1773b16d9aa4SMartin KaFai Lau 	if (do_idr_lock)
1774dc4bb0e2SMartin KaFai Lau 		spin_lock_bh(&prog_idr_lock);
1775b16d9aa4SMartin KaFai Lau 	else
1776b16d9aa4SMartin KaFai Lau 		__acquire(&prog_idr_lock);
1777b16d9aa4SMartin KaFai Lau 
1778dc4bb0e2SMartin KaFai Lau 	idr_remove(&prog_idr, prog->aux->id);
1779ad8ad79fSJakub Kicinski 	prog->aux->id = 0;
1780b16d9aa4SMartin KaFai Lau 
1781b16d9aa4SMartin KaFai Lau 	if (do_idr_lock)
1782dc4bb0e2SMartin KaFai Lau 		spin_unlock_bh(&prog_idr_lock);
1783b16d9aa4SMartin KaFai Lau 	else
1784b16d9aa4SMartin KaFai Lau 		__release(&prog_idr_lock);
1785dc4bb0e2SMartin KaFai Lau }
1786dc4bb0e2SMartin KaFai Lau 
17871aacde3dSDaniel Borkmann static void __bpf_prog_put_rcu(struct rcu_head *rcu)
1788abf2e7d6SAlexei Starovoitov {
1789abf2e7d6SAlexei Starovoitov 	struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
1790abf2e7d6SAlexei Starovoitov 
17913b4d9eb2SDaniel Borkmann 	kvfree(aux->func_info);
17928c1b6e69SAlexei Starovoitov 	kfree(aux->func_info_aux);
1793aaac3ba9SAlexei Starovoitov 	bpf_prog_uncharge_memlock(aux->prog);
1794afdb09c7SChenbo Feng 	security_bpf_prog_free(aux);
1795abf2e7d6SAlexei Starovoitov 	bpf_prog_free(aux->prog);
1796abf2e7d6SAlexei Starovoitov }
1797abf2e7d6SAlexei Starovoitov 
1798cd7455f1SDaniel Borkmann static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
1799cd7455f1SDaniel Borkmann {
1800cd7455f1SDaniel Borkmann 	bpf_prog_kallsyms_del_all(prog);
1801cd7455f1SDaniel Borkmann 	btf_put(prog->aux->btf);
1802cd7455f1SDaniel Borkmann 	bpf_prog_free_linfo(prog);
1803cd7455f1SDaniel Borkmann 
18041e6c62a8SAlexei Starovoitov 	if (deferred) {
18051e6c62a8SAlexei Starovoitov 		if (prog->aux->sleepable)
18061e6c62a8SAlexei Starovoitov 			call_rcu_tasks_trace(&prog->aux->rcu, __bpf_prog_put_rcu);
1807cd7455f1SDaniel Borkmann 		else
18081e6c62a8SAlexei Starovoitov 			call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
18091e6c62a8SAlexei Starovoitov 	} else {
1810cd7455f1SDaniel Borkmann 		__bpf_prog_put_rcu(&prog->aux->rcu);
1811cd7455f1SDaniel Borkmann 	}
18121e6c62a8SAlexei Starovoitov }
1813cd7455f1SDaniel Borkmann 
1814b16d9aa4SMartin KaFai Lau static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock)
181509756af4SAlexei Starovoitov {
181685192dbfSAndrii Nakryiko 	if (atomic64_dec_and_test(&prog->aux->refcnt)) {
18176ee52e2aSSong Liu 		perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0);
1818bae141f5SDaniel Borkmann 		bpf_audit_prog(prog, BPF_AUDIT_UNLOAD);
181934ad5580SMartin KaFai Lau 		/* bpf_prog_free_id() must be called first */
1820b16d9aa4SMartin KaFai Lau 		bpf_prog_free_id(prog, do_idr_lock);
1821cd7455f1SDaniel Borkmann 		__bpf_prog_put_noref(prog, true);
182209756af4SAlexei Starovoitov 	}
1823a67edbf4SDaniel Borkmann }
1824b16d9aa4SMartin KaFai Lau 
1825b16d9aa4SMartin KaFai Lau void bpf_prog_put(struct bpf_prog *prog)
1826b16d9aa4SMartin KaFai Lau {
1827b16d9aa4SMartin KaFai Lau 	__bpf_prog_put(prog, true);
1828b16d9aa4SMartin KaFai Lau }
1829e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put);
183009756af4SAlexei Starovoitov 
183109756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp)
183209756af4SAlexei Starovoitov {
183309756af4SAlexei Starovoitov 	struct bpf_prog *prog = filp->private_data;
183409756af4SAlexei Starovoitov 
18351aacde3dSDaniel Borkmann 	bpf_prog_put(prog);
183609756af4SAlexei Starovoitov 	return 0;
183709756af4SAlexei Starovoitov }
183809756af4SAlexei Starovoitov 
1839492ecee8SAlexei Starovoitov static void bpf_prog_get_stats(const struct bpf_prog *prog,
1840492ecee8SAlexei Starovoitov 			       struct bpf_prog_stats *stats)
1841492ecee8SAlexei Starovoitov {
1842492ecee8SAlexei Starovoitov 	u64 nsecs = 0, cnt = 0;
1843492ecee8SAlexei Starovoitov 	int cpu;
1844492ecee8SAlexei Starovoitov 
1845492ecee8SAlexei Starovoitov 	for_each_possible_cpu(cpu) {
1846492ecee8SAlexei Starovoitov 		const struct bpf_prog_stats *st;
1847492ecee8SAlexei Starovoitov 		unsigned int start;
1848492ecee8SAlexei Starovoitov 		u64 tnsecs, tcnt;
1849492ecee8SAlexei Starovoitov 
1850492ecee8SAlexei Starovoitov 		st = per_cpu_ptr(prog->aux->stats, cpu);
1851492ecee8SAlexei Starovoitov 		do {
1852492ecee8SAlexei Starovoitov 			start = u64_stats_fetch_begin_irq(&st->syncp);
1853492ecee8SAlexei Starovoitov 			tnsecs = st->nsecs;
1854492ecee8SAlexei Starovoitov 			tcnt = st->cnt;
1855492ecee8SAlexei Starovoitov 		} while (u64_stats_fetch_retry_irq(&st->syncp, start));
1856492ecee8SAlexei Starovoitov 		nsecs += tnsecs;
1857492ecee8SAlexei Starovoitov 		cnt += tcnt;
1858492ecee8SAlexei Starovoitov 	}
1859492ecee8SAlexei Starovoitov 	stats->nsecs = nsecs;
1860492ecee8SAlexei Starovoitov 	stats->cnt = cnt;
1861492ecee8SAlexei Starovoitov }
1862492ecee8SAlexei Starovoitov 
18637bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
18647bd509e3SDaniel Borkmann static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp)
18657bd509e3SDaniel Borkmann {
18667bd509e3SDaniel Borkmann 	const struct bpf_prog *prog = filp->private_data;
1867f1f7714eSDaniel Borkmann 	char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
1868492ecee8SAlexei Starovoitov 	struct bpf_prog_stats stats;
18697bd509e3SDaniel Borkmann 
1870492ecee8SAlexei Starovoitov 	bpf_prog_get_stats(prog, &stats);
1871f1f7714eSDaniel Borkmann 	bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
18727bd509e3SDaniel Borkmann 	seq_printf(m,
18737bd509e3SDaniel Borkmann 		   "prog_type:\t%u\n"
18747bd509e3SDaniel Borkmann 		   "prog_jited:\t%u\n"
1875f1f7714eSDaniel Borkmann 		   "prog_tag:\t%s\n"
18764316b409SDaniel Borkmann 		   "memlock:\t%llu\n"
1877492ecee8SAlexei Starovoitov 		   "prog_id:\t%u\n"
1878492ecee8SAlexei Starovoitov 		   "run_time_ns:\t%llu\n"
1879492ecee8SAlexei Starovoitov 		   "run_cnt:\t%llu\n",
18807bd509e3SDaniel Borkmann 		   prog->type,
18817bd509e3SDaniel Borkmann 		   prog->jited,
1882f1f7714eSDaniel Borkmann 		   prog_tag,
18834316b409SDaniel Borkmann 		   prog->pages * 1ULL << PAGE_SHIFT,
1884492ecee8SAlexei Starovoitov 		   prog->aux->id,
1885492ecee8SAlexei Starovoitov 		   stats.nsecs,
1886492ecee8SAlexei Starovoitov 		   stats.cnt);
18877bd509e3SDaniel Borkmann }
18887bd509e3SDaniel Borkmann #endif
18897bd509e3SDaniel Borkmann 
1890f66e448cSChenbo Feng const struct file_operations bpf_prog_fops = {
18917bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
18927bd509e3SDaniel Borkmann 	.show_fdinfo	= bpf_prog_show_fdinfo,
18937bd509e3SDaniel Borkmann #endif
189409756af4SAlexei Starovoitov 	.release	= bpf_prog_release,
18956e71b04aSChenbo Feng 	.read		= bpf_dummy_read,
18966e71b04aSChenbo Feng 	.write		= bpf_dummy_write,
189709756af4SAlexei Starovoitov };
189809756af4SAlexei Starovoitov 
1899b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog)
1900aa79781bSDaniel Borkmann {
1901afdb09c7SChenbo Feng 	int ret;
1902afdb09c7SChenbo Feng 
1903afdb09c7SChenbo Feng 	ret = security_bpf_prog(prog);
1904afdb09c7SChenbo Feng 	if (ret < 0)
1905afdb09c7SChenbo Feng 		return ret;
1906afdb09c7SChenbo Feng 
1907aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog,
1908aa79781bSDaniel Borkmann 				O_RDWR | O_CLOEXEC);
1909aa79781bSDaniel Borkmann }
1910aa79781bSDaniel Borkmann 
1911113214beSDaniel Borkmann static struct bpf_prog *____bpf_prog_get(struct fd f)
191209756af4SAlexei Starovoitov {
191309756af4SAlexei Starovoitov 	if (!f.file)
191409756af4SAlexei Starovoitov 		return ERR_PTR(-EBADF);
191509756af4SAlexei Starovoitov 	if (f.file->f_op != &bpf_prog_fops) {
191609756af4SAlexei Starovoitov 		fdput(f);
191709756af4SAlexei Starovoitov 		return ERR_PTR(-EINVAL);
191809756af4SAlexei Starovoitov 	}
191909756af4SAlexei Starovoitov 
1920c2101297SDaniel Borkmann 	return f.file->private_data;
192109756af4SAlexei Starovoitov }
192209756af4SAlexei Starovoitov 
192385192dbfSAndrii Nakryiko void bpf_prog_add(struct bpf_prog *prog, int i)
192492117d84SAlexei Starovoitov {
192585192dbfSAndrii Nakryiko 	atomic64_add(i, &prog->aux->refcnt);
192692117d84SAlexei Starovoitov }
192759d3656dSBrenden Blanco EXPORT_SYMBOL_GPL(bpf_prog_add);
192859d3656dSBrenden Blanco 
1929c540594fSDaniel Borkmann void bpf_prog_sub(struct bpf_prog *prog, int i)
1930c540594fSDaniel Borkmann {
1931c540594fSDaniel Borkmann 	/* Only to be used for undoing previous bpf_prog_add() in some
1932c540594fSDaniel Borkmann 	 * error path. We still know that another entity in our call
1933c540594fSDaniel Borkmann 	 * path holds a reference to the program, thus atomic_sub() can
1934c540594fSDaniel Borkmann 	 * be safely used in such cases!
1935c540594fSDaniel Borkmann 	 */
193685192dbfSAndrii Nakryiko 	WARN_ON(atomic64_sub_return(i, &prog->aux->refcnt) == 0);
1937c540594fSDaniel Borkmann }
1938c540594fSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_sub);
1939c540594fSDaniel Borkmann 
194085192dbfSAndrii Nakryiko void bpf_prog_inc(struct bpf_prog *prog)
194159d3656dSBrenden Blanco {
194285192dbfSAndrii Nakryiko 	atomic64_inc(&prog->aux->refcnt);
194359d3656dSBrenden Blanco }
194497bc402dSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_inc);
194592117d84SAlexei Starovoitov 
1946b16d9aa4SMartin KaFai Lau /* prog_idr_lock should have been held */
1947a6f6df69SJohn Fastabend struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog)
1948b16d9aa4SMartin KaFai Lau {
1949b16d9aa4SMartin KaFai Lau 	int refold;
1950b16d9aa4SMartin KaFai Lau 
195185192dbfSAndrii Nakryiko 	refold = atomic64_fetch_add_unless(&prog->aux->refcnt, 1, 0);
1952b16d9aa4SMartin KaFai Lau 
1953b16d9aa4SMartin KaFai Lau 	if (!refold)
1954b16d9aa4SMartin KaFai Lau 		return ERR_PTR(-ENOENT);
1955b16d9aa4SMartin KaFai Lau 
1956b16d9aa4SMartin KaFai Lau 	return prog;
1957b16d9aa4SMartin KaFai Lau }
1958a6f6df69SJohn Fastabend EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero);
1959b16d9aa4SMartin KaFai Lau 
1960040ee692SAl Viro bool bpf_prog_get_ok(struct bpf_prog *prog,
1961288b3de5SJakub Kicinski 			    enum bpf_prog_type *attach_type, bool attach_drv)
1962248f346fSJakub Kicinski {
1963288b3de5SJakub Kicinski 	/* not an attachment, just a refcount inc, always allow */
1964288b3de5SJakub Kicinski 	if (!attach_type)
1965288b3de5SJakub Kicinski 		return true;
1966248f346fSJakub Kicinski 
1967248f346fSJakub Kicinski 	if (prog->type != *attach_type)
1968248f346fSJakub Kicinski 		return false;
1969288b3de5SJakub Kicinski 	if (bpf_prog_is_dev_bound(prog->aux) && !attach_drv)
1970248f346fSJakub Kicinski 		return false;
1971248f346fSJakub Kicinski 
1972248f346fSJakub Kicinski 	return true;
1973248f346fSJakub Kicinski }
1974248f346fSJakub Kicinski 
1975248f346fSJakub Kicinski static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type,
1976288b3de5SJakub Kicinski 				       bool attach_drv)
197709756af4SAlexei Starovoitov {
197809756af4SAlexei Starovoitov 	struct fd f = fdget(ufd);
197909756af4SAlexei Starovoitov 	struct bpf_prog *prog;
198009756af4SAlexei Starovoitov 
1981113214beSDaniel Borkmann 	prog = ____bpf_prog_get(f);
198209756af4SAlexei Starovoitov 	if (IS_ERR(prog))
198309756af4SAlexei Starovoitov 		return prog;
1984288b3de5SJakub Kicinski 	if (!bpf_prog_get_ok(prog, attach_type, attach_drv)) {
1985113214beSDaniel Borkmann 		prog = ERR_PTR(-EINVAL);
1986113214beSDaniel Borkmann 		goto out;
1987113214beSDaniel Borkmann 	}
198809756af4SAlexei Starovoitov 
198985192dbfSAndrii Nakryiko 	bpf_prog_inc(prog);
1990113214beSDaniel Borkmann out:
199109756af4SAlexei Starovoitov 	fdput(f);
199209756af4SAlexei Starovoitov 	return prog;
199309756af4SAlexei Starovoitov }
1994113214beSDaniel Borkmann 
1995113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get(u32 ufd)
1996113214beSDaniel Borkmann {
1997288b3de5SJakub Kicinski 	return __bpf_prog_get(ufd, NULL, false);
1998113214beSDaniel Borkmann }
1999113214beSDaniel Borkmann 
2000248f346fSJakub Kicinski struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type,
2001288b3de5SJakub Kicinski 				       bool attach_drv)
2002248f346fSJakub Kicinski {
20034d220ed0SAlexei Starovoitov 	return __bpf_prog_get(ufd, &type, attach_drv);
2004248f346fSJakub Kicinski }
20056c8dfe21SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_prog_get_type_dev);
2006248f346fSJakub Kicinski 
2007aac3fc32SAndrey Ignatov /* Initially all BPF programs could be loaded w/o specifying
2008aac3fc32SAndrey Ignatov  * expected_attach_type. Later for some of them specifying expected_attach_type
2009aac3fc32SAndrey Ignatov  * at load time became required so that program could be validated properly.
2010aac3fc32SAndrey Ignatov  * Programs of types that are allowed to be loaded both w/ and w/o (for
2011aac3fc32SAndrey Ignatov  * backward compatibility) expected_attach_type, should have the default attach
2012aac3fc32SAndrey Ignatov  * type assigned to expected_attach_type for the latter case, so that it can be
2013aac3fc32SAndrey Ignatov  * validated later at attach time.
2014aac3fc32SAndrey Ignatov  *
2015aac3fc32SAndrey Ignatov  * bpf_prog_load_fixup_attach_type() sets expected_attach_type in @attr if
2016aac3fc32SAndrey Ignatov  * prog type requires it but has some attach types that have to be backward
2017aac3fc32SAndrey Ignatov  * compatible.
2018aac3fc32SAndrey Ignatov  */
2019aac3fc32SAndrey Ignatov static void bpf_prog_load_fixup_attach_type(union bpf_attr *attr)
2020aac3fc32SAndrey Ignatov {
2021aac3fc32SAndrey Ignatov 	switch (attr->prog_type) {
2022aac3fc32SAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK:
2023aac3fc32SAndrey Ignatov 		/* Unfortunately BPF_ATTACH_TYPE_UNSPEC enumeration doesn't
2024aac3fc32SAndrey Ignatov 		 * exist so checking for non-zero is the way to go here.
2025aac3fc32SAndrey Ignatov 		 */
2026aac3fc32SAndrey Ignatov 		if (!attr->expected_attach_type)
2027aac3fc32SAndrey Ignatov 			attr->expected_attach_type =
2028aac3fc32SAndrey Ignatov 				BPF_CGROUP_INET_SOCK_CREATE;
2029aac3fc32SAndrey Ignatov 		break;
2030aac3fc32SAndrey Ignatov 	}
2031aac3fc32SAndrey Ignatov }
2032aac3fc32SAndrey Ignatov 
20335e43f899SAndrey Ignatov static int
2034ccfe29ebSAlexei Starovoitov bpf_prog_load_check_attach(enum bpf_prog_type prog_type,
2035ccfe29ebSAlexei Starovoitov 			   enum bpf_attach_type expected_attach_type,
20365b92a28aSAlexei Starovoitov 			   u32 btf_id, u32 prog_fd)
20375e43f899SAndrey Ignatov {
203827ae7997SMartin KaFai Lau 	if (btf_id) {
2039c108e3c1SAlexei Starovoitov 		if (btf_id > BTF_MAX_TYPE)
2040c108e3c1SAlexei Starovoitov 			return -EINVAL;
204127ae7997SMartin KaFai Lau 
204227ae7997SMartin KaFai Lau 		switch (prog_type) {
204327ae7997SMartin KaFai Lau 		case BPF_PROG_TYPE_TRACING:
20449e4e01dfSKP Singh 		case BPF_PROG_TYPE_LSM:
204527ae7997SMartin KaFai Lau 		case BPF_PROG_TYPE_STRUCT_OPS:
2046be8704ffSAlexei Starovoitov 		case BPF_PROG_TYPE_EXT:
2047c108e3c1SAlexei Starovoitov 			break;
2048c108e3c1SAlexei Starovoitov 		default:
2049c108e3c1SAlexei Starovoitov 			return -EINVAL;
2050c108e3c1SAlexei Starovoitov 		}
205127ae7997SMartin KaFai Lau 	}
205227ae7997SMartin KaFai Lau 
2053be8704ffSAlexei Starovoitov 	if (prog_fd && prog_type != BPF_PROG_TYPE_TRACING &&
2054be8704ffSAlexei Starovoitov 	    prog_type != BPF_PROG_TYPE_EXT)
205527ae7997SMartin KaFai Lau 		return -EINVAL;
2056c108e3c1SAlexei Starovoitov 
2057c108e3c1SAlexei Starovoitov 	switch (prog_type) {
2058aac3fc32SAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK:
2059aac3fc32SAndrey Ignatov 		switch (expected_attach_type) {
2060aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET_SOCK_CREATE:
2061f5836749SStanislav Fomichev 		case BPF_CGROUP_INET_SOCK_RELEASE:
2062aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET4_POST_BIND:
2063aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET6_POST_BIND:
2064aac3fc32SAndrey Ignatov 			return 0;
2065aac3fc32SAndrey Ignatov 		default:
2066aac3fc32SAndrey Ignatov 			return -EINVAL;
2067aac3fc32SAndrey Ignatov 		}
20684fbac77dSAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
20694fbac77dSAndrey Ignatov 		switch (expected_attach_type) {
20704fbac77dSAndrey Ignatov 		case BPF_CGROUP_INET4_BIND:
20714fbac77dSAndrey Ignatov 		case BPF_CGROUP_INET6_BIND:
2072d74bad4eSAndrey Ignatov 		case BPF_CGROUP_INET4_CONNECT:
2073d74bad4eSAndrey Ignatov 		case BPF_CGROUP_INET6_CONNECT:
20741b66d253SDaniel Borkmann 		case BPF_CGROUP_INET4_GETPEERNAME:
20751b66d253SDaniel Borkmann 		case BPF_CGROUP_INET6_GETPEERNAME:
20761b66d253SDaniel Borkmann 		case BPF_CGROUP_INET4_GETSOCKNAME:
20771b66d253SDaniel Borkmann 		case BPF_CGROUP_INET6_GETSOCKNAME:
20781cedee13SAndrey Ignatov 		case BPF_CGROUP_UDP4_SENDMSG:
20791cedee13SAndrey Ignatov 		case BPF_CGROUP_UDP6_SENDMSG:
2080983695faSDaniel Borkmann 		case BPF_CGROUP_UDP4_RECVMSG:
2081983695faSDaniel Borkmann 		case BPF_CGROUP_UDP6_RECVMSG:
20825e43f899SAndrey Ignatov 			return 0;
20834fbac77dSAndrey Ignatov 		default:
20844fbac77dSAndrey Ignatov 			return -EINVAL;
20854fbac77dSAndrey Ignatov 		}
20865cf1e914Sbrakmo 	case BPF_PROG_TYPE_CGROUP_SKB:
20875cf1e914Sbrakmo 		switch (expected_attach_type) {
20885cf1e914Sbrakmo 		case BPF_CGROUP_INET_INGRESS:
20895cf1e914Sbrakmo 		case BPF_CGROUP_INET_EGRESS:
20905cf1e914Sbrakmo 			return 0;
20915cf1e914Sbrakmo 		default:
20925cf1e914Sbrakmo 			return -EINVAL;
20935cf1e914Sbrakmo 		}
20940d01da6aSStanislav Fomichev 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
20950d01da6aSStanislav Fomichev 		switch (expected_attach_type) {
20960d01da6aSStanislav Fomichev 		case BPF_CGROUP_SETSOCKOPT:
20970d01da6aSStanislav Fomichev 		case BPF_CGROUP_GETSOCKOPT:
20980d01da6aSStanislav Fomichev 			return 0;
20990d01da6aSStanislav Fomichev 		default:
21000d01da6aSStanislav Fomichev 			return -EINVAL;
21010d01da6aSStanislav Fomichev 		}
2102e9ddbb77SJakub Sitnicki 	case BPF_PROG_TYPE_SK_LOOKUP:
2103e9ddbb77SJakub Sitnicki 		if (expected_attach_type == BPF_SK_LOOKUP)
2104e9ddbb77SJakub Sitnicki 			return 0;
2105e9ddbb77SJakub Sitnicki 		return -EINVAL;
2106be8704ffSAlexei Starovoitov 	case BPF_PROG_TYPE_EXT:
2107be8704ffSAlexei Starovoitov 		if (expected_attach_type)
2108be8704ffSAlexei Starovoitov 			return -EINVAL;
2109df561f66SGustavo A. R. Silva 		fallthrough;
21104fbac77dSAndrey Ignatov 	default:
21114fbac77dSAndrey Ignatov 		return 0;
21124fbac77dSAndrey Ignatov 	}
21135e43f899SAndrey Ignatov }
21145e43f899SAndrey Ignatov 
21152c78ee89SAlexei Starovoitov static bool is_net_admin_prog_type(enum bpf_prog_type prog_type)
21162c78ee89SAlexei Starovoitov {
21172c78ee89SAlexei Starovoitov 	switch (prog_type) {
21182c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SCHED_CLS:
21192c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SCHED_ACT:
21202c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_XDP:
21212c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_IN:
21222c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_OUT:
21232c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_XMIT:
21242c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_SEG6LOCAL:
21252c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SK_SKB:
21262c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SK_MSG:
21272c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LIRC_MODE2:
21282c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
21292c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_DEVICE:
21302c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SOCK:
21312c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
21322c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
21332c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
21342c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SOCK_OPS:
21352c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_EXT: /* extends any prog */
21362c78ee89SAlexei Starovoitov 		return true;
21372c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SKB:
21382c78ee89SAlexei Starovoitov 		/* always unpriv */
21392c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SK_REUSEPORT:
21402c78ee89SAlexei Starovoitov 		/* equivalent to SOCKET_FILTER. need CAP_BPF only */
21412c78ee89SAlexei Starovoitov 	default:
21422c78ee89SAlexei Starovoitov 		return false;
21432c78ee89SAlexei Starovoitov 	}
21442c78ee89SAlexei Starovoitov }
21452c78ee89SAlexei Starovoitov 
21462c78ee89SAlexei Starovoitov static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
21472c78ee89SAlexei Starovoitov {
21482c78ee89SAlexei Starovoitov 	switch (prog_type) {
21492c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_KPROBE:
21502c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_TRACEPOINT:
21512c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_PERF_EVENT:
21522c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_RAW_TRACEPOINT:
21532c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
21542c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_TRACING:
21552c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LSM:
21562c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_STRUCT_OPS: /* has access to struct sock */
21572c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_EXT: /* extends any prog */
21582c78ee89SAlexei Starovoitov 		return true;
21592c78ee89SAlexei Starovoitov 	default:
21602c78ee89SAlexei Starovoitov 		return false;
21612c78ee89SAlexei Starovoitov 	}
21622c78ee89SAlexei Starovoitov }
21632c78ee89SAlexei Starovoitov 
216409756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
21655b92a28aSAlexei Starovoitov #define	BPF_PROG_LOAD_LAST_FIELD attach_prog_fd
216609756af4SAlexei Starovoitov 
2167838e9690SYonghong Song static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
216809756af4SAlexei Starovoitov {
216909756af4SAlexei Starovoitov 	enum bpf_prog_type type = attr->prog_type;
217009756af4SAlexei Starovoitov 	struct bpf_prog *prog;
217109756af4SAlexei Starovoitov 	int err;
217209756af4SAlexei Starovoitov 	char license[128];
217309756af4SAlexei Starovoitov 	bool is_gpl;
217409756af4SAlexei Starovoitov 
217509756af4SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_LOAD))
217609756af4SAlexei Starovoitov 		return -EINVAL;
217709756af4SAlexei Starovoitov 
2178c240eff6SJiong Wang 	if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT |
2179c240eff6SJiong Wang 				 BPF_F_ANY_ALIGNMENT |
218010d274e8SAlexei Starovoitov 				 BPF_F_TEST_STATE_FREQ |
21811e6c62a8SAlexei Starovoitov 				 BPF_F_SLEEPABLE |
2182c240eff6SJiong Wang 				 BPF_F_TEST_RND_HI32))
2183e07b98d9SDavid S. Miller 		return -EINVAL;
2184e07b98d9SDavid S. Miller 
2185e9ee9efcSDavid Miller 	if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
2186e9ee9efcSDavid Miller 	    (attr->prog_flags & BPF_F_ANY_ALIGNMENT) &&
21872c78ee89SAlexei Starovoitov 	    !bpf_capable())
2188e9ee9efcSDavid Miller 		return -EPERM;
2189e9ee9efcSDavid Miller 
219009756af4SAlexei Starovoitov 	/* copy eBPF program license from user space */
2191535e7b4bSMickaël Salaün 	if (strncpy_from_user(license, u64_to_user_ptr(attr->license),
219209756af4SAlexei Starovoitov 			      sizeof(license) - 1) < 0)
219309756af4SAlexei Starovoitov 		return -EFAULT;
219409756af4SAlexei Starovoitov 	license[sizeof(license) - 1] = 0;
219509756af4SAlexei Starovoitov 
219609756af4SAlexei Starovoitov 	/* eBPF programs must be GPL compatible to use GPL-ed functions */
219709756af4SAlexei Starovoitov 	is_gpl = license_is_gpl_compatible(license);
219809756af4SAlexei Starovoitov 
2199c04c0d2bSAlexei Starovoitov 	if (attr->insn_cnt == 0 ||
22002c78ee89SAlexei Starovoitov 	    attr->insn_cnt > (bpf_capable() ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS))
2201ef0915caSDaniel Borkmann 		return -E2BIG;
220280b7d819SChenbo Feng 	if (type != BPF_PROG_TYPE_SOCKET_FILTER &&
220380b7d819SChenbo Feng 	    type != BPF_PROG_TYPE_CGROUP_SKB &&
22042c78ee89SAlexei Starovoitov 	    !bpf_capable())
22052c78ee89SAlexei Starovoitov 		return -EPERM;
22062c78ee89SAlexei Starovoitov 
2207b338cb92SMaciej Żenczykowski 	if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN) && !capable(CAP_SYS_ADMIN))
22082c78ee89SAlexei Starovoitov 		return -EPERM;
22092c78ee89SAlexei Starovoitov 	if (is_perfmon_prog_type(type) && !perfmon_capable())
22101be7f75dSAlexei Starovoitov 		return -EPERM;
22111be7f75dSAlexei Starovoitov 
2212aac3fc32SAndrey Ignatov 	bpf_prog_load_fixup_attach_type(attr);
2213ccfe29ebSAlexei Starovoitov 	if (bpf_prog_load_check_attach(type, attr->expected_attach_type,
22145b92a28aSAlexei Starovoitov 				       attr->attach_btf_id,
22155b92a28aSAlexei Starovoitov 				       attr->attach_prog_fd))
22165e43f899SAndrey Ignatov 		return -EINVAL;
22175e43f899SAndrey Ignatov 
221809756af4SAlexei Starovoitov 	/* plain bpf_prog allocation */
221909756af4SAlexei Starovoitov 	prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
222009756af4SAlexei Starovoitov 	if (!prog)
222109756af4SAlexei Starovoitov 		return -ENOMEM;
222209756af4SAlexei Starovoitov 
22235e43f899SAndrey Ignatov 	prog->expected_attach_type = attr->expected_attach_type;
2224ccfe29ebSAlexei Starovoitov 	prog->aux->attach_btf_id = attr->attach_btf_id;
22255b92a28aSAlexei Starovoitov 	if (attr->attach_prog_fd) {
22263aac1eadSToke Høiland-Jørgensen 		struct bpf_prog *dst_prog;
22275b92a28aSAlexei Starovoitov 
22283aac1eadSToke Høiland-Jørgensen 		dst_prog = bpf_prog_get(attr->attach_prog_fd);
22293aac1eadSToke Høiland-Jørgensen 		if (IS_ERR(dst_prog)) {
22303aac1eadSToke Høiland-Jørgensen 			err = PTR_ERR(dst_prog);
22315b92a28aSAlexei Starovoitov 			goto free_prog_nouncharge;
22325b92a28aSAlexei Starovoitov 		}
22333aac1eadSToke Høiland-Jørgensen 		prog->aux->dst_prog = dst_prog;
22345b92a28aSAlexei Starovoitov 	}
22355e43f899SAndrey Ignatov 
22369a18eedbSJakub Kicinski 	prog->aux->offload_requested = !!attr->prog_ifindex;
22371e6c62a8SAlexei Starovoitov 	prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE;
22389a18eedbSJakub Kicinski 
2239afdb09c7SChenbo Feng 	err = security_bpf_prog_alloc(prog->aux);
2240aaac3ba9SAlexei Starovoitov 	if (err)
2241aaac3ba9SAlexei Starovoitov 		goto free_prog_nouncharge;
2242aaac3ba9SAlexei Starovoitov 
2243afdb09c7SChenbo Feng 	err = bpf_prog_charge_memlock(prog);
2244afdb09c7SChenbo Feng 	if (err)
2245afdb09c7SChenbo Feng 		goto free_prog_sec;
2246afdb09c7SChenbo Feng 
224709756af4SAlexei Starovoitov 	prog->len = attr->insn_cnt;
224809756af4SAlexei Starovoitov 
224909756af4SAlexei Starovoitov 	err = -EFAULT;
2250535e7b4bSMickaël Salaün 	if (copy_from_user(prog->insns, u64_to_user_ptr(attr->insns),
2251aafe6ae9SDaniel Borkmann 			   bpf_prog_insn_size(prog)) != 0)
225209756af4SAlexei Starovoitov 		goto free_prog;
225309756af4SAlexei Starovoitov 
225409756af4SAlexei Starovoitov 	prog->orig_prog = NULL;
2255a91263d5SDaniel Borkmann 	prog->jited = 0;
225609756af4SAlexei Starovoitov 
225785192dbfSAndrii Nakryiko 	atomic64_set(&prog->aux->refcnt, 1);
2258a91263d5SDaniel Borkmann 	prog->gpl_compatible = is_gpl ? 1 : 0;
225909756af4SAlexei Starovoitov 
22609a18eedbSJakub Kicinski 	if (bpf_prog_is_dev_bound(prog->aux)) {
2261ab3f0063SJakub Kicinski 		err = bpf_prog_offload_init(prog, attr);
2262ab3f0063SJakub Kicinski 		if (err)
2263ab3f0063SJakub Kicinski 			goto free_prog;
2264ab3f0063SJakub Kicinski 	}
2265ab3f0063SJakub Kicinski 
226609756af4SAlexei Starovoitov 	/* find program type: socket_filter vs tracing_filter */
226709756af4SAlexei Starovoitov 	err = find_prog_type(type, prog);
226809756af4SAlexei Starovoitov 	if (err < 0)
226909756af4SAlexei Starovoitov 		goto free_prog;
227009756af4SAlexei Starovoitov 
22719285ec4cSJason A. Donenfeld 	prog->aux->load_time = ktime_get_boottime_ns();
22728e7ae251SMartin KaFai Lau 	err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name,
22738e7ae251SMartin KaFai Lau 			       sizeof(attr->prog_name));
22748e7ae251SMartin KaFai Lau 	if (err < 0)
2275cb4d2b3fSMartin KaFai Lau 		goto free_prog;
2276cb4d2b3fSMartin KaFai Lau 
227709756af4SAlexei Starovoitov 	/* run eBPF verifier */
2278838e9690SYonghong Song 	err = bpf_check(&prog, attr, uattr);
227909756af4SAlexei Starovoitov 	if (err < 0)
228009756af4SAlexei Starovoitov 		goto free_used_maps;
228109756af4SAlexei Starovoitov 
2282d1c55ab5SDaniel Borkmann 	prog = bpf_prog_select_runtime(prog, &err);
228304fd61abSAlexei Starovoitov 	if (err < 0)
228404fd61abSAlexei Starovoitov 		goto free_used_maps;
228509756af4SAlexei Starovoitov 
2286dc4bb0e2SMartin KaFai Lau 	err = bpf_prog_alloc_id(prog);
2287dc4bb0e2SMartin KaFai Lau 	if (err)
2288dc4bb0e2SMartin KaFai Lau 		goto free_used_maps;
2289dc4bb0e2SMartin KaFai Lau 
2290c751798aSDaniel Borkmann 	/* Upon success of bpf_prog_alloc_id(), the BPF prog is
2291c751798aSDaniel Borkmann 	 * effectively publicly exposed. However, retrieving via
2292c751798aSDaniel Borkmann 	 * bpf_prog_get_fd_by_id() will take another reference,
2293c751798aSDaniel Borkmann 	 * therefore it cannot be gone underneath us.
2294c751798aSDaniel Borkmann 	 *
2295c751798aSDaniel Borkmann 	 * Only for the time /after/ successful bpf_prog_new_fd()
2296c751798aSDaniel Borkmann 	 * and before returning to userspace, we might just hold
2297c751798aSDaniel Borkmann 	 * one reference and any parallel close on that fd could
2298c751798aSDaniel Borkmann 	 * rip everything out. Hence, below notifications must
2299c751798aSDaniel Borkmann 	 * happen before bpf_prog_new_fd().
2300c751798aSDaniel Borkmann 	 *
2301c751798aSDaniel Borkmann 	 * Also, any failure handling from this point onwards must
2302c751798aSDaniel Borkmann 	 * be using bpf_prog_put() given the program is exposed.
2303b16d9aa4SMartin KaFai Lau 	 */
230474451e66SDaniel Borkmann 	bpf_prog_kallsyms_add(prog);
23056ee52e2aSSong Liu 	perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0);
2306bae141f5SDaniel Borkmann 	bpf_audit_prog(prog, BPF_AUDIT_LOAD);
2307c751798aSDaniel Borkmann 
2308c751798aSDaniel Borkmann 	err = bpf_prog_new_fd(prog);
2309c751798aSDaniel Borkmann 	if (err < 0)
2310c751798aSDaniel Borkmann 		bpf_prog_put(prog);
231109756af4SAlexei Starovoitov 	return err;
231209756af4SAlexei Starovoitov 
231309756af4SAlexei Starovoitov free_used_maps:
2314cd7455f1SDaniel Borkmann 	/* In case we have subprogs, we need to wait for a grace
2315cd7455f1SDaniel Borkmann 	 * period before we can tear down JIT memory since symbols
2316cd7455f1SDaniel Borkmann 	 * are already exposed under kallsyms.
2317cd7455f1SDaniel Borkmann 	 */
2318cd7455f1SDaniel Borkmann 	__bpf_prog_put_noref(prog, prog->aux->func_cnt);
2319cd7455f1SDaniel Borkmann 	return err;
232009756af4SAlexei Starovoitov free_prog:
2321aaac3ba9SAlexei Starovoitov 	bpf_prog_uncharge_memlock(prog);
2322afdb09c7SChenbo Feng free_prog_sec:
2323afdb09c7SChenbo Feng 	security_bpf_prog_free(prog->aux);
2324aaac3ba9SAlexei Starovoitov free_prog_nouncharge:
232509756af4SAlexei Starovoitov 	bpf_prog_free(prog);
232609756af4SAlexei Starovoitov 	return err;
232709756af4SAlexei Starovoitov }
232809756af4SAlexei Starovoitov 
23296e71b04aSChenbo Feng #define BPF_OBJ_LAST_FIELD file_flags
2330b2197755SDaniel Borkmann 
2331b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr)
2332b2197755SDaniel Borkmann {
23336e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_OBJ) || attr->file_flags != 0)
2334b2197755SDaniel Borkmann 		return -EINVAL;
2335b2197755SDaniel Borkmann 
2336535e7b4bSMickaël Salaün 	return bpf_obj_pin_user(attr->bpf_fd, u64_to_user_ptr(attr->pathname));
2337b2197755SDaniel Borkmann }
2338b2197755SDaniel Borkmann 
2339b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr)
2340b2197755SDaniel Borkmann {
23416e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0 ||
23426e71b04aSChenbo Feng 	    attr->file_flags & ~BPF_OBJ_FLAG_MASK)
2343b2197755SDaniel Borkmann 		return -EINVAL;
2344b2197755SDaniel Borkmann 
23456e71b04aSChenbo Feng 	return bpf_obj_get_user(u64_to_user_ptr(attr->pathname),
23466e71b04aSChenbo Feng 				attr->file_flags);
2347b2197755SDaniel Borkmann }
2348b2197755SDaniel Borkmann 
2349f2e10bffSAndrii Nakryiko void bpf_link_init(struct bpf_link *link, enum bpf_link_type type,
2350a3b80e10SAndrii Nakryiko 		   const struct bpf_link_ops *ops, struct bpf_prog *prog)
235170ed506cSAndrii Nakryiko {
235270ed506cSAndrii Nakryiko 	atomic64_set(&link->refcnt, 1);
2353f2e10bffSAndrii Nakryiko 	link->type = type;
2354a3b80e10SAndrii Nakryiko 	link->id = 0;
235570ed506cSAndrii Nakryiko 	link->ops = ops;
235670ed506cSAndrii Nakryiko 	link->prog = prog;
235770ed506cSAndrii Nakryiko }
235870ed506cSAndrii Nakryiko 
2359a3b80e10SAndrii Nakryiko static void bpf_link_free_id(int id)
2360a3b80e10SAndrii Nakryiko {
2361a3b80e10SAndrii Nakryiko 	if (!id)
2362a3b80e10SAndrii Nakryiko 		return;
2363a3b80e10SAndrii Nakryiko 
2364a3b80e10SAndrii Nakryiko 	spin_lock_bh(&link_idr_lock);
2365a3b80e10SAndrii Nakryiko 	idr_remove(&link_idr, id);
2366a3b80e10SAndrii Nakryiko 	spin_unlock_bh(&link_idr_lock);
2367a3b80e10SAndrii Nakryiko }
2368a3b80e10SAndrii Nakryiko 
236998868668SAndrii Nakryiko /* Clean up bpf_link and corresponding anon_inode file and FD. After
237098868668SAndrii Nakryiko  * anon_inode is created, bpf_link can't be just kfree()'d due to deferred
2371a3b80e10SAndrii Nakryiko  * anon_inode's release() call. This helper marksbpf_link as
2372a3b80e10SAndrii Nakryiko  * defunct, releases anon_inode file and puts reserved FD. bpf_prog's refcnt
2373a3b80e10SAndrii Nakryiko  * is not decremented, it's the responsibility of a calling code that failed
2374a3b80e10SAndrii Nakryiko  * to complete bpf_link initialization.
237598868668SAndrii Nakryiko  */
2376a3b80e10SAndrii Nakryiko void bpf_link_cleanup(struct bpf_link_primer *primer)
2377babf3164SAndrii Nakryiko {
2378a3b80e10SAndrii Nakryiko 	primer->link->prog = NULL;
2379a3b80e10SAndrii Nakryiko 	bpf_link_free_id(primer->id);
2380a3b80e10SAndrii Nakryiko 	fput(primer->file);
2381a3b80e10SAndrii Nakryiko 	put_unused_fd(primer->fd);
2382babf3164SAndrii Nakryiko }
2383babf3164SAndrii Nakryiko 
238470ed506cSAndrii Nakryiko void bpf_link_inc(struct bpf_link *link)
238570ed506cSAndrii Nakryiko {
238670ed506cSAndrii Nakryiko 	atomic64_inc(&link->refcnt);
238770ed506cSAndrii Nakryiko }
238870ed506cSAndrii Nakryiko 
238970ed506cSAndrii Nakryiko /* bpf_link_free is guaranteed to be called from process context */
239070ed506cSAndrii Nakryiko static void bpf_link_free(struct bpf_link *link)
239170ed506cSAndrii Nakryiko {
2392a3b80e10SAndrii Nakryiko 	bpf_link_free_id(link->id);
2393babf3164SAndrii Nakryiko 	if (link->prog) {
2394babf3164SAndrii Nakryiko 		/* detach BPF program, clean up used resources */
239570ed506cSAndrii Nakryiko 		link->ops->release(link);
2396babf3164SAndrii Nakryiko 		bpf_prog_put(link->prog);
2397babf3164SAndrii Nakryiko 	}
2398babf3164SAndrii Nakryiko 	/* free bpf_link and its containing memory */
2399babf3164SAndrii Nakryiko 	link->ops->dealloc(link);
240070ed506cSAndrii Nakryiko }
240170ed506cSAndrii Nakryiko 
240270ed506cSAndrii Nakryiko static void bpf_link_put_deferred(struct work_struct *work)
240370ed506cSAndrii Nakryiko {
240470ed506cSAndrii Nakryiko 	struct bpf_link *link = container_of(work, struct bpf_link, work);
240570ed506cSAndrii Nakryiko 
240670ed506cSAndrii Nakryiko 	bpf_link_free(link);
240770ed506cSAndrii Nakryiko }
240870ed506cSAndrii Nakryiko 
240970ed506cSAndrii Nakryiko /* bpf_link_put can be called from atomic context, but ensures that resources
241070ed506cSAndrii Nakryiko  * are freed from process context
241170ed506cSAndrii Nakryiko  */
241270ed506cSAndrii Nakryiko void bpf_link_put(struct bpf_link *link)
241370ed506cSAndrii Nakryiko {
241470ed506cSAndrii Nakryiko 	if (!atomic64_dec_and_test(&link->refcnt))
241570ed506cSAndrii Nakryiko 		return;
241670ed506cSAndrii Nakryiko 
2417f00f2f7fSAlexei Starovoitov 	if (in_atomic()) {
241870ed506cSAndrii Nakryiko 		INIT_WORK(&link->work, bpf_link_put_deferred);
241970ed506cSAndrii Nakryiko 		schedule_work(&link->work);
2420f00f2f7fSAlexei Starovoitov 	} else {
2421f00f2f7fSAlexei Starovoitov 		bpf_link_free(link);
2422f00f2f7fSAlexei Starovoitov 	}
242370ed506cSAndrii Nakryiko }
242470ed506cSAndrii Nakryiko 
242570ed506cSAndrii Nakryiko static int bpf_link_release(struct inode *inode, struct file *filp)
242670ed506cSAndrii Nakryiko {
242770ed506cSAndrii Nakryiko 	struct bpf_link *link = filp->private_data;
242870ed506cSAndrii Nakryiko 
242970ed506cSAndrii Nakryiko 	bpf_link_put(link);
2430fec56f58SAlexei Starovoitov 	return 0;
2431fec56f58SAlexei Starovoitov }
2432fec56f58SAlexei Starovoitov 
243370ed506cSAndrii Nakryiko #ifdef CONFIG_PROC_FS
2434f2e10bffSAndrii Nakryiko #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type)
2435f2e10bffSAndrii Nakryiko #define BPF_MAP_TYPE(_id, _ops)
2436f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name) [_id] = #_name,
2437f2e10bffSAndrii Nakryiko static const char *bpf_link_type_strs[] = {
2438f2e10bffSAndrii Nakryiko 	[BPF_LINK_TYPE_UNSPEC] = "<invalid>",
2439f2e10bffSAndrii Nakryiko #include <linux/bpf_types.h>
2440f2e10bffSAndrii Nakryiko };
2441f2e10bffSAndrii Nakryiko #undef BPF_PROG_TYPE
2442f2e10bffSAndrii Nakryiko #undef BPF_MAP_TYPE
2443f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE
244470ed506cSAndrii Nakryiko 
244570ed506cSAndrii Nakryiko static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
244670ed506cSAndrii Nakryiko {
244770ed506cSAndrii Nakryiko 	const struct bpf_link *link = filp->private_data;
244870ed506cSAndrii Nakryiko 	const struct bpf_prog *prog = link->prog;
244970ed506cSAndrii Nakryiko 	char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
245070ed506cSAndrii Nakryiko 
245170ed506cSAndrii Nakryiko 	bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
245270ed506cSAndrii Nakryiko 	seq_printf(m,
245370ed506cSAndrii Nakryiko 		   "link_type:\t%s\n"
2454a3b80e10SAndrii Nakryiko 		   "link_id:\t%u\n"
245570ed506cSAndrii Nakryiko 		   "prog_tag:\t%s\n"
245670ed506cSAndrii Nakryiko 		   "prog_id:\t%u\n",
2457f2e10bffSAndrii Nakryiko 		   bpf_link_type_strs[link->type],
2458a3b80e10SAndrii Nakryiko 		   link->id,
245970ed506cSAndrii Nakryiko 		   prog_tag,
246070ed506cSAndrii Nakryiko 		   prog->aux->id);
2461f2e10bffSAndrii Nakryiko 	if (link->ops->show_fdinfo)
2462f2e10bffSAndrii Nakryiko 		link->ops->show_fdinfo(link, m);
246370ed506cSAndrii Nakryiko }
246470ed506cSAndrii Nakryiko #endif
246570ed506cSAndrii Nakryiko 
24666f302bfbSZou Wei static const struct file_operations bpf_link_fops = {
246770ed506cSAndrii Nakryiko #ifdef CONFIG_PROC_FS
246870ed506cSAndrii Nakryiko 	.show_fdinfo	= bpf_link_show_fdinfo,
246970ed506cSAndrii Nakryiko #endif
247070ed506cSAndrii Nakryiko 	.release	= bpf_link_release,
2471fec56f58SAlexei Starovoitov 	.read		= bpf_dummy_read,
2472fec56f58SAlexei Starovoitov 	.write		= bpf_dummy_write,
2473fec56f58SAlexei Starovoitov };
2474fec56f58SAlexei Starovoitov 
2475a3b80e10SAndrii Nakryiko static int bpf_link_alloc_id(struct bpf_link *link)
247670ed506cSAndrii Nakryiko {
2477a3b80e10SAndrii Nakryiko 	int id;
2478a3b80e10SAndrii Nakryiko 
2479a3b80e10SAndrii Nakryiko 	idr_preload(GFP_KERNEL);
2480a3b80e10SAndrii Nakryiko 	spin_lock_bh(&link_idr_lock);
2481a3b80e10SAndrii Nakryiko 	id = idr_alloc_cyclic(&link_idr, link, 1, INT_MAX, GFP_ATOMIC);
2482a3b80e10SAndrii Nakryiko 	spin_unlock_bh(&link_idr_lock);
2483a3b80e10SAndrii Nakryiko 	idr_preload_end();
2484a3b80e10SAndrii Nakryiko 
2485a3b80e10SAndrii Nakryiko 	return id;
248670ed506cSAndrii Nakryiko }
248770ed506cSAndrii Nakryiko 
2488a3b80e10SAndrii Nakryiko /* Prepare bpf_link to be exposed to user-space by allocating anon_inode file,
2489a3b80e10SAndrii Nakryiko  * reserving unused FD and allocating ID from link_idr. This is to be paired
2490a3b80e10SAndrii Nakryiko  * with bpf_link_settle() to install FD and ID and expose bpf_link to
2491a3b80e10SAndrii Nakryiko  * user-space, if bpf_link is successfully attached. If not, bpf_link and
2492a3b80e10SAndrii Nakryiko  * pre-allocated resources are to be freed with bpf_cleanup() call. All the
2493a3b80e10SAndrii Nakryiko  * transient state is passed around in struct bpf_link_primer.
2494a3b80e10SAndrii Nakryiko  * This is preferred way to create and initialize bpf_link, especially when
2495a3b80e10SAndrii Nakryiko  * there are complicated and expensive operations inbetween creating bpf_link
2496a3b80e10SAndrii Nakryiko  * itself and attaching it to BPF hook. By using bpf_link_prime() and
2497a3b80e10SAndrii Nakryiko  * bpf_link_settle() kernel code using bpf_link doesn't have to perform
2498a3b80e10SAndrii Nakryiko  * expensive (and potentially failing) roll back operations in a rare case
2499a3b80e10SAndrii Nakryiko  * that file, FD, or ID can't be allocated.
2500babf3164SAndrii Nakryiko  */
2501a3b80e10SAndrii Nakryiko int bpf_link_prime(struct bpf_link *link, struct bpf_link_primer *primer)
2502babf3164SAndrii Nakryiko {
2503babf3164SAndrii Nakryiko 	struct file *file;
2504a3b80e10SAndrii Nakryiko 	int fd, id;
2505babf3164SAndrii Nakryiko 
2506babf3164SAndrii Nakryiko 	fd = get_unused_fd_flags(O_CLOEXEC);
2507babf3164SAndrii Nakryiko 	if (fd < 0)
2508a3b80e10SAndrii Nakryiko 		return fd;
2509babf3164SAndrii Nakryiko 
2510babf3164SAndrii Nakryiko 
2511a3b80e10SAndrii Nakryiko 	id = bpf_link_alloc_id(link);
2512a3b80e10SAndrii Nakryiko 	if (id < 0) {
2513a3b80e10SAndrii Nakryiko 		put_unused_fd(fd);
2514a3b80e10SAndrii Nakryiko 		return id;
2515a3b80e10SAndrii Nakryiko 	}
2516babf3164SAndrii Nakryiko 
2517babf3164SAndrii Nakryiko 	file = anon_inode_getfile("bpf_link", &bpf_link_fops, link, O_CLOEXEC);
2518babf3164SAndrii Nakryiko 	if (IS_ERR(file)) {
2519138c6767SAndrii Nakryiko 		bpf_link_free_id(id);
2520babf3164SAndrii Nakryiko 		put_unused_fd(fd);
2521138c6767SAndrii Nakryiko 		return PTR_ERR(file);
2522babf3164SAndrii Nakryiko 	}
2523babf3164SAndrii Nakryiko 
2524a3b80e10SAndrii Nakryiko 	primer->link = link;
2525a3b80e10SAndrii Nakryiko 	primer->file = file;
2526a3b80e10SAndrii Nakryiko 	primer->fd = fd;
2527a3b80e10SAndrii Nakryiko 	primer->id = id;
2528a3b80e10SAndrii Nakryiko 	return 0;
2529a3b80e10SAndrii Nakryiko }
2530a3b80e10SAndrii Nakryiko 
2531a3b80e10SAndrii Nakryiko int bpf_link_settle(struct bpf_link_primer *primer)
2532a3b80e10SAndrii Nakryiko {
2533a3b80e10SAndrii Nakryiko 	/* make bpf_link fetchable by ID */
2534a3b80e10SAndrii Nakryiko 	spin_lock_bh(&link_idr_lock);
2535a3b80e10SAndrii Nakryiko 	primer->link->id = primer->id;
2536a3b80e10SAndrii Nakryiko 	spin_unlock_bh(&link_idr_lock);
2537a3b80e10SAndrii Nakryiko 	/* make bpf_link fetchable by FD */
2538a3b80e10SAndrii Nakryiko 	fd_install(primer->fd, primer->file);
2539a3b80e10SAndrii Nakryiko 	/* pass through installed FD */
2540a3b80e10SAndrii Nakryiko 	return primer->fd;
2541a3b80e10SAndrii Nakryiko }
2542a3b80e10SAndrii Nakryiko 
2543a3b80e10SAndrii Nakryiko int bpf_link_new_fd(struct bpf_link *link)
2544a3b80e10SAndrii Nakryiko {
2545a3b80e10SAndrii Nakryiko 	return anon_inode_getfd("bpf-link", &bpf_link_fops, link, O_CLOEXEC);
2546babf3164SAndrii Nakryiko }
2547babf3164SAndrii Nakryiko 
254870ed506cSAndrii Nakryiko struct bpf_link *bpf_link_get_from_fd(u32 ufd)
254970ed506cSAndrii Nakryiko {
255070ed506cSAndrii Nakryiko 	struct fd f = fdget(ufd);
255170ed506cSAndrii Nakryiko 	struct bpf_link *link;
255270ed506cSAndrii Nakryiko 
255370ed506cSAndrii Nakryiko 	if (!f.file)
255470ed506cSAndrii Nakryiko 		return ERR_PTR(-EBADF);
255570ed506cSAndrii Nakryiko 	if (f.file->f_op != &bpf_link_fops) {
255670ed506cSAndrii Nakryiko 		fdput(f);
255770ed506cSAndrii Nakryiko 		return ERR_PTR(-EINVAL);
255870ed506cSAndrii Nakryiko 	}
255970ed506cSAndrii Nakryiko 
256070ed506cSAndrii Nakryiko 	link = f.file->private_data;
256170ed506cSAndrii Nakryiko 	bpf_link_inc(link);
256270ed506cSAndrii Nakryiko 	fdput(f);
256370ed506cSAndrii Nakryiko 
256470ed506cSAndrii Nakryiko 	return link;
256570ed506cSAndrii Nakryiko }
256670ed506cSAndrii Nakryiko 
256770ed506cSAndrii Nakryiko struct bpf_tracing_link {
256870ed506cSAndrii Nakryiko 	struct bpf_link link;
2569f2e10bffSAndrii Nakryiko 	enum bpf_attach_type attach_type;
25703aac1eadSToke Høiland-Jørgensen 	struct bpf_trampoline *trampoline;
25713aac1eadSToke Høiland-Jørgensen 	struct bpf_prog *tgt_prog;
257270ed506cSAndrii Nakryiko };
257370ed506cSAndrii Nakryiko 
257470ed506cSAndrii Nakryiko static void bpf_tracing_link_release(struct bpf_link *link)
257570ed506cSAndrii Nakryiko {
25763aac1eadSToke Høiland-Jørgensen 	struct bpf_tracing_link *tr_link =
25773aac1eadSToke Høiland-Jørgensen 		container_of(link, struct bpf_tracing_link, link);
25783aac1eadSToke Høiland-Jørgensen 
25793aac1eadSToke Høiland-Jørgensen 	WARN_ON_ONCE(bpf_trampoline_unlink_prog(link->prog,
25803aac1eadSToke Høiland-Jørgensen 						tr_link->trampoline));
25813aac1eadSToke Høiland-Jørgensen 
25823aac1eadSToke Høiland-Jørgensen 	bpf_trampoline_put(tr_link->trampoline);
25833aac1eadSToke Høiland-Jørgensen 
25843aac1eadSToke Høiland-Jørgensen 	/* tgt_prog is NULL if target is a kernel function */
25853aac1eadSToke Høiland-Jørgensen 	if (tr_link->tgt_prog)
25863aac1eadSToke Høiland-Jørgensen 		bpf_prog_put(tr_link->tgt_prog);
2587babf3164SAndrii Nakryiko }
2588babf3164SAndrii Nakryiko 
2589babf3164SAndrii Nakryiko static void bpf_tracing_link_dealloc(struct bpf_link *link)
2590babf3164SAndrii Nakryiko {
259170ed506cSAndrii Nakryiko 	struct bpf_tracing_link *tr_link =
259270ed506cSAndrii Nakryiko 		container_of(link, struct bpf_tracing_link, link);
259370ed506cSAndrii Nakryiko 
259470ed506cSAndrii Nakryiko 	kfree(tr_link);
259570ed506cSAndrii Nakryiko }
259670ed506cSAndrii Nakryiko 
2597f2e10bffSAndrii Nakryiko static void bpf_tracing_link_show_fdinfo(const struct bpf_link *link,
2598f2e10bffSAndrii Nakryiko 					 struct seq_file *seq)
2599f2e10bffSAndrii Nakryiko {
2600f2e10bffSAndrii Nakryiko 	struct bpf_tracing_link *tr_link =
2601f2e10bffSAndrii Nakryiko 		container_of(link, struct bpf_tracing_link, link);
2602f2e10bffSAndrii Nakryiko 
2603f2e10bffSAndrii Nakryiko 	seq_printf(seq,
2604f2e10bffSAndrii Nakryiko 		   "attach_type:\t%d\n",
2605f2e10bffSAndrii Nakryiko 		   tr_link->attach_type);
2606f2e10bffSAndrii Nakryiko }
2607f2e10bffSAndrii Nakryiko 
2608f2e10bffSAndrii Nakryiko static int bpf_tracing_link_fill_link_info(const struct bpf_link *link,
2609f2e10bffSAndrii Nakryiko 					   struct bpf_link_info *info)
2610f2e10bffSAndrii Nakryiko {
2611f2e10bffSAndrii Nakryiko 	struct bpf_tracing_link *tr_link =
2612f2e10bffSAndrii Nakryiko 		container_of(link, struct bpf_tracing_link, link);
2613f2e10bffSAndrii Nakryiko 
2614f2e10bffSAndrii Nakryiko 	info->tracing.attach_type = tr_link->attach_type;
2615f2e10bffSAndrii Nakryiko 
2616f2e10bffSAndrii Nakryiko 	return 0;
2617f2e10bffSAndrii Nakryiko }
2618f2e10bffSAndrii Nakryiko 
261970ed506cSAndrii Nakryiko static const struct bpf_link_ops bpf_tracing_link_lops = {
262070ed506cSAndrii Nakryiko 	.release = bpf_tracing_link_release,
2621babf3164SAndrii Nakryiko 	.dealloc = bpf_tracing_link_dealloc,
2622f2e10bffSAndrii Nakryiko 	.show_fdinfo = bpf_tracing_link_show_fdinfo,
2623f2e10bffSAndrii Nakryiko 	.fill_link_info = bpf_tracing_link_fill_link_info,
262470ed506cSAndrii Nakryiko };
262570ed506cSAndrii Nakryiko 
26264a1e7c0cSToke Høiland-Jørgensen static int bpf_tracing_prog_attach(struct bpf_prog *prog,
26274a1e7c0cSToke Høiland-Jørgensen 				   int tgt_prog_fd,
26284a1e7c0cSToke Høiland-Jørgensen 				   u32 btf_id)
2629fec56f58SAlexei Starovoitov {
2630a3b80e10SAndrii Nakryiko 	struct bpf_link_primer link_primer;
26313aac1eadSToke Høiland-Jørgensen 	struct bpf_prog *tgt_prog = NULL;
26324a1e7c0cSToke Høiland-Jørgensen 	struct bpf_trampoline *tr = NULL;
263370ed506cSAndrii Nakryiko 	struct bpf_tracing_link *link;
26344a1e7c0cSToke Høiland-Jørgensen 	u64 key = 0;
2635a3b80e10SAndrii Nakryiko 	int err;
2636fec56f58SAlexei Starovoitov 
26379e4e01dfSKP Singh 	switch (prog->type) {
26389e4e01dfSKP Singh 	case BPF_PROG_TYPE_TRACING:
2639fec56f58SAlexei Starovoitov 		if (prog->expected_attach_type != BPF_TRACE_FENTRY &&
2640be8704ffSAlexei Starovoitov 		    prog->expected_attach_type != BPF_TRACE_FEXIT &&
26419e4e01dfSKP Singh 		    prog->expected_attach_type != BPF_MODIFY_RETURN) {
26429e4e01dfSKP Singh 			err = -EINVAL;
26439e4e01dfSKP Singh 			goto out_put_prog;
26449e4e01dfSKP Singh 		}
26459e4e01dfSKP Singh 		break;
26469e4e01dfSKP Singh 	case BPF_PROG_TYPE_EXT:
26479e4e01dfSKP Singh 		if (prog->expected_attach_type != 0) {
26489e4e01dfSKP Singh 			err = -EINVAL;
26499e4e01dfSKP Singh 			goto out_put_prog;
26509e4e01dfSKP Singh 		}
26519e4e01dfSKP Singh 		break;
26529e4e01dfSKP Singh 	case BPF_PROG_TYPE_LSM:
26539e4e01dfSKP Singh 		if (prog->expected_attach_type != BPF_LSM_MAC) {
26549e4e01dfSKP Singh 			err = -EINVAL;
26559e4e01dfSKP Singh 			goto out_put_prog;
26569e4e01dfSKP Singh 		}
26579e4e01dfSKP Singh 		break;
26589e4e01dfSKP Singh 	default:
2659fec56f58SAlexei Starovoitov 		err = -EINVAL;
2660fec56f58SAlexei Starovoitov 		goto out_put_prog;
2661fec56f58SAlexei Starovoitov 	}
2662fec56f58SAlexei Starovoitov 
26634a1e7c0cSToke Høiland-Jørgensen 	if (!!tgt_prog_fd != !!btf_id) {
26644a1e7c0cSToke Høiland-Jørgensen 		err = -EINVAL;
26654a1e7c0cSToke Høiland-Jørgensen 		goto out_put_prog;
26664a1e7c0cSToke Høiland-Jørgensen 	}
26674a1e7c0cSToke Høiland-Jørgensen 
26684a1e7c0cSToke Høiland-Jørgensen 	if (tgt_prog_fd) {
26694a1e7c0cSToke Høiland-Jørgensen 		/* For now we only allow new targets for BPF_PROG_TYPE_EXT */
26704a1e7c0cSToke Høiland-Jørgensen 		if (prog->type != BPF_PROG_TYPE_EXT) {
26714a1e7c0cSToke Høiland-Jørgensen 			err = -EINVAL;
26724a1e7c0cSToke Høiland-Jørgensen 			goto out_put_prog;
26734a1e7c0cSToke Høiland-Jørgensen 		}
26744a1e7c0cSToke Høiland-Jørgensen 
26754a1e7c0cSToke Høiland-Jørgensen 		tgt_prog = bpf_prog_get(tgt_prog_fd);
26764a1e7c0cSToke Høiland-Jørgensen 		if (IS_ERR(tgt_prog)) {
26774a1e7c0cSToke Høiland-Jørgensen 			err = PTR_ERR(tgt_prog);
26784a1e7c0cSToke Høiland-Jørgensen 			tgt_prog = NULL;
26794a1e7c0cSToke Høiland-Jørgensen 			goto out_put_prog;
26804a1e7c0cSToke Høiland-Jørgensen 		}
26814a1e7c0cSToke Høiland-Jørgensen 
26824a1e7c0cSToke Høiland-Jørgensen 		key = bpf_trampoline_compute_key(tgt_prog, btf_id);
26834a1e7c0cSToke Høiland-Jørgensen 	}
26844a1e7c0cSToke Høiland-Jørgensen 
268570ed506cSAndrii Nakryiko 	link = kzalloc(sizeof(*link), GFP_USER);
268670ed506cSAndrii Nakryiko 	if (!link) {
268770ed506cSAndrii Nakryiko 		err = -ENOMEM;
2688fec56f58SAlexei Starovoitov 		goto out_put_prog;
2689fec56f58SAlexei Starovoitov 	}
2690f2e10bffSAndrii Nakryiko 	bpf_link_init(&link->link, BPF_LINK_TYPE_TRACING,
2691f2e10bffSAndrii Nakryiko 		      &bpf_tracing_link_lops, prog);
2692f2e10bffSAndrii Nakryiko 	link->attach_type = prog->expected_attach_type;
2693fec56f58SAlexei Starovoitov 
26943aac1eadSToke Høiland-Jørgensen 	mutex_lock(&prog->aux->dst_mutex);
2695babf3164SAndrii Nakryiko 
26964a1e7c0cSToke Høiland-Jørgensen 	/* There are a few possible cases here:
26974a1e7c0cSToke Høiland-Jørgensen 	 *
26984a1e7c0cSToke Høiland-Jørgensen 	 * - if prog->aux->dst_trampoline is set, the program was just loaded
26994a1e7c0cSToke Høiland-Jørgensen 	 *   and not yet attached to anything, so we can use the values stored
27004a1e7c0cSToke Høiland-Jørgensen 	 *   in prog->aux
27014a1e7c0cSToke Høiland-Jørgensen 	 *
27024a1e7c0cSToke Høiland-Jørgensen 	 * - if prog->aux->dst_trampoline is NULL, the program has already been
27034a1e7c0cSToke Høiland-Jørgensen          *   attached to a target and its initial target was cleared (below)
27044a1e7c0cSToke Høiland-Jørgensen 	 *
27054a1e7c0cSToke Høiland-Jørgensen 	 * - if tgt_prog != NULL, the caller specified tgt_prog_fd +
27064a1e7c0cSToke Høiland-Jørgensen 	 *   target_btf_id using the link_create API.
27074a1e7c0cSToke Høiland-Jørgensen 	 *
27084a1e7c0cSToke Høiland-Jørgensen 	 * - if tgt_prog == NULL when this function was called using the old
27094a1e7c0cSToke Høiland-Jørgensen          *   raw_tracepoint_open API, and we need a target from prog->aux
27104a1e7c0cSToke Høiland-Jørgensen          *
27114a1e7c0cSToke Høiland-Jørgensen          * The combination of no saved target in prog->aux, and no target
27124a1e7c0cSToke Høiland-Jørgensen          * specified on load is illegal, and we reject that here.
27134a1e7c0cSToke Høiland-Jørgensen 	 */
27144a1e7c0cSToke Høiland-Jørgensen 	if (!prog->aux->dst_trampoline && !tgt_prog) {
27153aac1eadSToke Høiland-Jørgensen 		err = -ENOENT;
27163aac1eadSToke Høiland-Jørgensen 		goto out_unlock;
27173aac1eadSToke Høiland-Jørgensen 	}
27184a1e7c0cSToke Høiland-Jørgensen 
27194a1e7c0cSToke Høiland-Jørgensen 	if (!prog->aux->dst_trampoline ||
27204a1e7c0cSToke Høiland-Jørgensen 	    (key && key != prog->aux->dst_trampoline->key)) {
27214a1e7c0cSToke Høiland-Jørgensen 		/* If there is no saved target, or the specified target is
27224a1e7c0cSToke Høiland-Jørgensen 		 * different from the destination specified at load time, we
27234a1e7c0cSToke Høiland-Jørgensen 		 * need a new trampoline and a check for compatibility
27244a1e7c0cSToke Høiland-Jørgensen 		 */
27254a1e7c0cSToke Høiland-Jørgensen 		struct bpf_attach_target_info tgt_info = {};
27264a1e7c0cSToke Høiland-Jørgensen 
27274a1e7c0cSToke Høiland-Jørgensen 		err = bpf_check_attach_target(NULL, prog, tgt_prog, btf_id,
27284a1e7c0cSToke Høiland-Jørgensen 					      &tgt_info);
27294a1e7c0cSToke Høiland-Jørgensen 		if (err)
27304a1e7c0cSToke Høiland-Jørgensen 			goto out_unlock;
27314a1e7c0cSToke Høiland-Jørgensen 
27324a1e7c0cSToke Høiland-Jørgensen 		tr = bpf_trampoline_get(key, &tgt_info);
27334a1e7c0cSToke Høiland-Jørgensen 		if (!tr) {
27344a1e7c0cSToke Høiland-Jørgensen 			err = -ENOMEM;
27354a1e7c0cSToke Høiland-Jørgensen 			goto out_unlock;
27364a1e7c0cSToke Høiland-Jørgensen 		}
27374a1e7c0cSToke Høiland-Jørgensen 	} else {
27384a1e7c0cSToke Høiland-Jørgensen 		/* The caller didn't specify a target, or the target was the
27394a1e7c0cSToke Høiland-Jørgensen 		 * same as the destination supplied during program load. This
27404a1e7c0cSToke Høiland-Jørgensen 		 * means we can reuse the trampoline and reference from program
27414a1e7c0cSToke Høiland-Jørgensen 		 * load time, and there is no need to allocate a new one. This
27424a1e7c0cSToke Høiland-Jørgensen 		 * can only happen once for any program, as the saved values in
27434a1e7c0cSToke Høiland-Jørgensen 		 * prog->aux are cleared below.
27444a1e7c0cSToke Høiland-Jørgensen 		 */
27453aac1eadSToke Høiland-Jørgensen 		tr = prog->aux->dst_trampoline;
27463aac1eadSToke Høiland-Jørgensen 		tgt_prog = prog->aux->dst_prog;
27474a1e7c0cSToke Høiland-Jørgensen 	}
27483aac1eadSToke Høiland-Jørgensen 
27493aac1eadSToke Høiland-Jørgensen 	err = bpf_link_prime(&link->link, &link_primer);
27503aac1eadSToke Høiland-Jørgensen 	if (err)
27513aac1eadSToke Høiland-Jørgensen 		goto out_unlock;
27523aac1eadSToke Høiland-Jørgensen 
27533aac1eadSToke Høiland-Jørgensen 	err = bpf_trampoline_link_prog(prog, tr);
2754babf3164SAndrii Nakryiko 	if (err) {
2755a3b80e10SAndrii Nakryiko 		bpf_link_cleanup(&link_primer);
27563aac1eadSToke Høiland-Jørgensen 		link = NULL;
27573aac1eadSToke Høiland-Jørgensen 		goto out_unlock;
2758babf3164SAndrii Nakryiko 	}
2759babf3164SAndrii Nakryiko 
27603aac1eadSToke Høiland-Jørgensen 	link->tgt_prog = tgt_prog;
27613aac1eadSToke Høiland-Jørgensen 	link->trampoline = tr;
27623aac1eadSToke Høiland-Jørgensen 
27634a1e7c0cSToke Høiland-Jørgensen 	/* Always clear the trampoline and target prog from prog->aux to make
27644a1e7c0cSToke Høiland-Jørgensen 	 * sure the original attach destination is not kept alive after a
27654a1e7c0cSToke Høiland-Jørgensen 	 * program is (re-)attached to another target.
27664a1e7c0cSToke Høiland-Jørgensen 	 */
27674a1e7c0cSToke Høiland-Jørgensen 	if (prog->aux->dst_prog &&
27684a1e7c0cSToke Høiland-Jørgensen 	    (tgt_prog_fd || tr != prog->aux->dst_trampoline))
27694a1e7c0cSToke Høiland-Jørgensen 		/* got extra prog ref from syscall, or attaching to different prog */
27704a1e7c0cSToke Høiland-Jørgensen 		bpf_prog_put(prog->aux->dst_prog);
27714a1e7c0cSToke Høiland-Jørgensen 	if (prog->aux->dst_trampoline && tr != prog->aux->dst_trampoline)
27724a1e7c0cSToke Høiland-Jørgensen 		/* we allocated a new trampoline, so free the old one */
27734a1e7c0cSToke Høiland-Jørgensen 		bpf_trampoline_put(prog->aux->dst_trampoline);
27744a1e7c0cSToke Høiland-Jørgensen 
27753aac1eadSToke Høiland-Jørgensen 	prog->aux->dst_prog = NULL;
27763aac1eadSToke Høiland-Jørgensen 	prog->aux->dst_trampoline = NULL;
27773aac1eadSToke Høiland-Jørgensen 	mutex_unlock(&prog->aux->dst_mutex);
27783aac1eadSToke Høiland-Jørgensen 
2779a3b80e10SAndrii Nakryiko 	return bpf_link_settle(&link_primer);
27803aac1eadSToke Høiland-Jørgensen out_unlock:
27814a1e7c0cSToke Høiland-Jørgensen 	if (tr && tr != prog->aux->dst_trampoline)
27824a1e7c0cSToke Høiland-Jørgensen 		bpf_trampoline_put(tr);
27833aac1eadSToke Høiland-Jørgensen 	mutex_unlock(&prog->aux->dst_mutex);
27843aac1eadSToke Høiland-Jørgensen 	kfree(link);
2785fec56f58SAlexei Starovoitov out_put_prog:
27864a1e7c0cSToke Høiland-Jørgensen 	if (tgt_prog_fd && tgt_prog)
27874a1e7c0cSToke Høiland-Jørgensen 		bpf_prog_put(tgt_prog);
2788fec56f58SAlexei Starovoitov 	bpf_prog_put(prog);
2789fec56f58SAlexei Starovoitov 	return err;
2790fec56f58SAlexei Starovoitov }
2791fec56f58SAlexei Starovoitov 
279270ed506cSAndrii Nakryiko struct bpf_raw_tp_link {
279370ed506cSAndrii Nakryiko 	struct bpf_link link;
2794c4f6699dSAlexei Starovoitov 	struct bpf_raw_event_map *btp;
2795c4f6699dSAlexei Starovoitov };
2796c4f6699dSAlexei Starovoitov 
279770ed506cSAndrii Nakryiko static void bpf_raw_tp_link_release(struct bpf_link *link)
2798c4f6699dSAlexei Starovoitov {
279970ed506cSAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp =
280070ed506cSAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
2801c4f6699dSAlexei Starovoitov 
280270ed506cSAndrii Nakryiko 	bpf_probe_unregister(raw_tp->btp, raw_tp->link.prog);
2803a38d1107SMatt Mullins 	bpf_put_raw_tracepoint(raw_tp->btp);
2804babf3164SAndrii Nakryiko }
2805babf3164SAndrii Nakryiko 
2806babf3164SAndrii Nakryiko static void bpf_raw_tp_link_dealloc(struct bpf_link *link)
2807babf3164SAndrii Nakryiko {
2808babf3164SAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp =
2809babf3164SAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
2810babf3164SAndrii Nakryiko 
2811c4f6699dSAlexei Starovoitov 	kfree(raw_tp);
2812c4f6699dSAlexei Starovoitov }
2813c4f6699dSAlexei Starovoitov 
2814f2e10bffSAndrii Nakryiko static void bpf_raw_tp_link_show_fdinfo(const struct bpf_link *link,
2815f2e10bffSAndrii Nakryiko 					struct seq_file *seq)
2816f2e10bffSAndrii Nakryiko {
2817f2e10bffSAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp_link =
2818f2e10bffSAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
2819f2e10bffSAndrii Nakryiko 
2820f2e10bffSAndrii Nakryiko 	seq_printf(seq,
2821f2e10bffSAndrii Nakryiko 		   "tp_name:\t%s\n",
2822f2e10bffSAndrii Nakryiko 		   raw_tp_link->btp->tp->name);
2823f2e10bffSAndrii Nakryiko }
2824f2e10bffSAndrii Nakryiko 
2825f2e10bffSAndrii Nakryiko static int bpf_raw_tp_link_fill_link_info(const struct bpf_link *link,
2826f2e10bffSAndrii Nakryiko 					  struct bpf_link_info *info)
2827f2e10bffSAndrii Nakryiko {
2828f2e10bffSAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp_link =
2829f2e10bffSAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
2830f2e10bffSAndrii Nakryiko 	char __user *ubuf = u64_to_user_ptr(info->raw_tracepoint.tp_name);
2831f2e10bffSAndrii Nakryiko 	const char *tp_name = raw_tp_link->btp->tp->name;
2832f2e10bffSAndrii Nakryiko 	u32 ulen = info->raw_tracepoint.tp_name_len;
2833f2e10bffSAndrii Nakryiko 	size_t tp_len = strlen(tp_name);
2834f2e10bffSAndrii Nakryiko 
2835b474959dSYonghong Song 	if (!ulen ^ !ubuf)
2836f2e10bffSAndrii Nakryiko 		return -EINVAL;
2837f2e10bffSAndrii Nakryiko 
2838f2e10bffSAndrii Nakryiko 	info->raw_tracepoint.tp_name_len = tp_len + 1;
2839f2e10bffSAndrii Nakryiko 
2840f2e10bffSAndrii Nakryiko 	if (!ubuf)
2841f2e10bffSAndrii Nakryiko 		return 0;
2842f2e10bffSAndrii Nakryiko 
2843f2e10bffSAndrii Nakryiko 	if (ulen >= tp_len + 1) {
2844f2e10bffSAndrii Nakryiko 		if (copy_to_user(ubuf, tp_name, tp_len + 1))
2845f2e10bffSAndrii Nakryiko 			return -EFAULT;
2846f2e10bffSAndrii Nakryiko 	} else {
2847f2e10bffSAndrii Nakryiko 		char zero = '\0';
2848f2e10bffSAndrii Nakryiko 
2849f2e10bffSAndrii Nakryiko 		if (copy_to_user(ubuf, tp_name, ulen - 1))
2850f2e10bffSAndrii Nakryiko 			return -EFAULT;
2851f2e10bffSAndrii Nakryiko 		if (put_user(zero, ubuf + ulen - 1))
2852f2e10bffSAndrii Nakryiko 			return -EFAULT;
2853f2e10bffSAndrii Nakryiko 		return -ENOSPC;
2854f2e10bffSAndrii Nakryiko 	}
2855f2e10bffSAndrii Nakryiko 
2856f2e10bffSAndrii Nakryiko 	return 0;
2857f2e10bffSAndrii Nakryiko }
2858f2e10bffSAndrii Nakryiko 
2859a3b80e10SAndrii Nakryiko static const struct bpf_link_ops bpf_raw_tp_link_lops = {
286070ed506cSAndrii Nakryiko 	.release = bpf_raw_tp_link_release,
2861babf3164SAndrii Nakryiko 	.dealloc = bpf_raw_tp_link_dealloc,
2862f2e10bffSAndrii Nakryiko 	.show_fdinfo = bpf_raw_tp_link_show_fdinfo,
2863f2e10bffSAndrii Nakryiko 	.fill_link_info = bpf_raw_tp_link_fill_link_info,
2864c4f6699dSAlexei Starovoitov };
2865c4f6699dSAlexei Starovoitov 
2866c4f6699dSAlexei Starovoitov #define BPF_RAW_TRACEPOINT_OPEN_LAST_FIELD raw_tracepoint.prog_fd
2867c4f6699dSAlexei Starovoitov 
2868c4f6699dSAlexei Starovoitov static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
2869c4f6699dSAlexei Starovoitov {
2870a3b80e10SAndrii Nakryiko 	struct bpf_link_primer link_primer;
2871babf3164SAndrii Nakryiko 	struct bpf_raw_tp_link *link;
2872c4f6699dSAlexei Starovoitov 	struct bpf_raw_event_map *btp;
2873c4f6699dSAlexei Starovoitov 	struct bpf_prog *prog;
2874ac4414b5SAlexei Starovoitov 	const char *tp_name;
2875ac4414b5SAlexei Starovoitov 	char buf[128];
2876a3b80e10SAndrii Nakryiko 	int err;
2877c4f6699dSAlexei Starovoitov 
2878ac4414b5SAlexei Starovoitov 	if (CHECK_ATTR(BPF_RAW_TRACEPOINT_OPEN))
2879ac4414b5SAlexei Starovoitov 		return -EINVAL;
2880ac4414b5SAlexei Starovoitov 
2881ac4414b5SAlexei Starovoitov 	prog = bpf_prog_get(attr->raw_tracepoint.prog_fd);
2882ac4414b5SAlexei Starovoitov 	if (IS_ERR(prog))
2883ac4414b5SAlexei Starovoitov 		return PTR_ERR(prog);
2884ac4414b5SAlexei Starovoitov 
28859e4e01dfSKP Singh 	switch (prog->type) {
28869e4e01dfSKP Singh 	case BPF_PROG_TYPE_TRACING:
28879e4e01dfSKP Singh 	case BPF_PROG_TYPE_EXT:
28889e4e01dfSKP Singh 	case BPF_PROG_TYPE_LSM:
2889ac4414b5SAlexei Starovoitov 		if (attr->raw_tracepoint.name) {
2890fec56f58SAlexei Starovoitov 			/* The attach point for this category of programs
2891fec56f58SAlexei Starovoitov 			 * should be specified via btf_id during program load.
2892ac4414b5SAlexei Starovoitov 			 */
2893ac4414b5SAlexei Starovoitov 			err = -EINVAL;
2894ac4414b5SAlexei Starovoitov 			goto out_put_prog;
2895ac4414b5SAlexei Starovoitov 		}
28969e4e01dfSKP Singh 		if (prog->type == BPF_PROG_TYPE_TRACING &&
28979e4e01dfSKP Singh 		    prog->expected_attach_type == BPF_TRACE_RAW_TP) {
289838207291SMartin KaFai Lau 			tp_name = prog->aux->attach_func_name;
28999e4e01dfSKP Singh 			break;
29009e4e01dfSKP Singh 		}
29014a1e7c0cSToke Høiland-Jørgensen 		return bpf_tracing_prog_attach(prog, 0, 0);
29029e4e01dfSKP Singh 	case BPF_PROG_TYPE_RAW_TRACEPOINT:
29039e4e01dfSKP Singh 	case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
2904ac4414b5SAlexei Starovoitov 		if (strncpy_from_user(buf,
2905ac4414b5SAlexei Starovoitov 				      u64_to_user_ptr(attr->raw_tracepoint.name),
2906ac4414b5SAlexei Starovoitov 				      sizeof(buf) - 1) < 0) {
2907ac4414b5SAlexei Starovoitov 			err = -EFAULT;
2908ac4414b5SAlexei Starovoitov 			goto out_put_prog;
2909ac4414b5SAlexei Starovoitov 		}
2910ac4414b5SAlexei Starovoitov 		buf[sizeof(buf) - 1] = 0;
2911ac4414b5SAlexei Starovoitov 		tp_name = buf;
29129e4e01dfSKP Singh 		break;
29139e4e01dfSKP Singh 	default:
29149e4e01dfSKP Singh 		err = -EINVAL;
29159e4e01dfSKP Singh 		goto out_put_prog;
2916ac4414b5SAlexei Starovoitov 	}
2917c4f6699dSAlexei Starovoitov 
2918a38d1107SMatt Mullins 	btp = bpf_get_raw_tracepoint(tp_name);
2919ac4414b5SAlexei Starovoitov 	if (!btp) {
2920ac4414b5SAlexei Starovoitov 		err = -ENOENT;
2921ac4414b5SAlexei Starovoitov 		goto out_put_prog;
2922ac4414b5SAlexei Starovoitov 	}
2923c4f6699dSAlexei Starovoitov 
2924babf3164SAndrii Nakryiko 	link = kzalloc(sizeof(*link), GFP_USER);
2925babf3164SAndrii Nakryiko 	if (!link) {
2926a38d1107SMatt Mullins 		err = -ENOMEM;
2927a38d1107SMatt Mullins 		goto out_put_btp;
2928a38d1107SMatt Mullins 	}
2929f2e10bffSAndrii Nakryiko 	bpf_link_init(&link->link, BPF_LINK_TYPE_RAW_TRACEPOINT,
2930f2e10bffSAndrii Nakryiko 		      &bpf_raw_tp_link_lops, prog);
2931babf3164SAndrii Nakryiko 	link->btp = btp;
2932c4f6699dSAlexei Starovoitov 
2933a3b80e10SAndrii Nakryiko 	err = bpf_link_prime(&link->link, &link_primer);
2934a3b80e10SAndrii Nakryiko 	if (err) {
2935babf3164SAndrii Nakryiko 		kfree(link);
2936babf3164SAndrii Nakryiko 		goto out_put_btp;
2937c4f6699dSAlexei Starovoitov 	}
2938babf3164SAndrii Nakryiko 
2939babf3164SAndrii Nakryiko 	err = bpf_probe_register(link->btp, prog);
2940babf3164SAndrii Nakryiko 	if (err) {
2941a3b80e10SAndrii Nakryiko 		bpf_link_cleanup(&link_primer);
2942babf3164SAndrii Nakryiko 		goto out_put_btp;
2943babf3164SAndrii Nakryiko 	}
2944babf3164SAndrii Nakryiko 
2945a3b80e10SAndrii Nakryiko 	return bpf_link_settle(&link_primer);
2946c4f6699dSAlexei Starovoitov 
2947a38d1107SMatt Mullins out_put_btp:
2948a38d1107SMatt Mullins 	bpf_put_raw_tracepoint(btp);
2949ac4414b5SAlexei Starovoitov out_put_prog:
2950ac4414b5SAlexei Starovoitov 	bpf_prog_put(prog);
2951c4f6699dSAlexei Starovoitov 	return err;
2952c4f6699dSAlexei Starovoitov }
2953c4f6699dSAlexei Starovoitov 
295433491588SAnders Roxell static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog,
295533491588SAnders Roxell 					     enum bpf_attach_type attach_type)
295633491588SAnders Roxell {
295733491588SAnders Roxell 	switch (prog->type) {
295833491588SAnders Roxell 	case BPF_PROG_TYPE_CGROUP_SOCK:
295933491588SAnders Roxell 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
29600d01da6aSStanislav Fomichev 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
2961e9ddbb77SJakub Sitnicki 	case BPF_PROG_TYPE_SK_LOOKUP:
296233491588SAnders Roxell 		return attach_type == prog->expected_attach_type ? 0 : -EINVAL;
29635cf1e914Sbrakmo 	case BPF_PROG_TYPE_CGROUP_SKB:
29642c78ee89SAlexei Starovoitov 		if (!capable(CAP_NET_ADMIN))
29652c78ee89SAlexei Starovoitov 			/* cg-skb progs can be loaded by unpriv user.
29662c78ee89SAlexei Starovoitov 			 * check permissions at attach time.
29672c78ee89SAlexei Starovoitov 			 */
29682c78ee89SAlexei Starovoitov 			return -EPERM;
29695cf1e914Sbrakmo 		return prog->enforce_expected_attach_type &&
29705cf1e914Sbrakmo 			prog->expected_attach_type != attach_type ?
29715cf1e914Sbrakmo 			-EINVAL : 0;
297233491588SAnders Roxell 	default:
297333491588SAnders Roxell 		return 0;
297433491588SAnders Roxell 	}
297533491588SAnders Roxell }
297633491588SAnders Roxell 
2977e28784e3SAndrii Nakryiko static enum bpf_prog_type
2978e28784e3SAndrii Nakryiko attach_type_to_prog_type(enum bpf_attach_type attach_type)
2979e28784e3SAndrii Nakryiko {
2980e28784e3SAndrii Nakryiko 	switch (attach_type) {
2981e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET_INGRESS:
2982e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET_EGRESS:
2983e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SKB;
2984e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET_SOCK_CREATE:
2985f5836749SStanislav Fomichev 	case BPF_CGROUP_INET_SOCK_RELEASE:
2986e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET4_POST_BIND:
2987e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET6_POST_BIND:
2988e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SOCK;
2989e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET4_BIND:
2990e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET6_BIND:
2991e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET4_CONNECT:
2992e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET6_CONNECT:
29931b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETPEERNAME:
29941b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETPEERNAME:
29951b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETSOCKNAME:
29961b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETSOCKNAME:
2997e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP4_SENDMSG:
2998e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP6_SENDMSG:
2999e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP4_RECVMSG:
3000e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP6_RECVMSG:
3001e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
3002e28784e3SAndrii Nakryiko 	case BPF_CGROUP_SOCK_OPS:
3003e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_SOCK_OPS;
3004e28784e3SAndrii Nakryiko 	case BPF_CGROUP_DEVICE:
3005e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_DEVICE;
3006e28784e3SAndrii Nakryiko 	case BPF_SK_MSG_VERDICT:
3007e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_SK_MSG;
3008e28784e3SAndrii Nakryiko 	case BPF_SK_SKB_STREAM_PARSER:
3009e28784e3SAndrii Nakryiko 	case BPF_SK_SKB_STREAM_VERDICT:
3010e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_SK_SKB;
3011e28784e3SAndrii Nakryiko 	case BPF_LIRC_MODE2:
3012e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_LIRC_MODE2;
3013e28784e3SAndrii Nakryiko 	case BPF_FLOW_DISSECTOR:
3014e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_FLOW_DISSECTOR;
3015e28784e3SAndrii Nakryiko 	case BPF_CGROUP_SYSCTL:
3016e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SYSCTL;
3017e28784e3SAndrii Nakryiko 	case BPF_CGROUP_GETSOCKOPT:
3018e28784e3SAndrii Nakryiko 	case BPF_CGROUP_SETSOCKOPT:
3019e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SOCKOPT;
3020de4e05caSYonghong Song 	case BPF_TRACE_ITER:
3021de4e05caSYonghong Song 		return BPF_PROG_TYPE_TRACING;
3022e9ddbb77SJakub Sitnicki 	case BPF_SK_LOOKUP:
3023e9ddbb77SJakub Sitnicki 		return BPF_PROG_TYPE_SK_LOOKUP;
3024aa8d3a71SAndrii Nakryiko 	case BPF_XDP:
3025aa8d3a71SAndrii Nakryiko 		return BPF_PROG_TYPE_XDP;
3026e28784e3SAndrii Nakryiko 	default:
3027e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_UNSPEC;
3028e28784e3SAndrii Nakryiko 	}
3029e28784e3SAndrii Nakryiko }
3030e28784e3SAndrii Nakryiko 
30317dd68b32SAndrey Ignatov #define BPF_PROG_ATTACH_LAST_FIELD replace_bpf_fd
3032174a79ffSJohn Fastabend 
3033324bda9eSAlexei Starovoitov #define BPF_F_ATTACH_MASK \
30347dd68b32SAndrey Ignatov 	(BPF_F_ALLOW_OVERRIDE | BPF_F_ALLOW_MULTI | BPF_F_REPLACE)
3035324bda9eSAlexei Starovoitov 
3036f4324551SDaniel Mack static int bpf_prog_attach(const union bpf_attr *attr)
3037f4324551SDaniel Mack {
30387f677633SAlexei Starovoitov 	enum bpf_prog_type ptype;
3039f4324551SDaniel Mack 	struct bpf_prog *prog;
30407f677633SAlexei Starovoitov 	int ret;
3041f4324551SDaniel Mack 
3042f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_ATTACH))
3043f4324551SDaniel Mack 		return -EINVAL;
3044f4324551SDaniel Mack 
3045324bda9eSAlexei Starovoitov 	if (attr->attach_flags & ~BPF_F_ATTACH_MASK)
30467f677633SAlexei Starovoitov 		return -EINVAL;
30477f677633SAlexei Starovoitov 
3048e28784e3SAndrii Nakryiko 	ptype = attach_type_to_prog_type(attr->attach_type);
3049e28784e3SAndrii Nakryiko 	if (ptype == BPF_PROG_TYPE_UNSPEC)
3050b2cd1257SDavid Ahern 		return -EINVAL;
3051b2cd1257SDavid Ahern 
3052b2cd1257SDavid Ahern 	prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
3053f4324551SDaniel Mack 	if (IS_ERR(prog))
3054f4324551SDaniel Mack 		return PTR_ERR(prog);
3055f4324551SDaniel Mack 
30565e43f899SAndrey Ignatov 	if (bpf_prog_attach_check_attach_type(prog, attr->attach_type)) {
30575e43f899SAndrey Ignatov 		bpf_prog_put(prog);
30585e43f899SAndrey Ignatov 		return -EINVAL;
30595e43f899SAndrey Ignatov 	}
30605e43f899SAndrey Ignatov 
3061fdb5c453SSean Young 	switch (ptype) {
3062fdb5c453SSean Young 	case BPF_PROG_TYPE_SK_SKB:
3063fdb5c453SSean Young 	case BPF_PROG_TYPE_SK_MSG:
3064604326b4SDaniel Borkmann 		ret = sock_map_get_from_fd(attr, prog);
3065fdb5c453SSean Young 		break;
3066fdb5c453SSean Young 	case BPF_PROG_TYPE_LIRC_MODE2:
3067fdb5c453SSean Young 		ret = lirc_prog_attach(attr, prog);
3068fdb5c453SSean Young 		break;
3069d58e468bSPetar Penkov 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
3070a3fd7ceeSJakub Sitnicki 		ret = netns_bpf_prog_attach(attr, prog);
3071d58e468bSPetar Penkov 		break;
3072e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_DEVICE:
3073e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SKB:
3074e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK:
3075e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
3076e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
3077e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
3078e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SOCK_OPS:
3079fdb5c453SSean Young 		ret = cgroup_bpf_prog_attach(attr, ptype, prog);
3080e28784e3SAndrii Nakryiko 		break;
3081e28784e3SAndrii Nakryiko 	default:
3082e28784e3SAndrii Nakryiko 		ret = -EINVAL;
3083f4324551SDaniel Mack 	}
3084f4324551SDaniel Mack 
30857f677633SAlexei Starovoitov 	if (ret)
30867f677633SAlexei Starovoitov 		bpf_prog_put(prog);
30877f677633SAlexei Starovoitov 	return ret;
3088f4324551SDaniel Mack }
3089f4324551SDaniel Mack 
3090f4324551SDaniel Mack #define BPF_PROG_DETACH_LAST_FIELD attach_type
3091f4324551SDaniel Mack 
3092f4324551SDaniel Mack static int bpf_prog_detach(const union bpf_attr *attr)
3093f4324551SDaniel Mack {
3094324bda9eSAlexei Starovoitov 	enum bpf_prog_type ptype;
3095f4324551SDaniel Mack 
3096f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_DETACH))
3097f4324551SDaniel Mack 		return -EINVAL;
3098f4324551SDaniel Mack 
3099e28784e3SAndrii Nakryiko 	ptype = attach_type_to_prog_type(attr->attach_type);
3100e28784e3SAndrii Nakryiko 
3101e28784e3SAndrii Nakryiko 	switch (ptype) {
3102e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SK_MSG:
3103e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SK_SKB:
3104bb0de313SLorenz Bauer 		return sock_map_prog_detach(attr, ptype);
3105e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_LIRC_MODE2:
3106f4364dcfSSean Young 		return lirc_prog_detach(attr);
3107e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
31084ac2add6SLorenz Bauer 		return netns_bpf_prog_detach(attr, ptype);
3109e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_DEVICE:
3110e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SKB:
3111e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK:
3112e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
3113e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
3114e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
3115e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SOCK_OPS:
3116e28784e3SAndrii Nakryiko 		return cgroup_bpf_prog_detach(attr, ptype);
3117f4324551SDaniel Mack 	default:
3118f4324551SDaniel Mack 		return -EINVAL;
3119f4324551SDaniel Mack 	}
3120f4324551SDaniel Mack }
312140304b2aSLawrence Brakmo 
3122468e2f64SAlexei Starovoitov #define BPF_PROG_QUERY_LAST_FIELD query.prog_cnt
3123468e2f64SAlexei Starovoitov 
3124468e2f64SAlexei Starovoitov static int bpf_prog_query(const union bpf_attr *attr,
3125468e2f64SAlexei Starovoitov 			  union bpf_attr __user *uattr)
3126468e2f64SAlexei Starovoitov {
3127468e2f64SAlexei Starovoitov 	if (!capable(CAP_NET_ADMIN))
3128468e2f64SAlexei Starovoitov 		return -EPERM;
3129468e2f64SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_QUERY))
3130468e2f64SAlexei Starovoitov 		return -EINVAL;
3131468e2f64SAlexei Starovoitov 	if (attr->query.query_flags & ~BPF_F_QUERY_EFFECTIVE)
3132468e2f64SAlexei Starovoitov 		return -EINVAL;
3133468e2f64SAlexei Starovoitov 
3134468e2f64SAlexei Starovoitov 	switch (attr->query.attach_type) {
3135468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_INGRESS:
3136468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_EGRESS:
3137468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_SOCK_CREATE:
3138f5836749SStanislav Fomichev 	case BPF_CGROUP_INET_SOCK_RELEASE:
31394fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET4_BIND:
31404fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET6_BIND:
3141aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET4_POST_BIND:
3142aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET6_POST_BIND:
3143d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET4_CONNECT:
3144d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET6_CONNECT:
31451b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETPEERNAME:
31461b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETPEERNAME:
31471b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETSOCKNAME:
31481b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETSOCKNAME:
31491cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP4_SENDMSG:
31501cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP6_SENDMSG:
3151983695faSDaniel Borkmann 	case BPF_CGROUP_UDP4_RECVMSG:
3152983695faSDaniel Borkmann 	case BPF_CGROUP_UDP6_RECVMSG:
3153468e2f64SAlexei Starovoitov 	case BPF_CGROUP_SOCK_OPS:
3154ebc614f6SRoman Gushchin 	case BPF_CGROUP_DEVICE:
31557b146cebSAndrey Ignatov 	case BPF_CGROUP_SYSCTL:
31560d01da6aSStanislav Fomichev 	case BPF_CGROUP_GETSOCKOPT:
31570d01da6aSStanislav Fomichev 	case BPF_CGROUP_SETSOCKOPT:
3158e28784e3SAndrii Nakryiko 		return cgroup_bpf_prog_query(attr, uattr);
3159f4364dcfSSean Young 	case BPF_LIRC_MODE2:
3160f4364dcfSSean Young 		return lirc_prog_query(attr, uattr);
3161118c8e9aSStanislav Fomichev 	case BPF_FLOW_DISSECTOR:
3162e9ddbb77SJakub Sitnicki 	case BPF_SK_LOOKUP:
3163a3fd7ceeSJakub Sitnicki 		return netns_bpf_prog_query(attr, uattr);
3164468e2f64SAlexei Starovoitov 	default:
3165468e2f64SAlexei Starovoitov 		return -EINVAL;
3166468e2f64SAlexei Starovoitov 	}
3167468e2f64SAlexei Starovoitov }
3168f4324551SDaniel Mack 
31691b4d60ecSSong Liu #define BPF_PROG_TEST_RUN_LAST_FIELD test.cpu
31701cf1cae9SAlexei Starovoitov 
31711cf1cae9SAlexei Starovoitov static int bpf_prog_test_run(const union bpf_attr *attr,
31721cf1cae9SAlexei Starovoitov 			     union bpf_attr __user *uattr)
31731cf1cae9SAlexei Starovoitov {
31741cf1cae9SAlexei Starovoitov 	struct bpf_prog *prog;
31751cf1cae9SAlexei Starovoitov 	int ret = -ENOTSUPP;
31761cf1cae9SAlexei Starovoitov 
31771cf1cae9SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_TEST_RUN))
31781cf1cae9SAlexei Starovoitov 		return -EINVAL;
31791cf1cae9SAlexei Starovoitov 
3180b0b9395dSStanislav Fomichev 	if ((attr->test.ctx_size_in && !attr->test.ctx_in) ||
3181b0b9395dSStanislav Fomichev 	    (!attr->test.ctx_size_in && attr->test.ctx_in))
3182b0b9395dSStanislav Fomichev 		return -EINVAL;
3183b0b9395dSStanislav Fomichev 
3184b0b9395dSStanislav Fomichev 	if ((attr->test.ctx_size_out && !attr->test.ctx_out) ||
3185b0b9395dSStanislav Fomichev 	    (!attr->test.ctx_size_out && attr->test.ctx_out))
3186b0b9395dSStanislav Fomichev 		return -EINVAL;
3187b0b9395dSStanislav Fomichev 
31881cf1cae9SAlexei Starovoitov 	prog = bpf_prog_get(attr->test.prog_fd);
31891cf1cae9SAlexei Starovoitov 	if (IS_ERR(prog))
31901cf1cae9SAlexei Starovoitov 		return PTR_ERR(prog);
31911cf1cae9SAlexei Starovoitov 
31921cf1cae9SAlexei Starovoitov 	if (prog->aux->ops->test_run)
31931cf1cae9SAlexei Starovoitov 		ret = prog->aux->ops->test_run(prog, attr, uattr);
31941cf1cae9SAlexei Starovoitov 
31951cf1cae9SAlexei Starovoitov 	bpf_prog_put(prog);
31961cf1cae9SAlexei Starovoitov 	return ret;
31971cf1cae9SAlexei Starovoitov }
31981cf1cae9SAlexei Starovoitov 
319934ad5580SMartin KaFai Lau #define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id
320034ad5580SMartin KaFai Lau 
320134ad5580SMartin KaFai Lau static int bpf_obj_get_next_id(const union bpf_attr *attr,
320234ad5580SMartin KaFai Lau 			       union bpf_attr __user *uattr,
320334ad5580SMartin KaFai Lau 			       struct idr *idr,
320434ad5580SMartin KaFai Lau 			       spinlock_t *lock)
320534ad5580SMartin KaFai Lau {
320634ad5580SMartin KaFai Lau 	u32 next_id = attr->start_id;
320734ad5580SMartin KaFai Lau 	int err = 0;
320834ad5580SMartin KaFai Lau 
320934ad5580SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX)
321034ad5580SMartin KaFai Lau 		return -EINVAL;
321134ad5580SMartin KaFai Lau 
321234ad5580SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
321334ad5580SMartin KaFai Lau 		return -EPERM;
321434ad5580SMartin KaFai Lau 
321534ad5580SMartin KaFai Lau 	next_id++;
321634ad5580SMartin KaFai Lau 	spin_lock_bh(lock);
321734ad5580SMartin KaFai Lau 	if (!idr_get_next(idr, &next_id))
321834ad5580SMartin KaFai Lau 		err = -ENOENT;
321934ad5580SMartin KaFai Lau 	spin_unlock_bh(lock);
322034ad5580SMartin KaFai Lau 
322134ad5580SMartin KaFai Lau 	if (!err)
322234ad5580SMartin KaFai Lau 		err = put_user(next_id, &uattr->next_id);
322334ad5580SMartin KaFai Lau 
322434ad5580SMartin KaFai Lau 	return err;
322534ad5580SMartin KaFai Lau }
322634ad5580SMartin KaFai Lau 
32276086d29dSYonghong Song struct bpf_map *bpf_map_get_curr_or_next(u32 *id)
32286086d29dSYonghong Song {
32296086d29dSYonghong Song 	struct bpf_map *map;
32306086d29dSYonghong Song 
32316086d29dSYonghong Song 	spin_lock_bh(&map_idr_lock);
32326086d29dSYonghong Song again:
32336086d29dSYonghong Song 	map = idr_get_next(&map_idr, id);
32346086d29dSYonghong Song 	if (map) {
32356086d29dSYonghong Song 		map = __bpf_map_inc_not_zero(map, false);
32366086d29dSYonghong Song 		if (IS_ERR(map)) {
32376086d29dSYonghong Song 			(*id)++;
32386086d29dSYonghong Song 			goto again;
32396086d29dSYonghong Song 		}
32406086d29dSYonghong Song 	}
32416086d29dSYonghong Song 	spin_unlock_bh(&map_idr_lock);
32426086d29dSYonghong Song 
32436086d29dSYonghong Song 	return map;
32446086d29dSYonghong Song }
32456086d29dSYonghong Song 
3246a228a64fSAlexei Starovoitov struct bpf_prog *bpf_prog_get_curr_or_next(u32 *id)
3247a228a64fSAlexei Starovoitov {
3248a228a64fSAlexei Starovoitov 	struct bpf_prog *prog;
3249a228a64fSAlexei Starovoitov 
3250a228a64fSAlexei Starovoitov 	spin_lock_bh(&prog_idr_lock);
3251a228a64fSAlexei Starovoitov again:
3252a228a64fSAlexei Starovoitov 	prog = idr_get_next(&prog_idr, id);
3253a228a64fSAlexei Starovoitov 	if (prog) {
3254a228a64fSAlexei Starovoitov 		prog = bpf_prog_inc_not_zero(prog);
3255a228a64fSAlexei Starovoitov 		if (IS_ERR(prog)) {
3256a228a64fSAlexei Starovoitov 			(*id)++;
3257a228a64fSAlexei Starovoitov 			goto again;
3258a228a64fSAlexei Starovoitov 		}
3259a228a64fSAlexei Starovoitov 	}
3260a228a64fSAlexei Starovoitov 	spin_unlock_bh(&prog_idr_lock);
3261a228a64fSAlexei Starovoitov 
3262a228a64fSAlexei Starovoitov 	return prog;
3263a228a64fSAlexei Starovoitov }
3264a228a64fSAlexei Starovoitov 
3265b16d9aa4SMartin KaFai Lau #define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id
3266b16d9aa4SMartin KaFai Lau 
32677e6897f9SBjörn Töpel struct bpf_prog *bpf_prog_by_id(u32 id)
32687e6897f9SBjörn Töpel {
32697e6897f9SBjörn Töpel 	struct bpf_prog *prog;
32707e6897f9SBjörn Töpel 
32717e6897f9SBjörn Töpel 	if (!id)
32727e6897f9SBjörn Töpel 		return ERR_PTR(-ENOENT);
32737e6897f9SBjörn Töpel 
32747e6897f9SBjörn Töpel 	spin_lock_bh(&prog_idr_lock);
32757e6897f9SBjörn Töpel 	prog = idr_find(&prog_idr, id);
32767e6897f9SBjörn Töpel 	if (prog)
32777e6897f9SBjörn Töpel 		prog = bpf_prog_inc_not_zero(prog);
32787e6897f9SBjörn Töpel 	else
32797e6897f9SBjörn Töpel 		prog = ERR_PTR(-ENOENT);
32807e6897f9SBjörn Töpel 	spin_unlock_bh(&prog_idr_lock);
32817e6897f9SBjörn Töpel 	return prog;
32827e6897f9SBjörn Töpel }
32837e6897f9SBjörn Töpel 
3284b16d9aa4SMartin KaFai Lau static int bpf_prog_get_fd_by_id(const union bpf_attr *attr)
3285b16d9aa4SMartin KaFai Lau {
3286b16d9aa4SMartin KaFai Lau 	struct bpf_prog *prog;
3287b16d9aa4SMartin KaFai Lau 	u32 id = attr->prog_id;
3288b16d9aa4SMartin KaFai Lau 	int fd;
3289b16d9aa4SMartin KaFai Lau 
3290b16d9aa4SMartin KaFai Lau 	if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID))
3291b16d9aa4SMartin KaFai Lau 		return -EINVAL;
3292b16d9aa4SMartin KaFai Lau 
3293b16d9aa4SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
3294b16d9aa4SMartin KaFai Lau 		return -EPERM;
3295b16d9aa4SMartin KaFai Lau 
32967e6897f9SBjörn Töpel 	prog = bpf_prog_by_id(id);
3297b16d9aa4SMartin KaFai Lau 	if (IS_ERR(prog))
3298b16d9aa4SMartin KaFai Lau 		return PTR_ERR(prog);
3299b16d9aa4SMartin KaFai Lau 
3300b16d9aa4SMartin KaFai Lau 	fd = bpf_prog_new_fd(prog);
3301b16d9aa4SMartin KaFai Lau 	if (fd < 0)
3302b16d9aa4SMartin KaFai Lau 		bpf_prog_put(prog);
3303b16d9aa4SMartin KaFai Lau 
3304b16d9aa4SMartin KaFai Lau 	return fd;
3305b16d9aa4SMartin KaFai Lau }
3306b16d9aa4SMartin KaFai Lau 
33076e71b04aSChenbo Feng #define BPF_MAP_GET_FD_BY_ID_LAST_FIELD open_flags
3308bd5f5f4eSMartin KaFai Lau 
3309bd5f5f4eSMartin KaFai Lau static int bpf_map_get_fd_by_id(const union bpf_attr *attr)
3310bd5f5f4eSMartin KaFai Lau {
3311bd5f5f4eSMartin KaFai Lau 	struct bpf_map *map;
3312bd5f5f4eSMartin KaFai Lau 	u32 id = attr->map_id;
33136e71b04aSChenbo Feng 	int f_flags;
3314bd5f5f4eSMartin KaFai Lau 	int fd;
3315bd5f5f4eSMartin KaFai Lau 
33166e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_MAP_GET_FD_BY_ID) ||
33176e71b04aSChenbo Feng 	    attr->open_flags & ~BPF_OBJ_FLAG_MASK)
3318bd5f5f4eSMartin KaFai Lau 		return -EINVAL;
3319bd5f5f4eSMartin KaFai Lau 
3320bd5f5f4eSMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
3321bd5f5f4eSMartin KaFai Lau 		return -EPERM;
3322bd5f5f4eSMartin KaFai Lau 
33236e71b04aSChenbo Feng 	f_flags = bpf_get_file_flag(attr->open_flags);
33246e71b04aSChenbo Feng 	if (f_flags < 0)
33256e71b04aSChenbo Feng 		return f_flags;
33266e71b04aSChenbo Feng 
3327bd5f5f4eSMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
3328bd5f5f4eSMartin KaFai Lau 	map = idr_find(&map_idr, id);
3329bd5f5f4eSMartin KaFai Lau 	if (map)
3330b0e4701cSStanislav Fomichev 		map = __bpf_map_inc_not_zero(map, true);
3331bd5f5f4eSMartin KaFai Lau 	else
3332bd5f5f4eSMartin KaFai Lau 		map = ERR_PTR(-ENOENT);
3333bd5f5f4eSMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
3334bd5f5f4eSMartin KaFai Lau 
3335bd5f5f4eSMartin KaFai Lau 	if (IS_ERR(map))
3336bd5f5f4eSMartin KaFai Lau 		return PTR_ERR(map);
3337bd5f5f4eSMartin KaFai Lau 
33386e71b04aSChenbo Feng 	fd = bpf_map_new_fd(map, f_flags);
3339bd5f5f4eSMartin KaFai Lau 	if (fd < 0)
3340781e6282SPeng Sun 		bpf_map_put_with_uref(map);
3341bd5f5f4eSMartin KaFai Lau 
3342bd5f5f4eSMartin KaFai Lau 	return fd;
3343bd5f5f4eSMartin KaFai Lau }
3344bd5f5f4eSMartin KaFai Lau 
33457105e828SDaniel Borkmann static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog,
3346d8eca5bbSDaniel Borkmann 					      unsigned long addr, u32 *off,
3347d8eca5bbSDaniel Borkmann 					      u32 *type)
33487105e828SDaniel Borkmann {
3349d8eca5bbSDaniel Borkmann 	const struct bpf_map *map;
33507105e828SDaniel Borkmann 	int i;
33517105e828SDaniel Borkmann 
3352984fe94fSYiFei Zhu 	mutex_lock(&prog->aux->used_maps_mutex);
3353d8eca5bbSDaniel Borkmann 	for (i = 0, *off = 0; i < prog->aux->used_map_cnt; i++) {
3354d8eca5bbSDaniel Borkmann 		map = prog->aux->used_maps[i];
3355d8eca5bbSDaniel Borkmann 		if (map == (void *)addr) {
3356d8eca5bbSDaniel Borkmann 			*type = BPF_PSEUDO_MAP_FD;
3357984fe94fSYiFei Zhu 			goto out;
3358d8eca5bbSDaniel Borkmann 		}
3359d8eca5bbSDaniel Borkmann 		if (!map->ops->map_direct_value_meta)
3360d8eca5bbSDaniel Borkmann 			continue;
3361d8eca5bbSDaniel Borkmann 		if (!map->ops->map_direct_value_meta(map, addr, off)) {
3362d8eca5bbSDaniel Borkmann 			*type = BPF_PSEUDO_MAP_VALUE;
3363984fe94fSYiFei Zhu 			goto out;
3364d8eca5bbSDaniel Borkmann 		}
3365d8eca5bbSDaniel Borkmann 	}
3366984fe94fSYiFei Zhu 	map = NULL;
3367d8eca5bbSDaniel Borkmann 
3368984fe94fSYiFei Zhu out:
3369984fe94fSYiFei Zhu 	mutex_unlock(&prog->aux->used_maps_mutex);
3370984fe94fSYiFei Zhu 	return map;
33717105e828SDaniel Borkmann }
33727105e828SDaniel Borkmann 
337363960260SKees Cook static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog,
337463960260SKees Cook 					      const struct cred *f_cred)
33757105e828SDaniel Borkmann {
33767105e828SDaniel Borkmann 	const struct bpf_map *map;
33777105e828SDaniel Borkmann 	struct bpf_insn *insns;
3378d8eca5bbSDaniel Borkmann 	u32 off, type;
33797105e828SDaniel Borkmann 	u64 imm;
338029fcb05bSAndrii Nakryiko 	u8 code;
33817105e828SDaniel Borkmann 	int i;
33827105e828SDaniel Borkmann 
33837105e828SDaniel Borkmann 	insns = kmemdup(prog->insnsi, bpf_prog_insn_size(prog),
33847105e828SDaniel Borkmann 			GFP_USER);
33857105e828SDaniel Borkmann 	if (!insns)
33867105e828SDaniel Borkmann 		return insns;
33877105e828SDaniel Borkmann 
33887105e828SDaniel Borkmann 	for (i = 0; i < prog->len; i++) {
338929fcb05bSAndrii Nakryiko 		code = insns[i].code;
339029fcb05bSAndrii Nakryiko 
339129fcb05bSAndrii Nakryiko 		if (code == (BPF_JMP | BPF_TAIL_CALL)) {
33927105e828SDaniel Borkmann 			insns[i].code = BPF_JMP | BPF_CALL;
33937105e828SDaniel Borkmann 			insns[i].imm = BPF_FUNC_tail_call;
33947105e828SDaniel Borkmann 			/* fall-through */
33957105e828SDaniel Borkmann 		}
339629fcb05bSAndrii Nakryiko 		if (code == (BPF_JMP | BPF_CALL) ||
339729fcb05bSAndrii Nakryiko 		    code == (BPF_JMP | BPF_CALL_ARGS)) {
339829fcb05bSAndrii Nakryiko 			if (code == (BPF_JMP | BPF_CALL_ARGS))
33997105e828SDaniel Borkmann 				insns[i].code = BPF_JMP | BPF_CALL;
340063960260SKees Cook 			if (!bpf_dump_raw_ok(f_cred))
34017105e828SDaniel Borkmann 				insns[i].imm = 0;
34027105e828SDaniel Borkmann 			continue;
34037105e828SDaniel Borkmann 		}
340429fcb05bSAndrii Nakryiko 		if (BPF_CLASS(code) == BPF_LDX && BPF_MODE(code) == BPF_PROBE_MEM) {
340529fcb05bSAndrii Nakryiko 			insns[i].code = BPF_LDX | BPF_SIZE(code) | BPF_MEM;
340629fcb05bSAndrii Nakryiko 			continue;
340729fcb05bSAndrii Nakryiko 		}
34087105e828SDaniel Borkmann 
340929fcb05bSAndrii Nakryiko 		if (code != (BPF_LD | BPF_IMM | BPF_DW))
34107105e828SDaniel Borkmann 			continue;
34117105e828SDaniel Borkmann 
34127105e828SDaniel Borkmann 		imm = ((u64)insns[i + 1].imm << 32) | (u32)insns[i].imm;
3413d8eca5bbSDaniel Borkmann 		map = bpf_map_from_imm(prog, imm, &off, &type);
34147105e828SDaniel Borkmann 		if (map) {
3415d8eca5bbSDaniel Borkmann 			insns[i].src_reg = type;
34167105e828SDaniel Borkmann 			insns[i].imm = map->id;
3417d8eca5bbSDaniel Borkmann 			insns[i + 1].imm = off;
34187105e828SDaniel Borkmann 			continue;
34197105e828SDaniel Borkmann 		}
34207105e828SDaniel Borkmann 	}
34217105e828SDaniel Borkmann 
34227105e828SDaniel Borkmann 	return insns;
34237105e828SDaniel Borkmann }
34247105e828SDaniel Borkmann 
3425c454a46bSMartin KaFai Lau static int set_info_rec_size(struct bpf_prog_info *info)
3426c454a46bSMartin KaFai Lau {
3427c454a46bSMartin KaFai Lau 	/*
3428c454a46bSMartin KaFai Lau 	 * Ensure info.*_rec_size is the same as kernel expected size
3429c454a46bSMartin KaFai Lau 	 *
3430c454a46bSMartin KaFai Lau 	 * or
3431c454a46bSMartin KaFai Lau 	 *
3432c454a46bSMartin KaFai Lau 	 * Only allow zero *_rec_size if both _rec_size and _cnt are
3433c454a46bSMartin KaFai Lau 	 * zero.  In this case, the kernel will set the expected
3434c454a46bSMartin KaFai Lau 	 * _rec_size back to the info.
3435c454a46bSMartin KaFai Lau 	 */
3436c454a46bSMartin KaFai Lau 
343711d8b82dSYonghong Song 	if ((info->nr_func_info || info->func_info_rec_size) &&
3438c454a46bSMartin KaFai Lau 	    info->func_info_rec_size != sizeof(struct bpf_func_info))
3439c454a46bSMartin KaFai Lau 		return -EINVAL;
3440c454a46bSMartin KaFai Lau 
344111d8b82dSYonghong Song 	if ((info->nr_line_info || info->line_info_rec_size) &&
3442c454a46bSMartin KaFai Lau 	    info->line_info_rec_size != sizeof(struct bpf_line_info))
3443c454a46bSMartin KaFai Lau 		return -EINVAL;
3444c454a46bSMartin KaFai Lau 
344511d8b82dSYonghong Song 	if ((info->nr_jited_line_info || info->jited_line_info_rec_size) &&
3446c454a46bSMartin KaFai Lau 	    info->jited_line_info_rec_size != sizeof(__u64))
3447c454a46bSMartin KaFai Lau 		return -EINVAL;
3448c454a46bSMartin KaFai Lau 
3449c454a46bSMartin KaFai Lau 	info->func_info_rec_size = sizeof(struct bpf_func_info);
3450c454a46bSMartin KaFai Lau 	info->line_info_rec_size = sizeof(struct bpf_line_info);
3451c454a46bSMartin KaFai Lau 	info->jited_line_info_rec_size = sizeof(__u64);
3452c454a46bSMartin KaFai Lau 
3453c454a46bSMartin KaFai Lau 	return 0;
3454c454a46bSMartin KaFai Lau }
3455c454a46bSMartin KaFai Lau 
345663960260SKees Cook static int bpf_prog_get_info_by_fd(struct file *file,
345763960260SKees Cook 				   struct bpf_prog *prog,
34581e270976SMartin KaFai Lau 				   const union bpf_attr *attr,
34591e270976SMartin KaFai Lau 				   union bpf_attr __user *uattr)
34601e270976SMartin KaFai Lau {
34611e270976SMartin KaFai Lau 	struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info);
34625c6f2588SGreg Kroah-Hartman 	struct bpf_prog_info info;
34631e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
34645f8f8b93SAlexei Starovoitov 	struct bpf_prog_stats stats;
34651e270976SMartin KaFai Lau 	char __user *uinsns;
34661e270976SMartin KaFai Lau 	u32 ulen;
34671e270976SMartin KaFai Lau 	int err;
34681e270976SMartin KaFai Lau 
3469dcab51f1SMartin KaFai Lau 	err = bpf_check_uarg_tail_zero(uinfo, sizeof(info), info_len);
34701e270976SMartin KaFai Lau 	if (err)
34711e270976SMartin KaFai Lau 		return err;
34721e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
34731e270976SMartin KaFai Lau 
34745c6f2588SGreg Kroah-Hartman 	memset(&info, 0, sizeof(info));
34751e270976SMartin KaFai Lau 	if (copy_from_user(&info, uinfo, info_len))
347689b09689SDaniel Borkmann 		return -EFAULT;
34771e270976SMartin KaFai Lau 
34781e270976SMartin KaFai Lau 	info.type = prog->type;
34791e270976SMartin KaFai Lau 	info.id = prog->aux->id;
3480cb4d2b3fSMartin KaFai Lau 	info.load_time = prog->aux->load_time;
3481cb4d2b3fSMartin KaFai Lau 	info.created_by_uid = from_kuid_munged(current_user_ns(),
3482cb4d2b3fSMartin KaFai Lau 					       prog->aux->user->uid);
3483b85fab0eSJiri Olsa 	info.gpl_compatible = prog->gpl_compatible;
34841e270976SMartin KaFai Lau 
34851e270976SMartin KaFai Lau 	memcpy(info.tag, prog->tag, sizeof(prog->tag));
3486cb4d2b3fSMartin KaFai Lau 	memcpy(info.name, prog->aux->name, sizeof(prog->aux->name));
3487cb4d2b3fSMartin KaFai Lau 
3488984fe94fSYiFei Zhu 	mutex_lock(&prog->aux->used_maps_mutex);
3489cb4d2b3fSMartin KaFai Lau 	ulen = info.nr_map_ids;
3490cb4d2b3fSMartin KaFai Lau 	info.nr_map_ids = prog->aux->used_map_cnt;
3491cb4d2b3fSMartin KaFai Lau 	ulen = min_t(u32, info.nr_map_ids, ulen);
3492cb4d2b3fSMartin KaFai Lau 	if (ulen) {
3493721e08daSMartin KaFai Lau 		u32 __user *user_map_ids = u64_to_user_ptr(info.map_ids);
3494cb4d2b3fSMartin KaFai Lau 		u32 i;
3495cb4d2b3fSMartin KaFai Lau 
3496cb4d2b3fSMartin KaFai Lau 		for (i = 0; i < ulen; i++)
3497cb4d2b3fSMartin KaFai Lau 			if (put_user(prog->aux->used_maps[i]->id,
3498984fe94fSYiFei Zhu 				     &user_map_ids[i])) {
3499984fe94fSYiFei Zhu 				mutex_unlock(&prog->aux->used_maps_mutex);
3500cb4d2b3fSMartin KaFai Lau 				return -EFAULT;
3501cb4d2b3fSMartin KaFai Lau 			}
3502984fe94fSYiFei Zhu 	}
3503984fe94fSYiFei Zhu 	mutex_unlock(&prog->aux->used_maps_mutex);
35041e270976SMartin KaFai Lau 
3505c454a46bSMartin KaFai Lau 	err = set_info_rec_size(&info);
3506c454a46bSMartin KaFai Lau 	if (err)
3507c454a46bSMartin KaFai Lau 		return err;
35087337224fSMartin KaFai Lau 
35095f8f8b93SAlexei Starovoitov 	bpf_prog_get_stats(prog, &stats);
35105f8f8b93SAlexei Starovoitov 	info.run_time_ns = stats.nsecs;
35115f8f8b93SAlexei Starovoitov 	info.run_cnt = stats.cnt;
35125f8f8b93SAlexei Starovoitov 
35132c78ee89SAlexei Starovoitov 	if (!bpf_capable()) {
35141e270976SMartin KaFai Lau 		info.jited_prog_len = 0;
35151e270976SMartin KaFai Lau 		info.xlated_prog_len = 0;
3516dbecd738SSandipan Das 		info.nr_jited_ksyms = 0;
351728c2fae7SDaniel Borkmann 		info.nr_jited_func_lens = 0;
351811d8b82dSYonghong Song 		info.nr_func_info = 0;
351911d8b82dSYonghong Song 		info.nr_line_info = 0;
352011d8b82dSYonghong Song 		info.nr_jited_line_info = 0;
35211e270976SMartin KaFai Lau 		goto done;
35221e270976SMartin KaFai Lau 	}
35231e270976SMartin KaFai Lau 
35241e270976SMartin KaFai Lau 	ulen = info.xlated_prog_len;
35259975a54bSDaniel Borkmann 	info.xlated_prog_len = bpf_prog_insn_size(prog);
35261e270976SMartin KaFai Lau 	if (info.xlated_prog_len && ulen) {
35277105e828SDaniel Borkmann 		struct bpf_insn *insns_sanitized;
35287105e828SDaniel Borkmann 		bool fault;
35297105e828SDaniel Borkmann 
353063960260SKees Cook 		if (prog->blinded && !bpf_dump_raw_ok(file->f_cred)) {
35317105e828SDaniel Borkmann 			info.xlated_prog_insns = 0;
35327105e828SDaniel Borkmann 			goto done;
35337105e828SDaniel Borkmann 		}
353463960260SKees Cook 		insns_sanitized = bpf_insn_prepare_dump(prog, file->f_cred);
35357105e828SDaniel Borkmann 		if (!insns_sanitized)
35367105e828SDaniel Borkmann 			return -ENOMEM;
35371e270976SMartin KaFai Lau 		uinsns = u64_to_user_ptr(info.xlated_prog_insns);
35381e270976SMartin KaFai Lau 		ulen = min_t(u32, info.xlated_prog_len, ulen);
35397105e828SDaniel Borkmann 		fault = copy_to_user(uinsns, insns_sanitized, ulen);
35407105e828SDaniel Borkmann 		kfree(insns_sanitized);
35417105e828SDaniel Borkmann 		if (fault)
35421e270976SMartin KaFai Lau 			return -EFAULT;
35431e270976SMartin KaFai Lau 	}
35441e270976SMartin KaFai Lau 
3545675fc275SJakub Kicinski 	if (bpf_prog_is_dev_bound(prog->aux)) {
3546675fc275SJakub Kicinski 		err = bpf_prog_offload_info_fill(&info, prog);
3547675fc275SJakub Kicinski 		if (err)
3548675fc275SJakub Kicinski 			return err;
3549fcfb126dSJiong Wang 		goto done;
3550fcfb126dSJiong Wang 	}
3551fcfb126dSJiong Wang 
3552fcfb126dSJiong Wang 	/* NOTE: the following code is supposed to be skipped for offload.
3553fcfb126dSJiong Wang 	 * bpf_prog_offload_info_fill() is the place to fill similar fields
3554fcfb126dSJiong Wang 	 * for offload.
3555fcfb126dSJiong Wang 	 */
3556fcfb126dSJiong Wang 	ulen = info.jited_prog_len;
35574d56a76eSSandipan Das 	if (prog->aux->func_cnt) {
35584d56a76eSSandipan Das 		u32 i;
35594d56a76eSSandipan Das 
35604d56a76eSSandipan Das 		info.jited_prog_len = 0;
35614d56a76eSSandipan Das 		for (i = 0; i < prog->aux->func_cnt; i++)
35624d56a76eSSandipan Das 			info.jited_prog_len += prog->aux->func[i]->jited_len;
35634d56a76eSSandipan Das 	} else {
3564fcfb126dSJiong Wang 		info.jited_prog_len = prog->jited_len;
35654d56a76eSSandipan Das 	}
35664d56a76eSSandipan Das 
3567fcfb126dSJiong Wang 	if (info.jited_prog_len && ulen) {
356863960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
3569fcfb126dSJiong Wang 			uinsns = u64_to_user_ptr(info.jited_prog_insns);
3570fcfb126dSJiong Wang 			ulen = min_t(u32, info.jited_prog_len, ulen);
35714d56a76eSSandipan Das 
35724d56a76eSSandipan Das 			/* for multi-function programs, copy the JITed
35734d56a76eSSandipan Das 			 * instructions for all the functions
35744d56a76eSSandipan Das 			 */
35754d56a76eSSandipan Das 			if (prog->aux->func_cnt) {
35764d56a76eSSandipan Das 				u32 len, free, i;
35774d56a76eSSandipan Das 				u8 *img;
35784d56a76eSSandipan Das 
35794d56a76eSSandipan Das 				free = ulen;
35804d56a76eSSandipan Das 				for (i = 0; i < prog->aux->func_cnt; i++) {
35814d56a76eSSandipan Das 					len = prog->aux->func[i]->jited_len;
35824d56a76eSSandipan Das 					len = min_t(u32, len, free);
35834d56a76eSSandipan Das 					img = (u8 *) prog->aux->func[i]->bpf_func;
35844d56a76eSSandipan Das 					if (copy_to_user(uinsns, img, len))
35854d56a76eSSandipan Das 						return -EFAULT;
35864d56a76eSSandipan Das 					uinsns += len;
35874d56a76eSSandipan Das 					free -= len;
35884d56a76eSSandipan Das 					if (!free)
35894d56a76eSSandipan Das 						break;
35904d56a76eSSandipan Das 				}
35914d56a76eSSandipan Das 			} else {
3592fcfb126dSJiong Wang 				if (copy_to_user(uinsns, prog->bpf_func, ulen))
3593fcfb126dSJiong Wang 					return -EFAULT;
35944d56a76eSSandipan Das 			}
3595fcfb126dSJiong Wang 		} else {
3596fcfb126dSJiong Wang 			info.jited_prog_insns = 0;
3597fcfb126dSJiong Wang 		}
3598675fc275SJakub Kicinski 	}
3599675fc275SJakub Kicinski 
3600dbecd738SSandipan Das 	ulen = info.nr_jited_ksyms;
3601ff1889fcSSong Liu 	info.nr_jited_ksyms = prog->aux->func_cnt ? : 1;
36027a5725ddSSong Liu 	if (ulen) {
360363960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
3604ff1889fcSSong Liu 			unsigned long ksym_addr;
3605dbecd738SSandipan Das 			u64 __user *user_ksyms;
3606dbecd738SSandipan Das 			u32 i;
3607dbecd738SSandipan Das 
3608dbecd738SSandipan Das 			/* copy the address of the kernel symbol
3609dbecd738SSandipan Das 			 * corresponding to each function
3610dbecd738SSandipan Das 			 */
3611dbecd738SSandipan Das 			ulen = min_t(u32, info.nr_jited_ksyms, ulen);
3612dbecd738SSandipan Das 			user_ksyms = u64_to_user_ptr(info.jited_ksyms);
3613ff1889fcSSong Liu 			if (prog->aux->func_cnt) {
3614dbecd738SSandipan Das 				for (i = 0; i < ulen; i++) {
3615ff1889fcSSong Liu 					ksym_addr = (unsigned long)
3616ff1889fcSSong Liu 						prog->aux->func[i]->bpf_func;
3617ff1889fcSSong Liu 					if (put_user((u64) ksym_addr,
3618ff1889fcSSong Liu 						     &user_ksyms[i]))
3619ff1889fcSSong Liu 						return -EFAULT;
3620ff1889fcSSong Liu 				}
3621ff1889fcSSong Liu 			} else {
3622ff1889fcSSong Liu 				ksym_addr = (unsigned long) prog->bpf_func;
3623ff1889fcSSong Liu 				if (put_user((u64) ksym_addr, &user_ksyms[0]))
3624dbecd738SSandipan Das 					return -EFAULT;
3625dbecd738SSandipan Das 			}
3626dbecd738SSandipan Das 		} else {
3627dbecd738SSandipan Das 			info.jited_ksyms = 0;
3628dbecd738SSandipan Das 		}
3629dbecd738SSandipan Das 	}
3630dbecd738SSandipan Das 
3631815581c1SSandipan Das 	ulen = info.nr_jited_func_lens;
3632ff1889fcSSong Liu 	info.nr_jited_func_lens = prog->aux->func_cnt ? : 1;
36337a5725ddSSong Liu 	if (ulen) {
363463960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
3635815581c1SSandipan Das 			u32 __user *user_lens;
3636815581c1SSandipan Das 			u32 func_len, i;
3637815581c1SSandipan Das 
3638815581c1SSandipan Das 			/* copy the JITed image lengths for each function */
3639815581c1SSandipan Das 			ulen = min_t(u32, info.nr_jited_func_lens, ulen);
3640815581c1SSandipan Das 			user_lens = u64_to_user_ptr(info.jited_func_lens);
3641ff1889fcSSong Liu 			if (prog->aux->func_cnt) {
3642815581c1SSandipan Das 				for (i = 0; i < ulen; i++) {
3643ff1889fcSSong Liu 					func_len =
3644ff1889fcSSong Liu 						prog->aux->func[i]->jited_len;
3645815581c1SSandipan Das 					if (put_user(func_len, &user_lens[i]))
3646815581c1SSandipan Das 						return -EFAULT;
3647815581c1SSandipan Das 				}
3648815581c1SSandipan Das 			} else {
3649ff1889fcSSong Liu 				func_len = prog->jited_len;
3650ff1889fcSSong Liu 				if (put_user(func_len, &user_lens[0]))
3651ff1889fcSSong Liu 					return -EFAULT;
3652ff1889fcSSong Liu 			}
3653ff1889fcSSong Liu 		} else {
3654815581c1SSandipan Das 			info.jited_func_lens = 0;
3655815581c1SSandipan Das 		}
3656815581c1SSandipan Das 	}
3657815581c1SSandipan Das 
36587337224fSMartin KaFai Lau 	if (prog->aux->btf)
3659838e9690SYonghong Song 		info.btf_id = btf_id(prog->aux->btf);
3660838e9690SYonghong Song 
366111d8b82dSYonghong Song 	ulen = info.nr_func_info;
366211d8b82dSYonghong Song 	info.nr_func_info = prog->aux->func_info_cnt;
366311d8b82dSYonghong Song 	if (info.nr_func_info && ulen) {
3664838e9690SYonghong Song 		char __user *user_finfo;
3665838e9690SYonghong Song 
3666838e9690SYonghong Song 		user_finfo = u64_to_user_ptr(info.func_info);
366711d8b82dSYonghong Song 		ulen = min_t(u32, info.nr_func_info, ulen);
3668ba64e7d8SYonghong Song 		if (copy_to_user(user_finfo, prog->aux->func_info,
36697337224fSMartin KaFai Lau 				 info.func_info_rec_size * ulen))
3670838e9690SYonghong Song 			return -EFAULT;
3671838e9690SYonghong Song 	}
3672838e9690SYonghong Song 
367311d8b82dSYonghong Song 	ulen = info.nr_line_info;
367411d8b82dSYonghong Song 	info.nr_line_info = prog->aux->nr_linfo;
367511d8b82dSYonghong Song 	if (info.nr_line_info && ulen) {
3676c454a46bSMartin KaFai Lau 		__u8 __user *user_linfo;
3677c454a46bSMartin KaFai Lau 
3678c454a46bSMartin KaFai Lau 		user_linfo = u64_to_user_ptr(info.line_info);
367911d8b82dSYonghong Song 		ulen = min_t(u32, info.nr_line_info, ulen);
3680c454a46bSMartin KaFai Lau 		if (copy_to_user(user_linfo, prog->aux->linfo,
3681c454a46bSMartin KaFai Lau 				 info.line_info_rec_size * ulen))
3682c454a46bSMartin KaFai Lau 			return -EFAULT;
3683c454a46bSMartin KaFai Lau 	}
3684c454a46bSMartin KaFai Lau 
368511d8b82dSYonghong Song 	ulen = info.nr_jited_line_info;
3686c454a46bSMartin KaFai Lau 	if (prog->aux->jited_linfo)
368711d8b82dSYonghong Song 		info.nr_jited_line_info = prog->aux->nr_linfo;
3688c454a46bSMartin KaFai Lau 	else
368911d8b82dSYonghong Song 		info.nr_jited_line_info = 0;
369011d8b82dSYonghong Song 	if (info.nr_jited_line_info && ulen) {
369163960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
3692c454a46bSMartin KaFai Lau 			__u64 __user *user_linfo;
3693c454a46bSMartin KaFai Lau 			u32 i;
3694c454a46bSMartin KaFai Lau 
3695c454a46bSMartin KaFai Lau 			user_linfo = u64_to_user_ptr(info.jited_line_info);
369611d8b82dSYonghong Song 			ulen = min_t(u32, info.nr_jited_line_info, ulen);
3697c454a46bSMartin KaFai Lau 			for (i = 0; i < ulen; i++) {
3698c454a46bSMartin KaFai Lau 				if (put_user((__u64)(long)prog->aux->jited_linfo[i],
3699c454a46bSMartin KaFai Lau 					     &user_linfo[i]))
3700c454a46bSMartin KaFai Lau 					return -EFAULT;
3701c454a46bSMartin KaFai Lau 			}
3702c454a46bSMartin KaFai Lau 		} else {
3703c454a46bSMartin KaFai Lau 			info.jited_line_info = 0;
3704c454a46bSMartin KaFai Lau 		}
3705c454a46bSMartin KaFai Lau 	}
3706c454a46bSMartin KaFai Lau 
3707c872bdb3SSong Liu 	ulen = info.nr_prog_tags;
3708c872bdb3SSong Liu 	info.nr_prog_tags = prog->aux->func_cnt ? : 1;
3709c872bdb3SSong Liu 	if (ulen) {
3710c872bdb3SSong Liu 		__u8 __user (*user_prog_tags)[BPF_TAG_SIZE];
3711c872bdb3SSong Liu 		u32 i;
3712c872bdb3SSong Liu 
3713c872bdb3SSong Liu 		user_prog_tags = u64_to_user_ptr(info.prog_tags);
3714c872bdb3SSong Liu 		ulen = min_t(u32, info.nr_prog_tags, ulen);
3715c872bdb3SSong Liu 		if (prog->aux->func_cnt) {
3716c872bdb3SSong Liu 			for (i = 0; i < ulen; i++) {
3717c872bdb3SSong Liu 				if (copy_to_user(user_prog_tags[i],
3718c872bdb3SSong Liu 						 prog->aux->func[i]->tag,
3719c872bdb3SSong Liu 						 BPF_TAG_SIZE))
3720c872bdb3SSong Liu 					return -EFAULT;
3721c872bdb3SSong Liu 			}
3722c872bdb3SSong Liu 		} else {
3723c872bdb3SSong Liu 			if (copy_to_user(user_prog_tags[0],
3724c872bdb3SSong Liu 					 prog->tag, BPF_TAG_SIZE))
3725c872bdb3SSong Liu 				return -EFAULT;
3726c872bdb3SSong Liu 		}
3727c872bdb3SSong Liu 	}
3728c872bdb3SSong Liu 
37291e270976SMartin KaFai Lau done:
37301e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
37311e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
37321e270976SMartin KaFai Lau 		return -EFAULT;
37331e270976SMartin KaFai Lau 
37341e270976SMartin KaFai Lau 	return 0;
37351e270976SMartin KaFai Lau }
37361e270976SMartin KaFai Lau 
373763960260SKees Cook static int bpf_map_get_info_by_fd(struct file *file,
373863960260SKees Cook 				  struct bpf_map *map,
37391e270976SMartin KaFai Lau 				  const union bpf_attr *attr,
37401e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
37411e270976SMartin KaFai Lau {
37421e270976SMartin KaFai Lau 	struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info);
37435c6f2588SGreg Kroah-Hartman 	struct bpf_map_info info;
37441e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
37451e270976SMartin KaFai Lau 	int err;
37461e270976SMartin KaFai Lau 
3747dcab51f1SMartin KaFai Lau 	err = bpf_check_uarg_tail_zero(uinfo, sizeof(info), info_len);
37481e270976SMartin KaFai Lau 	if (err)
37491e270976SMartin KaFai Lau 		return err;
37501e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
37511e270976SMartin KaFai Lau 
37525c6f2588SGreg Kroah-Hartman 	memset(&info, 0, sizeof(info));
37531e270976SMartin KaFai Lau 	info.type = map->map_type;
37541e270976SMartin KaFai Lau 	info.id = map->id;
37551e270976SMartin KaFai Lau 	info.key_size = map->key_size;
37561e270976SMartin KaFai Lau 	info.value_size = map->value_size;
37571e270976SMartin KaFai Lau 	info.max_entries = map->max_entries;
37581e270976SMartin KaFai Lau 	info.map_flags = map->map_flags;
3759ad5b177bSMartin KaFai Lau 	memcpy(info.name, map->name, sizeof(map->name));
37601e270976SMartin KaFai Lau 
376178958fcaSMartin KaFai Lau 	if (map->btf) {
376278958fcaSMartin KaFai Lau 		info.btf_id = btf_id(map->btf);
37639b2cf328SMartin KaFai Lau 		info.btf_key_type_id = map->btf_key_type_id;
37649b2cf328SMartin KaFai Lau 		info.btf_value_type_id = map->btf_value_type_id;
376578958fcaSMartin KaFai Lau 	}
376685d33df3SMartin KaFai Lau 	info.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id;
376778958fcaSMartin KaFai Lau 
376852775b33SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
376952775b33SJakub Kicinski 		err = bpf_map_offload_info_fill(&info, map);
377052775b33SJakub Kicinski 		if (err)
377152775b33SJakub Kicinski 			return err;
377252775b33SJakub Kicinski 	}
377352775b33SJakub Kicinski 
37741e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
37751e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
37761e270976SMartin KaFai Lau 		return -EFAULT;
37771e270976SMartin KaFai Lau 
37781e270976SMartin KaFai Lau 	return 0;
37791e270976SMartin KaFai Lau }
37801e270976SMartin KaFai Lau 
378163960260SKees Cook static int bpf_btf_get_info_by_fd(struct file *file,
378263960260SKees Cook 				  struct btf *btf,
378362dab84cSMartin KaFai Lau 				  const union bpf_attr *attr,
378462dab84cSMartin KaFai Lau 				  union bpf_attr __user *uattr)
378562dab84cSMartin KaFai Lau {
378662dab84cSMartin KaFai Lau 	struct bpf_btf_info __user *uinfo = u64_to_user_ptr(attr->info.info);
378762dab84cSMartin KaFai Lau 	u32 info_len = attr->info.info_len;
378862dab84cSMartin KaFai Lau 	int err;
378962dab84cSMartin KaFai Lau 
3790dcab51f1SMartin KaFai Lau 	err = bpf_check_uarg_tail_zero(uinfo, sizeof(*uinfo), info_len);
379162dab84cSMartin KaFai Lau 	if (err)
379262dab84cSMartin KaFai Lau 		return err;
379362dab84cSMartin KaFai Lau 
379462dab84cSMartin KaFai Lau 	return btf_get_info_by_fd(btf, attr, uattr);
379562dab84cSMartin KaFai Lau }
379662dab84cSMartin KaFai Lau 
379763960260SKees Cook static int bpf_link_get_info_by_fd(struct file *file,
379863960260SKees Cook 				  struct bpf_link *link,
3799f2e10bffSAndrii Nakryiko 				  const union bpf_attr *attr,
3800f2e10bffSAndrii Nakryiko 				  union bpf_attr __user *uattr)
3801f2e10bffSAndrii Nakryiko {
3802f2e10bffSAndrii Nakryiko 	struct bpf_link_info __user *uinfo = u64_to_user_ptr(attr->info.info);
3803f2e10bffSAndrii Nakryiko 	struct bpf_link_info info;
3804f2e10bffSAndrii Nakryiko 	u32 info_len = attr->info.info_len;
3805f2e10bffSAndrii Nakryiko 	int err;
3806f2e10bffSAndrii Nakryiko 
3807f2e10bffSAndrii Nakryiko 	err = bpf_check_uarg_tail_zero(uinfo, sizeof(info), info_len);
3808f2e10bffSAndrii Nakryiko 	if (err)
3809f2e10bffSAndrii Nakryiko 		return err;
3810f2e10bffSAndrii Nakryiko 	info_len = min_t(u32, sizeof(info), info_len);
3811f2e10bffSAndrii Nakryiko 
3812f2e10bffSAndrii Nakryiko 	memset(&info, 0, sizeof(info));
3813f2e10bffSAndrii Nakryiko 	if (copy_from_user(&info, uinfo, info_len))
3814f2e10bffSAndrii Nakryiko 		return -EFAULT;
3815f2e10bffSAndrii Nakryiko 
3816f2e10bffSAndrii Nakryiko 	info.type = link->type;
3817f2e10bffSAndrii Nakryiko 	info.id = link->id;
3818f2e10bffSAndrii Nakryiko 	info.prog_id = link->prog->aux->id;
3819f2e10bffSAndrii Nakryiko 
3820f2e10bffSAndrii Nakryiko 	if (link->ops->fill_link_info) {
3821f2e10bffSAndrii Nakryiko 		err = link->ops->fill_link_info(link, &info);
3822f2e10bffSAndrii Nakryiko 		if (err)
3823f2e10bffSAndrii Nakryiko 			return err;
3824f2e10bffSAndrii Nakryiko 	}
3825f2e10bffSAndrii Nakryiko 
3826f2e10bffSAndrii Nakryiko 	if (copy_to_user(uinfo, &info, info_len) ||
3827f2e10bffSAndrii Nakryiko 	    put_user(info_len, &uattr->info.info_len))
3828f2e10bffSAndrii Nakryiko 		return -EFAULT;
3829f2e10bffSAndrii Nakryiko 
3830f2e10bffSAndrii Nakryiko 	return 0;
3831f2e10bffSAndrii Nakryiko }
3832f2e10bffSAndrii Nakryiko 
3833f2e10bffSAndrii Nakryiko 
38341e270976SMartin KaFai Lau #define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info
38351e270976SMartin KaFai Lau 
38361e270976SMartin KaFai Lau static int bpf_obj_get_info_by_fd(const union bpf_attr *attr,
38371e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
38381e270976SMartin KaFai Lau {
38391e270976SMartin KaFai Lau 	int ufd = attr->info.bpf_fd;
38401e270976SMartin KaFai Lau 	struct fd f;
38411e270976SMartin KaFai Lau 	int err;
38421e270976SMartin KaFai Lau 
38431e270976SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD))
38441e270976SMartin KaFai Lau 		return -EINVAL;
38451e270976SMartin KaFai Lau 
38461e270976SMartin KaFai Lau 	f = fdget(ufd);
38471e270976SMartin KaFai Lau 	if (!f.file)
38481e270976SMartin KaFai Lau 		return -EBADFD;
38491e270976SMartin KaFai Lau 
38501e270976SMartin KaFai Lau 	if (f.file->f_op == &bpf_prog_fops)
385163960260SKees Cook 		err = bpf_prog_get_info_by_fd(f.file, f.file->private_data, attr,
38521e270976SMartin KaFai Lau 					      uattr);
38531e270976SMartin KaFai Lau 	else if (f.file->f_op == &bpf_map_fops)
385463960260SKees Cook 		err = bpf_map_get_info_by_fd(f.file, f.file->private_data, attr,
38551e270976SMartin KaFai Lau 					     uattr);
385660197cfbSMartin KaFai Lau 	else if (f.file->f_op == &btf_fops)
385763960260SKees Cook 		err = bpf_btf_get_info_by_fd(f.file, f.file->private_data, attr, uattr);
3858f2e10bffSAndrii Nakryiko 	else if (f.file->f_op == &bpf_link_fops)
385963960260SKees Cook 		err = bpf_link_get_info_by_fd(f.file, f.file->private_data,
3860f2e10bffSAndrii Nakryiko 					      attr, uattr);
38611e270976SMartin KaFai Lau 	else
38621e270976SMartin KaFai Lau 		err = -EINVAL;
38631e270976SMartin KaFai Lau 
38641e270976SMartin KaFai Lau 	fdput(f);
38651e270976SMartin KaFai Lau 	return err;
38661e270976SMartin KaFai Lau }
38671e270976SMartin KaFai Lau 
3868f56a653cSMartin KaFai Lau #define BPF_BTF_LOAD_LAST_FIELD btf_log_level
3869f56a653cSMartin KaFai Lau 
3870f56a653cSMartin KaFai Lau static int bpf_btf_load(const union bpf_attr *attr)
3871f56a653cSMartin KaFai Lau {
3872f56a653cSMartin KaFai Lau 	if (CHECK_ATTR(BPF_BTF_LOAD))
3873f56a653cSMartin KaFai Lau 		return -EINVAL;
3874f56a653cSMartin KaFai Lau 
38752c78ee89SAlexei Starovoitov 	if (!bpf_capable())
3876f56a653cSMartin KaFai Lau 		return -EPERM;
3877f56a653cSMartin KaFai Lau 
3878f56a653cSMartin KaFai Lau 	return btf_new_fd(attr);
3879f56a653cSMartin KaFai Lau }
3880f56a653cSMartin KaFai Lau 
388178958fcaSMartin KaFai Lau #define BPF_BTF_GET_FD_BY_ID_LAST_FIELD btf_id
388278958fcaSMartin KaFai Lau 
388378958fcaSMartin KaFai Lau static int bpf_btf_get_fd_by_id(const union bpf_attr *attr)
388478958fcaSMartin KaFai Lau {
388578958fcaSMartin KaFai Lau 	if (CHECK_ATTR(BPF_BTF_GET_FD_BY_ID))
388678958fcaSMartin KaFai Lau 		return -EINVAL;
388778958fcaSMartin KaFai Lau 
388878958fcaSMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
388978958fcaSMartin KaFai Lau 		return -EPERM;
389078958fcaSMartin KaFai Lau 
389178958fcaSMartin KaFai Lau 	return btf_get_fd_by_id(attr->btf_id);
389278958fcaSMartin KaFai Lau }
389378958fcaSMartin KaFai Lau 
389441bdc4b4SYonghong Song static int bpf_task_fd_query_copy(const union bpf_attr *attr,
389541bdc4b4SYonghong Song 				    union bpf_attr __user *uattr,
389641bdc4b4SYonghong Song 				    u32 prog_id, u32 fd_type,
389741bdc4b4SYonghong Song 				    const char *buf, u64 probe_offset,
389841bdc4b4SYonghong Song 				    u64 probe_addr)
389941bdc4b4SYonghong Song {
390041bdc4b4SYonghong Song 	char __user *ubuf = u64_to_user_ptr(attr->task_fd_query.buf);
390141bdc4b4SYonghong Song 	u32 len = buf ? strlen(buf) : 0, input_len;
390241bdc4b4SYonghong Song 	int err = 0;
390341bdc4b4SYonghong Song 
390441bdc4b4SYonghong Song 	if (put_user(len, &uattr->task_fd_query.buf_len))
390541bdc4b4SYonghong Song 		return -EFAULT;
390641bdc4b4SYonghong Song 	input_len = attr->task_fd_query.buf_len;
390741bdc4b4SYonghong Song 	if (input_len && ubuf) {
390841bdc4b4SYonghong Song 		if (!len) {
390941bdc4b4SYonghong Song 			/* nothing to copy, just make ubuf NULL terminated */
391041bdc4b4SYonghong Song 			char zero = '\0';
391141bdc4b4SYonghong Song 
391241bdc4b4SYonghong Song 			if (put_user(zero, ubuf))
391341bdc4b4SYonghong Song 				return -EFAULT;
391441bdc4b4SYonghong Song 		} else if (input_len >= len + 1) {
391541bdc4b4SYonghong Song 			/* ubuf can hold the string with NULL terminator */
391641bdc4b4SYonghong Song 			if (copy_to_user(ubuf, buf, len + 1))
391741bdc4b4SYonghong Song 				return -EFAULT;
391841bdc4b4SYonghong Song 		} else {
391941bdc4b4SYonghong Song 			/* ubuf cannot hold the string with NULL terminator,
392041bdc4b4SYonghong Song 			 * do a partial copy with NULL terminator.
392141bdc4b4SYonghong Song 			 */
392241bdc4b4SYonghong Song 			char zero = '\0';
392341bdc4b4SYonghong Song 
392441bdc4b4SYonghong Song 			err = -ENOSPC;
392541bdc4b4SYonghong Song 			if (copy_to_user(ubuf, buf, input_len - 1))
392641bdc4b4SYonghong Song 				return -EFAULT;
392741bdc4b4SYonghong Song 			if (put_user(zero, ubuf + input_len - 1))
392841bdc4b4SYonghong Song 				return -EFAULT;
392941bdc4b4SYonghong Song 		}
393041bdc4b4SYonghong Song 	}
393141bdc4b4SYonghong Song 
393241bdc4b4SYonghong Song 	if (put_user(prog_id, &uattr->task_fd_query.prog_id) ||
393341bdc4b4SYonghong Song 	    put_user(fd_type, &uattr->task_fd_query.fd_type) ||
393441bdc4b4SYonghong Song 	    put_user(probe_offset, &uattr->task_fd_query.probe_offset) ||
393541bdc4b4SYonghong Song 	    put_user(probe_addr, &uattr->task_fd_query.probe_addr))
393641bdc4b4SYonghong Song 		return -EFAULT;
393741bdc4b4SYonghong Song 
393841bdc4b4SYonghong Song 	return err;
393941bdc4b4SYonghong Song }
394041bdc4b4SYonghong Song 
394141bdc4b4SYonghong Song #define BPF_TASK_FD_QUERY_LAST_FIELD task_fd_query.probe_addr
394241bdc4b4SYonghong Song 
394341bdc4b4SYonghong Song static int bpf_task_fd_query(const union bpf_attr *attr,
394441bdc4b4SYonghong Song 			     union bpf_attr __user *uattr)
394541bdc4b4SYonghong Song {
394641bdc4b4SYonghong Song 	pid_t pid = attr->task_fd_query.pid;
394741bdc4b4SYonghong Song 	u32 fd = attr->task_fd_query.fd;
394841bdc4b4SYonghong Song 	const struct perf_event *event;
394941bdc4b4SYonghong Song 	struct files_struct *files;
395041bdc4b4SYonghong Song 	struct task_struct *task;
395141bdc4b4SYonghong Song 	struct file *file;
395241bdc4b4SYonghong Song 	int err;
395341bdc4b4SYonghong Song 
395441bdc4b4SYonghong Song 	if (CHECK_ATTR(BPF_TASK_FD_QUERY))
395541bdc4b4SYonghong Song 		return -EINVAL;
395641bdc4b4SYonghong Song 
395741bdc4b4SYonghong Song 	if (!capable(CAP_SYS_ADMIN))
395841bdc4b4SYonghong Song 		return -EPERM;
395941bdc4b4SYonghong Song 
396041bdc4b4SYonghong Song 	if (attr->task_fd_query.flags != 0)
396141bdc4b4SYonghong Song 		return -EINVAL;
396241bdc4b4SYonghong Song 
396341bdc4b4SYonghong Song 	task = get_pid_task(find_vpid(pid), PIDTYPE_PID);
396441bdc4b4SYonghong Song 	if (!task)
396541bdc4b4SYonghong Song 		return -ENOENT;
396641bdc4b4SYonghong Song 
396741bdc4b4SYonghong Song 	files = get_files_struct(task);
396841bdc4b4SYonghong Song 	put_task_struct(task);
396941bdc4b4SYonghong Song 	if (!files)
397041bdc4b4SYonghong Song 		return -ENOENT;
397141bdc4b4SYonghong Song 
397241bdc4b4SYonghong Song 	err = 0;
397341bdc4b4SYonghong Song 	spin_lock(&files->file_lock);
397441bdc4b4SYonghong Song 	file = fcheck_files(files, fd);
397541bdc4b4SYonghong Song 	if (!file)
397641bdc4b4SYonghong Song 		err = -EBADF;
397741bdc4b4SYonghong Song 	else
397841bdc4b4SYonghong Song 		get_file(file);
397941bdc4b4SYonghong Song 	spin_unlock(&files->file_lock);
398041bdc4b4SYonghong Song 	put_files_struct(files);
398141bdc4b4SYonghong Song 
398241bdc4b4SYonghong Song 	if (err)
398341bdc4b4SYonghong Song 		goto out;
398441bdc4b4SYonghong Song 
398570ed506cSAndrii Nakryiko 	if (file->f_op == &bpf_link_fops) {
398670ed506cSAndrii Nakryiko 		struct bpf_link *link = file->private_data;
398770ed506cSAndrii Nakryiko 
3988a3b80e10SAndrii Nakryiko 		if (link->ops == &bpf_raw_tp_link_lops) {
398970ed506cSAndrii Nakryiko 			struct bpf_raw_tp_link *raw_tp =
399070ed506cSAndrii Nakryiko 				container_of(link, struct bpf_raw_tp_link, link);
399141bdc4b4SYonghong Song 			struct bpf_raw_event_map *btp = raw_tp->btp;
399241bdc4b4SYonghong Song 
399341bdc4b4SYonghong Song 			err = bpf_task_fd_query_copy(attr, uattr,
399470ed506cSAndrii Nakryiko 						     raw_tp->link.prog->aux->id,
399541bdc4b4SYonghong Song 						     BPF_FD_TYPE_RAW_TRACEPOINT,
399641bdc4b4SYonghong Song 						     btp->tp->name, 0, 0);
399741bdc4b4SYonghong Song 			goto put_file;
399841bdc4b4SYonghong Song 		}
399970ed506cSAndrii Nakryiko 		goto out_not_supp;
400070ed506cSAndrii Nakryiko 	}
400141bdc4b4SYonghong Song 
400241bdc4b4SYonghong Song 	event = perf_get_event(file);
400341bdc4b4SYonghong Song 	if (!IS_ERR(event)) {
400441bdc4b4SYonghong Song 		u64 probe_offset, probe_addr;
400541bdc4b4SYonghong Song 		u32 prog_id, fd_type;
400641bdc4b4SYonghong Song 		const char *buf;
400741bdc4b4SYonghong Song 
400841bdc4b4SYonghong Song 		err = bpf_get_perf_event_info(event, &prog_id, &fd_type,
400941bdc4b4SYonghong Song 					      &buf, &probe_offset,
401041bdc4b4SYonghong Song 					      &probe_addr);
401141bdc4b4SYonghong Song 		if (!err)
401241bdc4b4SYonghong Song 			err = bpf_task_fd_query_copy(attr, uattr, prog_id,
401341bdc4b4SYonghong Song 						     fd_type, buf,
401441bdc4b4SYonghong Song 						     probe_offset,
401541bdc4b4SYonghong Song 						     probe_addr);
401641bdc4b4SYonghong Song 		goto put_file;
401741bdc4b4SYonghong Song 	}
401841bdc4b4SYonghong Song 
401970ed506cSAndrii Nakryiko out_not_supp:
402041bdc4b4SYonghong Song 	err = -ENOTSUPP;
402141bdc4b4SYonghong Song put_file:
402241bdc4b4SYonghong Song 	fput(file);
402341bdc4b4SYonghong Song out:
402441bdc4b4SYonghong Song 	return err;
402541bdc4b4SYonghong Song }
402641bdc4b4SYonghong Song 
4027cb4d03abSBrian Vazquez #define BPF_MAP_BATCH_LAST_FIELD batch.flags
4028cb4d03abSBrian Vazquez 
4029cb4d03abSBrian Vazquez #define BPF_DO_BATCH(fn)			\
4030cb4d03abSBrian Vazquez 	do {					\
4031cb4d03abSBrian Vazquez 		if (!fn) {			\
4032cb4d03abSBrian Vazquez 			err = -ENOTSUPP;	\
4033cb4d03abSBrian Vazquez 			goto err_put;		\
4034cb4d03abSBrian Vazquez 		}				\
4035cb4d03abSBrian Vazquez 		err = fn(map, attr, uattr);	\
4036cb4d03abSBrian Vazquez 	} while (0)
4037cb4d03abSBrian Vazquez 
4038cb4d03abSBrian Vazquez static int bpf_map_do_batch(const union bpf_attr *attr,
4039cb4d03abSBrian Vazquez 			    union bpf_attr __user *uattr,
4040cb4d03abSBrian Vazquez 			    int cmd)
4041cb4d03abSBrian Vazquez {
4042cb4d03abSBrian Vazquez 	struct bpf_map *map;
4043cb4d03abSBrian Vazquez 	int err, ufd;
4044cb4d03abSBrian Vazquez 	struct fd f;
4045cb4d03abSBrian Vazquez 
4046cb4d03abSBrian Vazquez 	if (CHECK_ATTR(BPF_MAP_BATCH))
4047cb4d03abSBrian Vazquez 		return -EINVAL;
4048cb4d03abSBrian Vazquez 
4049cb4d03abSBrian Vazquez 	ufd = attr->batch.map_fd;
4050cb4d03abSBrian Vazquez 	f = fdget(ufd);
4051cb4d03abSBrian Vazquez 	map = __bpf_map_get(f);
4052cb4d03abSBrian Vazquez 	if (IS_ERR(map))
4053cb4d03abSBrian Vazquez 		return PTR_ERR(map);
4054cb4d03abSBrian Vazquez 
405505799638SYonghong Song 	if ((cmd == BPF_MAP_LOOKUP_BATCH ||
405605799638SYonghong Song 	     cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH) &&
4057cb4d03abSBrian Vazquez 	    !(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
4058cb4d03abSBrian Vazquez 		err = -EPERM;
4059cb4d03abSBrian Vazquez 		goto err_put;
4060cb4d03abSBrian Vazquez 	}
4061cb4d03abSBrian Vazquez 
4062cb4d03abSBrian Vazquez 	if (cmd != BPF_MAP_LOOKUP_BATCH &&
4063cb4d03abSBrian Vazquez 	    !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
4064cb4d03abSBrian Vazquez 		err = -EPERM;
4065cb4d03abSBrian Vazquez 		goto err_put;
4066cb4d03abSBrian Vazquez 	}
4067cb4d03abSBrian Vazquez 
4068cb4d03abSBrian Vazquez 	if (cmd == BPF_MAP_LOOKUP_BATCH)
4069cb4d03abSBrian Vazquez 		BPF_DO_BATCH(map->ops->map_lookup_batch);
407005799638SYonghong Song 	else if (cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH)
407105799638SYonghong Song 		BPF_DO_BATCH(map->ops->map_lookup_and_delete_batch);
4072aa2e93b8SBrian Vazquez 	else if (cmd == BPF_MAP_UPDATE_BATCH)
4073aa2e93b8SBrian Vazquez 		BPF_DO_BATCH(map->ops->map_update_batch);
4074aa2e93b8SBrian Vazquez 	else
4075aa2e93b8SBrian Vazquez 		BPF_DO_BATCH(map->ops->map_delete_batch);
4076cb4d03abSBrian Vazquez 
4077cb4d03abSBrian Vazquez err_put:
4078cb4d03abSBrian Vazquez 	fdput(f);
4079cb4d03abSBrian Vazquez 	return err;
4080cb4d03abSBrian Vazquez }
4081cb4d03abSBrian Vazquez 
4082de4e05caSYonghong Song static int tracing_bpf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
4083de4e05caSYonghong Song {
40844a1e7c0cSToke Høiland-Jørgensen 	if (attr->link_create.attach_type != prog->expected_attach_type)
40854a1e7c0cSToke Høiland-Jørgensen 		return -EINVAL;
4086de4e05caSYonghong Song 
40874a1e7c0cSToke Høiland-Jørgensen 	if (prog->expected_attach_type == BPF_TRACE_ITER)
40884a1e7c0cSToke Høiland-Jørgensen 		return bpf_iter_link_attach(attr, prog);
40894a1e7c0cSToke Høiland-Jørgensen 	else if (prog->type == BPF_PROG_TYPE_EXT)
40904a1e7c0cSToke Høiland-Jørgensen 		return bpf_tracing_prog_attach(prog,
40914a1e7c0cSToke Høiland-Jørgensen 					       attr->link_create.target_fd,
40924a1e7c0cSToke Høiland-Jørgensen 					       attr->link_create.target_btf_id);
4093de4e05caSYonghong Song 	return -EINVAL;
4094de4e05caSYonghong Song }
4095de4e05caSYonghong Song 
40965e7b3020SYonghong Song #define BPF_LINK_CREATE_LAST_FIELD link_create.iter_info_len
4097af6eea57SAndrii Nakryiko static int link_create(union bpf_attr *attr)
4098af6eea57SAndrii Nakryiko {
4099af6eea57SAndrii Nakryiko 	enum bpf_prog_type ptype;
4100af6eea57SAndrii Nakryiko 	struct bpf_prog *prog;
4101af6eea57SAndrii Nakryiko 	int ret;
4102af6eea57SAndrii Nakryiko 
4103af6eea57SAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_CREATE))
4104af6eea57SAndrii Nakryiko 		return -EINVAL;
4105af6eea57SAndrii Nakryiko 
41064a1e7c0cSToke Høiland-Jørgensen 	prog = bpf_prog_get(attr->link_create.prog_fd);
4107af6eea57SAndrii Nakryiko 	if (IS_ERR(prog))
4108af6eea57SAndrii Nakryiko 		return PTR_ERR(prog);
4109af6eea57SAndrii Nakryiko 
4110af6eea57SAndrii Nakryiko 	ret = bpf_prog_attach_check_attach_type(prog,
4111af6eea57SAndrii Nakryiko 						attr->link_create.attach_type);
4112af6eea57SAndrii Nakryiko 	if (ret)
41134a1e7c0cSToke Høiland-Jørgensen 		goto out;
41144a1e7c0cSToke Høiland-Jørgensen 
41154a1e7c0cSToke Høiland-Jørgensen 	if (prog->type == BPF_PROG_TYPE_EXT) {
41164a1e7c0cSToke Høiland-Jørgensen 		ret = tracing_bpf_link_attach(attr, prog);
41174a1e7c0cSToke Høiland-Jørgensen 		goto out;
41184a1e7c0cSToke Høiland-Jørgensen 	}
41194a1e7c0cSToke Høiland-Jørgensen 
41204a1e7c0cSToke Høiland-Jørgensen 	ptype = attach_type_to_prog_type(attr->link_create.attach_type);
41214a1e7c0cSToke Høiland-Jørgensen 	if (ptype == BPF_PROG_TYPE_UNSPEC || ptype != prog->type) {
41224a1e7c0cSToke Høiland-Jørgensen 		ret = -EINVAL;
41234a1e7c0cSToke Høiland-Jørgensen 		goto out;
41244a1e7c0cSToke Høiland-Jørgensen 	}
4125af6eea57SAndrii Nakryiko 
4126af6eea57SAndrii Nakryiko 	switch (ptype) {
4127af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SKB:
4128af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK:
4129af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
4130af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_SOCK_OPS:
4131af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_DEVICE:
4132af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
4133af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
4134af6eea57SAndrii Nakryiko 		ret = cgroup_bpf_link_attach(attr, prog);
4135af6eea57SAndrii Nakryiko 		break;
4136de4e05caSYonghong Song 	case BPF_PROG_TYPE_TRACING:
4137de4e05caSYonghong Song 		ret = tracing_bpf_link_attach(attr, prog);
4138de4e05caSYonghong Song 		break;
41397f045a49SJakub Sitnicki 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
4140e9ddbb77SJakub Sitnicki 	case BPF_PROG_TYPE_SK_LOOKUP:
41417f045a49SJakub Sitnicki 		ret = netns_bpf_link_create(attr, prog);
41427f045a49SJakub Sitnicki 		break;
4143310ad797SAndrii Nakryiko #ifdef CONFIG_NET
4144aa8d3a71SAndrii Nakryiko 	case BPF_PROG_TYPE_XDP:
4145aa8d3a71SAndrii Nakryiko 		ret = bpf_xdp_link_attach(attr, prog);
4146aa8d3a71SAndrii Nakryiko 		break;
4147310ad797SAndrii Nakryiko #endif
4148af6eea57SAndrii Nakryiko 	default:
4149af6eea57SAndrii Nakryiko 		ret = -EINVAL;
4150af6eea57SAndrii Nakryiko 	}
4151af6eea57SAndrii Nakryiko 
41524a1e7c0cSToke Høiland-Jørgensen out:
4153af6eea57SAndrii Nakryiko 	if (ret < 0)
4154af6eea57SAndrii Nakryiko 		bpf_prog_put(prog);
4155af6eea57SAndrii Nakryiko 	return ret;
4156af6eea57SAndrii Nakryiko }
4157af6eea57SAndrii Nakryiko 
41580c991ebcSAndrii Nakryiko #define BPF_LINK_UPDATE_LAST_FIELD link_update.old_prog_fd
41590c991ebcSAndrii Nakryiko 
41600c991ebcSAndrii Nakryiko static int link_update(union bpf_attr *attr)
41610c991ebcSAndrii Nakryiko {
41620c991ebcSAndrii Nakryiko 	struct bpf_prog *old_prog = NULL, *new_prog;
41630c991ebcSAndrii Nakryiko 	struct bpf_link *link;
41640c991ebcSAndrii Nakryiko 	u32 flags;
41650c991ebcSAndrii Nakryiko 	int ret;
41660c991ebcSAndrii Nakryiko 
41670c991ebcSAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_UPDATE))
41680c991ebcSAndrii Nakryiko 		return -EINVAL;
41690c991ebcSAndrii Nakryiko 
41700c991ebcSAndrii Nakryiko 	flags = attr->link_update.flags;
41710c991ebcSAndrii Nakryiko 	if (flags & ~BPF_F_REPLACE)
41720c991ebcSAndrii Nakryiko 		return -EINVAL;
41730c991ebcSAndrii Nakryiko 
41740c991ebcSAndrii Nakryiko 	link = bpf_link_get_from_fd(attr->link_update.link_fd);
41750c991ebcSAndrii Nakryiko 	if (IS_ERR(link))
41760c991ebcSAndrii Nakryiko 		return PTR_ERR(link);
41770c991ebcSAndrii Nakryiko 
41780c991ebcSAndrii Nakryiko 	new_prog = bpf_prog_get(attr->link_update.new_prog_fd);
41794adb7a4aSAndrii Nakryiko 	if (IS_ERR(new_prog)) {
41804adb7a4aSAndrii Nakryiko 		ret = PTR_ERR(new_prog);
41814adb7a4aSAndrii Nakryiko 		goto out_put_link;
41824adb7a4aSAndrii Nakryiko 	}
41830c991ebcSAndrii Nakryiko 
41840c991ebcSAndrii Nakryiko 	if (flags & BPF_F_REPLACE) {
41850c991ebcSAndrii Nakryiko 		old_prog = bpf_prog_get(attr->link_update.old_prog_fd);
41860c991ebcSAndrii Nakryiko 		if (IS_ERR(old_prog)) {
41870c991ebcSAndrii Nakryiko 			ret = PTR_ERR(old_prog);
41880c991ebcSAndrii Nakryiko 			old_prog = NULL;
41890c991ebcSAndrii Nakryiko 			goto out_put_progs;
41900c991ebcSAndrii Nakryiko 		}
41914adb7a4aSAndrii Nakryiko 	} else if (attr->link_update.old_prog_fd) {
41924adb7a4aSAndrii Nakryiko 		ret = -EINVAL;
41934adb7a4aSAndrii Nakryiko 		goto out_put_progs;
41940c991ebcSAndrii Nakryiko 	}
41950c991ebcSAndrii Nakryiko 
4196f9d04127SAndrii Nakryiko 	if (link->ops->update_prog)
4197f9d04127SAndrii Nakryiko 		ret = link->ops->update_prog(link, new_prog, old_prog);
4198f9d04127SAndrii Nakryiko 	else
41990c991ebcSAndrii Nakryiko 		ret = -EINVAL;
42000c991ebcSAndrii Nakryiko 
42010c991ebcSAndrii Nakryiko out_put_progs:
42020c991ebcSAndrii Nakryiko 	if (old_prog)
42030c991ebcSAndrii Nakryiko 		bpf_prog_put(old_prog);
42040c991ebcSAndrii Nakryiko 	if (ret)
42050c991ebcSAndrii Nakryiko 		bpf_prog_put(new_prog);
42064adb7a4aSAndrii Nakryiko out_put_link:
42074adb7a4aSAndrii Nakryiko 	bpf_link_put(link);
42080c991ebcSAndrii Nakryiko 	return ret;
42090c991ebcSAndrii Nakryiko }
42100c991ebcSAndrii Nakryiko 
421173b11c2aSAndrii Nakryiko #define BPF_LINK_DETACH_LAST_FIELD link_detach.link_fd
421273b11c2aSAndrii Nakryiko 
421373b11c2aSAndrii Nakryiko static int link_detach(union bpf_attr *attr)
421473b11c2aSAndrii Nakryiko {
421573b11c2aSAndrii Nakryiko 	struct bpf_link *link;
421673b11c2aSAndrii Nakryiko 	int ret;
421773b11c2aSAndrii Nakryiko 
421873b11c2aSAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_DETACH))
421973b11c2aSAndrii Nakryiko 		return -EINVAL;
422073b11c2aSAndrii Nakryiko 
422173b11c2aSAndrii Nakryiko 	link = bpf_link_get_from_fd(attr->link_detach.link_fd);
422273b11c2aSAndrii Nakryiko 	if (IS_ERR(link))
422373b11c2aSAndrii Nakryiko 		return PTR_ERR(link);
422473b11c2aSAndrii Nakryiko 
422573b11c2aSAndrii Nakryiko 	if (link->ops->detach)
422673b11c2aSAndrii Nakryiko 		ret = link->ops->detach(link);
422773b11c2aSAndrii Nakryiko 	else
422873b11c2aSAndrii Nakryiko 		ret = -EOPNOTSUPP;
422973b11c2aSAndrii Nakryiko 
423073b11c2aSAndrii Nakryiko 	bpf_link_put(link);
423173b11c2aSAndrii Nakryiko 	return ret;
423273b11c2aSAndrii Nakryiko }
423373b11c2aSAndrii Nakryiko 
4234005142b8SAlexei Starovoitov static struct bpf_link *bpf_link_inc_not_zero(struct bpf_link *link)
42352d602c8cSAndrii Nakryiko {
4236005142b8SAlexei Starovoitov 	return atomic64_fetch_add_unless(&link->refcnt, 1, 0) ? link : ERR_PTR(-ENOENT);
4237005142b8SAlexei Starovoitov }
4238005142b8SAlexei Starovoitov 
4239005142b8SAlexei Starovoitov struct bpf_link *bpf_link_by_id(u32 id)
4240005142b8SAlexei Starovoitov {
4241005142b8SAlexei Starovoitov 	struct bpf_link *link;
4242005142b8SAlexei Starovoitov 
4243005142b8SAlexei Starovoitov 	if (!id)
4244005142b8SAlexei Starovoitov 		return ERR_PTR(-ENOENT);
4245005142b8SAlexei Starovoitov 
4246005142b8SAlexei Starovoitov 	spin_lock_bh(&link_idr_lock);
4247005142b8SAlexei Starovoitov 	/* before link is "settled", ID is 0, pretend it doesn't exist yet */
4248005142b8SAlexei Starovoitov 	link = idr_find(&link_idr, id);
4249005142b8SAlexei Starovoitov 	if (link) {
4250005142b8SAlexei Starovoitov 		if (link->id)
4251005142b8SAlexei Starovoitov 			link = bpf_link_inc_not_zero(link);
4252005142b8SAlexei Starovoitov 		else
4253005142b8SAlexei Starovoitov 			link = ERR_PTR(-EAGAIN);
4254005142b8SAlexei Starovoitov 	} else {
4255005142b8SAlexei Starovoitov 		link = ERR_PTR(-ENOENT);
4256005142b8SAlexei Starovoitov 	}
4257005142b8SAlexei Starovoitov 	spin_unlock_bh(&link_idr_lock);
4258005142b8SAlexei Starovoitov 	return link;
42592d602c8cSAndrii Nakryiko }
42602d602c8cSAndrii Nakryiko 
42612d602c8cSAndrii Nakryiko #define BPF_LINK_GET_FD_BY_ID_LAST_FIELD link_id
42622d602c8cSAndrii Nakryiko 
42632d602c8cSAndrii Nakryiko static int bpf_link_get_fd_by_id(const union bpf_attr *attr)
42642d602c8cSAndrii Nakryiko {
42652d602c8cSAndrii Nakryiko 	struct bpf_link *link;
42662d602c8cSAndrii Nakryiko 	u32 id = attr->link_id;
4267005142b8SAlexei Starovoitov 	int fd;
42682d602c8cSAndrii Nakryiko 
42692d602c8cSAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_GET_FD_BY_ID))
42702d602c8cSAndrii Nakryiko 		return -EINVAL;
42712d602c8cSAndrii Nakryiko 
42722d602c8cSAndrii Nakryiko 	if (!capable(CAP_SYS_ADMIN))
42732d602c8cSAndrii Nakryiko 		return -EPERM;
42742d602c8cSAndrii Nakryiko 
4275005142b8SAlexei Starovoitov 	link = bpf_link_by_id(id);
4276005142b8SAlexei Starovoitov 	if (IS_ERR(link))
4277005142b8SAlexei Starovoitov 		return PTR_ERR(link);
42782d602c8cSAndrii Nakryiko 
42792d602c8cSAndrii Nakryiko 	fd = bpf_link_new_fd(link);
42802d602c8cSAndrii Nakryiko 	if (fd < 0)
42812d602c8cSAndrii Nakryiko 		bpf_link_put(link);
42822d602c8cSAndrii Nakryiko 
42832d602c8cSAndrii Nakryiko 	return fd;
42842d602c8cSAndrii Nakryiko }
42852d602c8cSAndrii Nakryiko 
4286d46edd67SSong Liu DEFINE_MUTEX(bpf_stats_enabled_mutex);
4287d46edd67SSong Liu 
4288d46edd67SSong Liu static int bpf_stats_release(struct inode *inode, struct file *file)
4289d46edd67SSong Liu {
4290d46edd67SSong Liu 	mutex_lock(&bpf_stats_enabled_mutex);
4291d46edd67SSong Liu 	static_key_slow_dec(&bpf_stats_enabled_key.key);
4292d46edd67SSong Liu 	mutex_unlock(&bpf_stats_enabled_mutex);
4293d46edd67SSong Liu 	return 0;
4294d46edd67SSong Liu }
4295d46edd67SSong Liu 
4296d46edd67SSong Liu static const struct file_operations bpf_stats_fops = {
4297d46edd67SSong Liu 	.release = bpf_stats_release,
4298d46edd67SSong Liu };
4299d46edd67SSong Liu 
4300d46edd67SSong Liu static int bpf_enable_runtime_stats(void)
4301d46edd67SSong Liu {
4302d46edd67SSong Liu 	int fd;
4303d46edd67SSong Liu 
4304d46edd67SSong Liu 	mutex_lock(&bpf_stats_enabled_mutex);
4305d46edd67SSong Liu 
4306d46edd67SSong Liu 	/* Set a very high limit to avoid overflow */
4307d46edd67SSong Liu 	if (static_key_count(&bpf_stats_enabled_key.key) > INT_MAX / 2) {
4308d46edd67SSong Liu 		mutex_unlock(&bpf_stats_enabled_mutex);
4309d46edd67SSong Liu 		return -EBUSY;
4310d46edd67SSong Liu 	}
4311d46edd67SSong Liu 
4312d46edd67SSong Liu 	fd = anon_inode_getfd("bpf-stats", &bpf_stats_fops, NULL, O_CLOEXEC);
4313d46edd67SSong Liu 	if (fd >= 0)
4314d46edd67SSong Liu 		static_key_slow_inc(&bpf_stats_enabled_key.key);
4315d46edd67SSong Liu 
4316d46edd67SSong Liu 	mutex_unlock(&bpf_stats_enabled_mutex);
4317d46edd67SSong Liu 	return fd;
4318d46edd67SSong Liu }
4319d46edd67SSong Liu 
4320d46edd67SSong Liu #define BPF_ENABLE_STATS_LAST_FIELD enable_stats.type
4321d46edd67SSong Liu 
4322d46edd67SSong Liu static int bpf_enable_stats(union bpf_attr *attr)
4323d46edd67SSong Liu {
4324d46edd67SSong Liu 
4325d46edd67SSong Liu 	if (CHECK_ATTR(BPF_ENABLE_STATS))
4326d46edd67SSong Liu 		return -EINVAL;
4327d46edd67SSong Liu 
4328d46edd67SSong Liu 	if (!capable(CAP_SYS_ADMIN))
4329d46edd67SSong Liu 		return -EPERM;
4330d46edd67SSong Liu 
4331d46edd67SSong Liu 	switch (attr->enable_stats.type) {
4332d46edd67SSong Liu 	case BPF_STATS_RUN_TIME:
4333d46edd67SSong Liu 		return bpf_enable_runtime_stats();
4334d46edd67SSong Liu 	default:
4335d46edd67SSong Liu 		break;
4336d46edd67SSong Liu 	}
4337d46edd67SSong Liu 	return -EINVAL;
4338d46edd67SSong Liu }
4339d46edd67SSong Liu 
4340ac51d99bSYonghong Song #define BPF_ITER_CREATE_LAST_FIELD iter_create.flags
4341ac51d99bSYonghong Song 
4342ac51d99bSYonghong Song static int bpf_iter_create(union bpf_attr *attr)
4343ac51d99bSYonghong Song {
4344ac51d99bSYonghong Song 	struct bpf_link *link;
4345ac51d99bSYonghong Song 	int err;
4346ac51d99bSYonghong Song 
4347ac51d99bSYonghong Song 	if (CHECK_ATTR(BPF_ITER_CREATE))
4348ac51d99bSYonghong Song 		return -EINVAL;
4349ac51d99bSYonghong Song 
4350ac51d99bSYonghong Song 	if (attr->iter_create.flags)
4351ac51d99bSYonghong Song 		return -EINVAL;
4352ac51d99bSYonghong Song 
4353ac51d99bSYonghong Song 	link = bpf_link_get_from_fd(attr->iter_create.link_fd);
4354ac51d99bSYonghong Song 	if (IS_ERR(link))
4355ac51d99bSYonghong Song 		return PTR_ERR(link);
4356ac51d99bSYonghong Song 
4357ac51d99bSYonghong Song 	err = bpf_iter_new_fd(link);
4358ac51d99bSYonghong Song 	bpf_link_put(link);
4359ac51d99bSYonghong Song 
4360ac51d99bSYonghong Song 	return err;
4361ac51d99bSYonghong Song }
4362ac51d99bSYonghong Song 
4363ef15314aSYiFei Zhu #define BPF_PROG_BIND_MAP_LAST_FIELD prog_bind_map.flags
4364ef15314aSYiFei Zhu 
4365ef15314aSYiFei Zhu static int bpf_prog_bind_map(union bpf_attr *attr)
4366ef15314aSYiFei Zhu {
4367ef15314aSYiFei Zhu 	struct bpf_prog *prog;
4368ef15314aSYiFei Zhu 	struct bpf_map *map;
4369ef15314aSYiFei Zhu 	struct bpf_map **used_maps_old, **used_maps_new;
4370ef15314aSYiFei Zhu 	int i, ret = 0;
4371ef15314aSYiFei Zhu 
4372ef15314aSYiFei Zhu 	if (CHECK_ATTR(BPF_PROG_BIND_MAP))
4373ef15314aSYiFei Zhu 		return -EINVAL;
4374ef15314aSYiFei Zhu 
4375ef15314aSYiFei Zhu 	if (attr->prog_bind_map.flags)
4376ef15314aSYiFei Zhu 		return -EINVAL;
4377ef15314aSYiFei Zhu 
4378ef15314aSYiFei Zhu 	prog = bpf_prog_get(attr->prog_bind_map.prog_fd);
4379ef15314aSYiFei Zhu 	if (IS_ERR(prog))
4380ef15314aSYiFei Zhu 		return PTR_ERR(prog);
4381ef15314aSYiFei Zhu 
4382ef15314aSYiFei Zhu 	map = bpf_map_get(attr->prog_bind_map.map_fd);
4383ef15314aSYiFei Zhu 	if (IS_ERR(map)) {
4384ef15314aSYiFei Zhu 		ret = PTR_ERR(map);
4385ef15314aSYiFei Zhu 		goto out_prog_put;
4386ef15314aSYiFei Zhu 	}
4387ef15314aSYiFei Zhu 
4388ef15314aSYiFei Zhu 	mutex_lock(&prog->aux->used_maps_mutex);
4389ef15314aSYiFei Zhu 
4390ef15314aSYiFei Zhu 	used_maps_old = prog->aux->used_maps;
4391ef15314aSYiFei Zhu 
4392ef15314aSYiFei Zhu 	for (i = 0; i < prog->aux->used_map_cnt; i++)
43931028ae40SStanislav Fomichev 		if (used_maps_old[i] == map) {
43941028ae40SStanislav Fomichev 			bpf_map_put(map);
4395ef15314aSYiFei Zhu 			goto out_unlock;
43961028ae40SStanislav Fomichev 		}
4397ef15314aSYiFei Zhu 
4398ef15314aSYiFei Zhu 	used_maps_new = kmalloc_array(prog->aux->used_map_cnt + 1,
4399ef15314aSYiFei Zhu 				      sizeof(used_maps_new[0]),
4400ef15314aSYiFei Zhu 				      GFP_KERNEL);
4401ef15314aSYiFei Zhu 	if (!used_maps_new) {
4402ef15314aSYiFei Zhu 		ret = -ENOMEM;
4403ef15314aSYiFei Zhu 		goto out_unlock;
4404ef15314aSYiFei Zhu 	}
4405ef15314aSYiFei Zhu 
4406ef15314aSYiFei Zhu 	memcpy(used_maps_new, used_maps_old,
4407ef15314aSYiFei Zhu 	       sizeof(used_maps_old[0]) * prog->aux->used_map_cnt);
4408ef15314aSYiFei Zhu 	used_maps_new[prog->aux->used_map_cnt] = map;
4409ef15314aSYiFei Zhu 
4410ef15314aSYiFei Zhu 	prog->aux->used_map_cnt++;
4411ef15314aSYiFei Zhu 	prog->aux->used_maps = used_maps_new;
4412ef15314aSYiFei Zhu 
4413ef15314aSYiFei Zhu 	kfree(used_maps_old);
4414ef15314aSYiFei Zhu 
4415ef15314aSYiFei Zhu out_unlock:
4416ef15314aSYiFei Zhu 	mutex_unlock(&prog->aux->used_maps_mutex);
4417ef15314aSYiFei Zhu 
4418ef15314aSYiFei Zhu 	if (ret)
4419ef15314aSYiFei Zhu 		bpf_map_put(map);
4420ef15314aSYiFei Zhu out_prog_put:
4421ef15314aSYiFei Zhu 	bpf_prog_put(prog);
4422ef15314aSYiFei Zhu 	return ret;
4423ef15314aSYiFei Zhu }
4424ef15314aSYiFei Zhu 
442599c55f7dSAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
442699c55f7dSAlexei Starovoitov {
44278096f229SGreg Kroah-Hartman 	union bpf_attr attr;
442899c55f7dSAlexei Starovoitov 	int err;
442999c55f7dSAlexei Starovoitov 
44302c78ee89SAlexei Starovoitov 	if (sysctl_unprivileged_bpf_disabled && !bpf_capable())
443199c55f7dSAlexei Starovoitov 		return -EPERM;
443299c55f7dSAlexei Starovoitov 
4433dcab51f1SMartin KaFai Lau 	err = bpf_check_uarg_tail_zero(uattr, sizeof(attr), size);
443499c55f7dSAlexei Starovoitov 	if (err)
443599c55f7dSAlexei Starovoitov 		return err;
44361e270976SMartin KaFai Lau 	size = min_t(u32, size, sizeof(attr));
443799c55f7dSAlexei Starovoitov 
443899c55f7dSAlexei Starovoitov 	/* copy attributes from user space, may be less than sizeof(bpf_attr) */
44398096f229SGreg Kroah-Hartman 	memset(&attr, 0, sizeof(attr));
444099c55f7dSAlexei Starovoitov 	if (copy_from_user(&attr, uattr, size) != 0)
444199c55f7dSAlexei Starovoitov 		return -EFAULT;
444299c55f7dSAlexei Starovoitov 
4443afdb09c7SChenbo Feng 	err = security_bpf(cmd, &attr, size);
4444afdb09c7SChenbo Feng 	if (err < 0)
4445afdb09c7SChenbo Feng 		return err;
4446afdb09c7SChenbo Feng 
444799c55f7dSAlexei Starovoitov 	switch (cmd) {
444899c55f7dSAlexei Starovoitov 	case BPF_MAP_CREATE:
444999c55f7dSAlexei Starovoitov 		err = map_create(&attr);
445099c55f7dSAlexei Starovoitov 		break;
4451db20fd2bSAlexei Starovoitov 	case BPF_MAP_LOOKUP_ELEM:
4452db20fd2bSAlexei Starovoitov 		err = map_lookup_elem(&attr);
4453db20fd2bSAlexei Starovoitov 		break;
4454db20fd2bSAlexei Starovoitov 	case BPF_MAP_UPDATE_ELEM:
4455db20fd2bSAlexei Starovoitov 		err = map_update_elem(&attr);
4456db20fd2bSAlexei Starovoitov 		break;
4457db20fd2bSAlexei Starovoitov 	case BPF_MAP_DELETE_ELEM:
4458db20fd2bSAlexei Starovoitov 		err = map_delete_elem(&attr);
4459db20fd2bSAlexei Starovoitov 		break;
4460db20fd2bSAlexei Starovoitov 	case BPF_MAP_GET_NEXT_KEY:
4461db20fd2bSAlexei Starovoitov 		err = map_get_next_key(&attr);
4462db20fd2bSAlexei Starovoitov 		break;
446387df15deSDaniel Borkmann 	case BPF_MAP_FREEZE:
446487df15deSDaniel Borkmann 		err = map_freeze(&attr);
446587df15deSDaniel Borkmann 		break;
446609756af4SAlexei Starovoitov 	case BPF_PROG_LOAD:
4467838e9690SYonghong Song 		err = bpf_prog_load(&attr, uattr);
446809756af4SAlexei Starovoitov 		break;
4469b2197755SDaniel Borkmann 	case BPF_OBJ_PIN:
4470b2197755SDaniel Borkmann 		err = bpf_obj_pin(&attr);
4471b2197755SDaniel Borkmann 		break;
4472b2197755SDaniel Borkmann 	case BPF_OBJ_GET:
4473b2197755SDaniel Borkmann 		err = bpf_obj_get(&attr);
4474b2197755SDaniel Borkmann 		break;
4475f4324551SDaniel Mack 	case BPF_PROG_ATTACH:
4476f4324551SDaniel Mack 		err = bpf_prog_attach(&attr);
4477f4324551SDaniel Mack 		break;
4478f4324551SDaniel Mack 	case BPF_PROG_DETACH:
4479f4324551SDaniel Mack 		err = bpf_prog_detach(&attr);
4480f4324551SDaniel Mack 		break;
4481468e2f64SAlexei Starovoitov 	case BPF_PROG_QUERY:
4482468e2f64SAlexei Starovoitov 		err = bpf_prog_query(&attr, uattr);
4483468e2f64SAlexei Starovoitov 		break;
44841cf1cae9SAlexei Starovoitov 	case BPF_PROG_TEST_RUN:
44851cf1cae9SAlexei Starovoitov 		err = bpf_prog_test_run(&attr, uattr);
44861cf1cae9SAlexei Starovoitov 		break;
448734ad5580SMartin KaFai Lau 	case BPF_PROG_GET_NEXT_ID:
448834ad5580SMartin KaFai Lau 		err = bpf_obj_get_next_id(&attr, uattr,
448934ad5580SMartin KaFai Lau 					  &prog_idr, &prog_idr_lock);
449034ad5580SMartin KaFai Lau 		break;
449134ad5580SMartin KaFai Lau 	case BPF_MAP_GET_NEXT_ID:
449234ad5580SMartin KaFai Lau 		err = bpf_obj_get_next_id(&attr, uattr,
449334ad5580SMartin KaFai Lau 					  &map_idr, &map_idr_lock);
449434ad5580SMartin KaFai Lau 		break;
44951b9ed84eSQuentin Monnet 	case BPF_BTF_GET_NEXT_ID:
44961b9ed84eSQuentin Monnet 		err = bpf_obj_get_next_id(&attr, uattr,
44971b9ed84eSQuentin Monnet 					  &btf_idr, &btf_idr_lock);
44981b9ed84eSQuentin Monnet 		break;
4499b16d9aa4SMartin KaFai Lau 	case BPF_PROG_GET_FD_BY_ID:
4500b16d9aa4SMartin KaFai Lau 		err = bpf_prog_get_fd_by_id(&attr);
4501b16d9aa4SMartin KaFai Lau 		break;
4502bd5f5f4eSMartin KaFai Lau 	case BPF_MAP_GET_FD_BY_ID:
4503bd5f5f4eSMartin KaFai Lau 		err = bpf_map_get_fd_by_id(&attr);
4504bd5f5f4eSMartin KaFai Lau 		break;
45051e270976SMartin KaFai Lau 	case BPF_OBJ_GET_INFO_BY_FD:
45061e270976SMartin KaFai Lau 		err = bpf_obj_get_info_by_fd(&attr, uattr);
45071e270976SMartin KaFai Lau 		break;
4508c4f6699dSAlexei Starovoitov 	case BPF_RAW_TRACEPOINT_OPEN:
4509c4f6699dSAlexei Starovoitov 		err = bpf_raw_tracepoint_open(&attr);
4510c4f6699dSAlexei Starovoitov 		break;
4511f56a653cSMartin KaFai Lau 	case BPF_BTF_LOAD:
4512f56a653cSMartin KaFai Lau 		err = bpf_btf_load(&attr);
4513f56a653cSMartin KaFai Lau 		break;
451478958fcaSMartin KaFai Lau 	case BPF_BTF_GET_FD_BY_ID:
451578958fcaSMartin KaFai Lau 		err = bpf_btf_get_fd_by_id(&attr);
451678958fcaSMartin KaFai Lau 		break;
451741bdc4b4SYonghong Song 	case BPF_TASK_FD_QUERY:
451841bdc4b4SYonghong Song 		err = bpf_task_fd_query(&attr, uattr);
451941bdc4b4SYonghong Song 		break;
4520bd513cd0SMauricio Vasquez B 	case BPF_MAP_LOOKUP_AND_DELETE_ELEM:
4521bd513cd0SMauricio Vasquez B 		err = map_lookup_and_delete_elem(&attr);
4522bd513cd0SMauricio Vasquez B 		break;
4523cb4d03abSBrian Vazquez 	case BPF_MAP_LOOKUP_BATCH:
4524cb4d03abSBrian Vazquez 		err = bpf_map_do_batch(&attr, uattr, BPF_MAP_LOOKUP_BATCH);
4525cb4d03abSBrian Vazquez 		break;
452605799638SYonghong Song 	case BPF_MAP_LOOKUP_AND_DELETE_BATCH:
452705799638SYonghong Song 		err = bpf_map_do_batch(&attr, uattr,
452805799638SYonghong Song 				       BPF_MAP_LOOKUP_AND_DELETE_BATCH);
452905799638SYonghong Song 		break;
4530aa2e93b8SBrian Vazquez 	case BPF_MAP_UPDATE_BATCH:
4531aa2e93b8SBrian Vazquez 		err = bpf_map_do_batch(&attr, uattr, BPF_MAP_UPDATE_BATCH);
4532aa2e93b8SBrian Vazquez 		break;
4533aa2e93b8SBrian Vazquez 	case BPF_MAP_DELETE_BATCH:
4534aa2e93b8SBrian Vazquez 		err = bpf_map_do_batch(&attr, uattr, BPF_MAP_DELETE_BATCH);
4535aa2e93b8SBrian Vazquez 		break;
4536af6eea57SAndrii Nakryiko 	case BPF_LINK_CREATE:
4537af6eea57SAndrii Nakryiko 		err = link_create(&attr);
4538af6eea57SAndrii Nakryiko 		break;
45390c991ebcSAndrii Nakryiko 	case BPF_LINK_UPDATE:
45400c991ebcSAndrii Nakryiko 		err = link_update(&attr);
45410c991ebcSAndrii Nakryiko 		break;
45422d602c8cSAndrii Nakryiko 	case BPF_LINK_GET_FD_BY_ID:
45432d602c8cSAndrii Nakryiko 		err = bpf_link_get_fd_by_id(&attr);
45442d602c8cSAndrii Nakryiko 		break;
45452d602c8cSAndrii Nakryiko 	case BPF_LINK_GET_NEXT_ID:
45462d602c8cSAndrii Nakryiko 		err = bpf_obj_get_next_id(&attr, uattr,
45472d602c8cSAndrii Nakryiko 					  &link_idr, &link_idr_lock);
45482d602c8cSAndrii Nakryiko 		break;
4549d46edd67SSong Liu 	case BPF_ENABLE_STATS:
4550d46edd67SSong Liu 		err = bpf_enable_stats(&attr);
4551d46edd67SSong Liu 		break;
4552ac51d99bSYonghong Song 	case BPF_ITER_CREATE:
4553ac51d99bSYonghong Song 		err = bpf_iter_create(&attr);
4554ac51d99bSYonghong Song 		break;
455573b11c2aSAndrii Nakryiko 	case BPF_LINK_DETACH:
455673b11c2aSAndrii Nakryiko 		err = link_detach(&attr);
455773b11c2aSAndrii Nakryiko 		break;
4558ef15314aSYiFei Zhu 	case BPF_PROG_BIND_MAP:
4559ef15314aSYiFei Zhu 		err = bpf_prog_bind_map(&attr);
4560ef15314aSYiFei Zhu 		break;
456199c55f7dSAlexei Starovoitov 	default:
456299c55f7dSAlexei Starovoitov 		err = -EINVAL;
456399c55f7dSAlexei Starovoitov 		break;
456499c55f7dSAlexei Starovoitov 	}
456599c55f7dSAlexei Starovoitov 
456699c55f7dSAlexei Starovoitov 	return err;
456799c55f7dSAlexei Starovoitov }
4568