xref: /linux/kernel/bpf/syscall.c (revision c22dfdd21592c5d56b49d5fba8de300ad7bf293c)
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>
5aef2fedaSJakub Kicinski #include <linux/bpf-cgroup.h>
6a67edbf4SDaniel Borkmann #include <linux/bpf_trace.h>
7f4364dcfSSean Young #include <linux/bpf_lirc.h>
84a1e7c0cSToke Høiland-Jørgensen #include <linux/bpf_verifier.h>
961df10c7SKumar Kartikeya Dwivedi #include <linux/bsearch.h>
10f56a653cSMartin KaFai Lau #include <linux/btf.h>
1199c55f7dSAlexei Starovoitov #include <linux/syscalls.h>
1299c55f7dSAlexei Starovoitov #include <linux/slab.h>
133f07c014SIngo Molnar #include <linux/sched/signal.h>
14d407bd25SDaniel Borkmann #include <linux/vmalloc.h>
15d407bd25SDaniel Borkmann #include <linux/mmzone.h>
1699c55f7dSAlexei Starovoitov #include <linux/anon_inodes.h>
1741bdc4b4SYonghong Song #include <linux/fdtable.h>
18db20fd2bSAlexei Starovoitov #include <linux/file.h>
1941bdc4b4SYonghong Song #include <linux/fs.h>
2009756af4SAlexei Starovoitov #include <linux/license.h>
2109756af4SAlexei Starovoitov #include <linux/filter.h>
22535e7b4bSMickaël Salaün #include <linux/kernel.h>
23dc4bb0e2SMartin KaFai Lau #include <linux/idr.h>
24cb4d2b3fSMartin KaFai Lau #include <linux/cred.h>
25cb4d2b3fSMartin KaFai Lau #include <linux/timekeeping.h>
26cb4d2b3fSMartin KaFai Lau #include <linux/ctype.h>
279ef09e35SMark Rutland #include <linux/nospec.h>
28bae141f5SDaniel Borkmann #include <linux/audit.h>
29ccfe29ebSAlexei Starovoitov #include <uapi/linux/btf.h>
30ca5999fdSMike Rapoport #include <linux/pgtable.h>
319e4e01dfSKP Singh #include <linux/bpf_lsm.h>
32457f4436SAndrii Nakryiko #include <linux/poll.h>
334d7d7f69SKumar Kartikeya Dwivedi #include <linux/sort.h>
34a3fd7ceeSJakub Sitnicki #include <linux/bpf-netns.h>
351e6c62a8SAlexei Starovoitov #include <linux/rcupdate_trace.h>
3648edc1f7SRoman Gushchin #include <linux/memcontrol.h>
370dcac272SJiri Olsa #include <linux/trace_events.h>
3899c55f7dSAlexei Starovoitov 
39da765a2fSDaniel Borkmann #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \
4014dc6f04SMartin KaFai Lau 			  (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \
4114dc6f04SMartin KaFai Lau 			  (map)->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS)
42da765a2fSDaniel Borkmann #define IS_FD_PROG_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY)
4314dc6f04SMartin KaFai Lau #define IS_FD_HASH(map) ((map)->map_type == BPF_MAP_TYPE_HASH_OF_MAPS)
44da765a2fSDaniel Borkmann #define IS_FD_MAP(map) (IS_FD_ARRAY(map) || IS_FD_PROG_ARRAY(map) || \
45da765a2fSDaniel Borkmann 			IS_FD_HASH(map))
4614dc6f04SMartin KaFai Lau 
476e71b04aSChenbo Feng #define BPF_OBJ_FLAG_MASK   (BPF_F_RDONLY | BPF_F_WRONLY)
486e71b04aSChenbo Feng 
49b121d1e7SAlexei Starovoitov DEFINE_PER_CPU(int, bpf_prog_active);
50dc4bb0e2SMartin KaFai Lau static DEFINE_IDR(prog_idr);
51dc4bb0e2SMartin KaFai Lau static DEFINE_SPINLOCK(prog_idr_lock);
52f3f1c054SMartin KaFai Lau static DEFINE_IDR(map_idr);
53f3f1c054SMartin KaFai Lau static DEFINE_SPINLOCK(map_idr_lock);
54a3b80e10SAndrii Nakryiko static DEFINE_IDR(link_idr);
55a3b80e10SAndrii Nakryiko static DEFINE_SPINLOCK(link_idr_lock);
56b121d1e7SAlexei Starovoitov 
5708389d88SDaniel Borkmann int sysctl_unprivileged_bpf_disabled __read_mostly =
5808389d88SDaniel Borkmann 	IS_BUILTIN(CONFIG_BPF_UNPRIV_DEFAULT_OFF) ? 2 : 0;
591be7f75dSAlexei Starovoitov 
6040077e0cSJohannes Berg static const struct bpf_map_ops * const bpf_map_types[] = {
6191cc1a99SAlexei Starovoitov #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type)
6240077e0cSJohannes Berg #define BPF_MAP_TYPE(_id, _ops) \
6340077e0cSJohannes Berg 	[_id] = &_ops,
64f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name)
6540077e0cSJohannes Berg #include <linux/bpf_types.h>
6640077e0cSJohannes Berg #undef BPF_PROG_TYPE
6740077e0cSJohannes Berg #undef BPF_MAP_TYPE
68f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE
6940077e0cSJohannes Berg };
7099c55f7dSAlexei Starovoitov 
71752ba56fSMickaël Salaün /*
72752ba56fSMickaël Salaün  * If we're handed a bigger struct than we know of, ensure all the unknown bits
73752ba56fSMickaël Salaün  * are 0 - i.e. new user-space does not rely on any kernel feature extensions
74752ba56fSMickaël Salaün  * we don't know about yet.
75752ba56fSMickaël Salaün  *
76752ba56fSMickaël Salaün  * There is a ToCToU between this function call and the following
77752ba56fSMickaël Salaün  * copy_from_user() call. However, this is not a concern since this function is
78752ba56fSMickaël Salaün  * meant to be a future-proofing of bits.
79752ba56fSMickaël Salaün  */
80af2ac3e1SAlexei Starovoitov int bpf_check_uarg_tail_zero(bpfptr_t uaddr,
8158291a74SMickaël Salaün 			     size_t expected_size,
8258291a74SMickaël Salaün 			     size_t actual_size)
8358291a74SMickaël Salaün {
84b7e4b65fSAl Viro 	int res;
8558291a74SMickaël Salaün 
86752ba56fSMickaël Salaün 	if (unlikely(actual_size > PAGE_SIZE))	/* silly large */
87752ba56fSMickaël Salaün 		return -E2BIG;
88752ba56fSMickaël Salaün 
8958291a74SMickaël Salaün 	if (actual_size <= expected_size)
9058291a74SMickaël Salaün 		return 0;
9158291a74SMickaël Salaün 
92af2ac3e1SAlexei Starovoitov 	if (uaddr.is_kernel)
93af2ac3e1SAlexei Starovoitov 		res = memchr_inv(uaddr.kernel + expected_size, 0,
94af2ac3e1SAlexei Starovoitov 				 actual_size - expected_size) == NULL;
95af2ac3e1SAlexei Starovoitov 	else
96af2ac3e1SAlexei Starovoitov 		res = check_zeroed_user(uaddr.user + expected_size,
97af2ac3e1SAlexei Starovoitov 					actual_size - expected_size);
98b7e4b65fSAl Viro 	if (res < 0)
99b7e4b65fSAl Viro 		return res;
100b7e4b65fSAl Viro 	return res ? 0 : -E2BIG;
10158291a74SMickaël Salaün }
10258291a74SMickaël Salaün 
103a3884572SJakub Kicinski const struct bpf_map_ops bpf_map_offload_ops = {
104f4d05259SMartin KaFai Lau 	.map_meta_equal = bpf_map_meta_equal,
105a3884572SJakub Kicinski 	.map_alloc = bpf_map_offload_map_alloc,
106a3884572SJakub Kicinski 	.map_free = bpf_map_offload_map_free,
107e8d2bec0SDaniel Borkmann 	.map_check_btf = map_check_no_btf,
108a3884572SJakub Kicinski };
109a3884572SJakub Kicinski 
11099c55f7dSAlexei Starovoitov static struct bpf_map *find_and_alloc_map(union bpf_attr *attr)
11199c55f7dSAlexei Starovoitov {
1121110f3a9SJakub Kicinski 	const struct bpf_map_ops *ops;
1139ef09e35SMark Rutland 	u32 type = attr->map_type;
11499c55f7dSAlexei Starovoitov 	struct bpf_map *map;
1151110f3a9SJakub Kicinski 	int err;
11699c55f7dSAlexei Starovoitov 
1179ef09e35SMark Rutland 	if (type >= ARRAY_SIZE(bpf_map_types))
1181110f3a9SJakub Kicinski 		return ERR_PTR(-EINVAL);
1199ef09e35SMark Rutland 	type = array_index_nospec(type, ARRAY_SIZE(bpf_map_types));
1209ef09e35SMark Rutland 	ops = bpf_map_types[type];
1211110f3a9SJakub Kicinski 	if (!ops)
12240077e0cSJohannes Berg 		return ERR_PTR(-EINVAL);
12340077e0cSJohannes Berg 
1241110f3a9SJakub Kicinski 	if (ops->map_alloc_check) {
1251110f3a9SJakub Kicinski 		err = ops->map_alloc_check(attr);
1261110f3a9SJakub Kicinski 		if (err)
1271110f3a9SJakub Kicinski 			return ERR_PTR(err);
1281110f3a9SJakub Kicinski 	}
129a3884572SJakub Kicinski 	if (attr->map_ifindex)
130a3884572SJakub Kicinski 		ops = &bpf_map_offload_ops;
1311110f3a9SJakub Kicinski 	map = ops->map_alloc(attr);
13299c55f7dSAlexei Starovoitov 	if (IS_ERR(map))
13399c55f7dSAlexei Starovoitov 		return map;
1341110f3a9SJakub Kicinski 	map->ops = ops;
1359ef09e35SMark Rutland 	map->map_type = type;
13699c55f7dSAlexei Starovoitov 	return map;
13799c55f7dSAlexei Starovoitov }
13899c55f7dSAlexei Starovoitov 
139353050beSDaniel Borkmann static void bpf_map_write_active_inc(struct bpf_map *map)
140353050beSDaniel Borkmann {
141353050beSDaniel Borkmann 	atomic64_inc(&map->writecnt);
142353050beSDaniel Borkmann }
143353050beSDaniel Borkmann 
144353050beSDaniel Borkmann static void bpf_map_write_active_dec(struct bpf_map *map)
145353050beSDaniel Borkmann {
146353050beSDaniel Borkmann 	atomic64_dec(&map->writecnt);
147353050beSDaniel Borkmann }
148353050beSDaniel Borkmann 
149353050beSDaniel Borkmann bool bpf_map_write_active(const struct bpf_map *map)
150353050beSDaniel Borkmann {
151353050beSDaniel Borkmann 	return atomic64_read(&map->writecnt) != 0;
152353050beSDaniel Borkmann }
153353050beSDaniel Borkmann 
15480ee81e0SRoman Gushchin static u32 bpf_map_value_size(const struct bpf_map *map)
15515c14a3dSBrian Vazquez {
15615c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
15715c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
15815c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY ||
15915c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE)
16015c14a3dSBrian Vazquez 		return round_up(map->value_size, 8) * num_possible_cpus();
16115c14a3dSBrian Vazquez 	else if (IS_FD_MAP(map))
16215c14a3dSBrian Vazquez 		return sizeof(u32);
16315c14a3dSBrian Vazquez 	else
16415c14a3dSBrian Vazquez 		return  map->value_size;
16515c14a3dSBrian Vazquez }
16615c14a3dSBrian Vazquez 
16715c14a3dSBrian Vazquez static void maybe_wait_bpf_programs(struct bpf_map *map)
16815c14a3dSBrian Vazquez {
16915c14a3dSBrian Vazquez 	/* Wait for any running BPF programs to complete so that
17015c14a3dSBrian Vazquez 	 * userspace, when we return to it, knows that all programs
17115c14a3dSBrian Vazquez 	 * that could be running use the new map value.
17215c14a3dSBrian Vazquez 	 */
17315c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS ||
17415c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS)
17515c14a3dSBrian Vazquez 		synchronize_rcu();
17615c14a3dSBrian Vazquez }
17715c14a3dSBrian Vazquez 
1783af43ba4SHou Tao static int bpf_map_update_value(struct bpf_map *map, struct file *map_file,
1793af43ba4SHou Tao 				void *key, void *value, __u64 flags)
18015c14a3dSBrian Vazquez {
18115c14a3dSBrian Vazquez 	int err;
18215c14a3dSBrian Vazquez 
18315c14a3dSBrian Vazquez 	/* Need to create a kthread, thus must support schedule */
18415c14a3dSBrian Vazquez 	if (bpf_map_is_dev_bound(map)) {
18515c14a3dSBrian Vazquez 		return bpf_map_offload_update_elem(map, key, value, flags);
18615c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_CPUMAP ||
18715c14a3dSBrian Vazquez 		   map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
18815c14a3dSBrian Vazquez 		return map->ops->map_update_elem(map, key, value, flags);
18913b79d3fSLorenz Bauer 	} else if (map->map_type == BPF_MAP_TYPE_SOCKHASH ||
19013b79d3fSLorenz Bauer 		   map->map_type == BPF_MAP_TYPE_SOCKMAP) {
19113b79d3fSLorenz Bauer 		return sock_map_update_elem_sys(map, key, value, flags);
19215c14a3dSBrian Vazquez 	} else if (IS_FD_PROG_ARRAY(map)) {
1933af43ba4SHou Tao 		return bpf_fd_array_map_update_elem(map, map_file, key, value,
19415c14a3dSBrian Vazquez 						    flags);
19515c14a3dSBrian Vazquez 	}
19615c14a3dSBrian Vazquez 
197b6e5dae1SThomas Gleixner 	bpf_disable_instrumentation();
19815c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
19915c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
20015c14a3dSBrian Vazquez 		err = bpf_percpu_hash_update(map, key, value, flags);
20115c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
20215c14a3dSBrian Vazquez 		err = bpf_percpu_array_update(map, key, value, flags);
20315c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
20415c14a3dSBrian Vazquez 		err = bpf_percpu_cgroup_storage_update(map, key, value,
20515c14a3dSBrian Vazquez 						       flags);
20615c14a3dSBrian Vazquez 	} else if (IS_FD_ARRAY(map)) {
20715c14a3dSBrian Vazquez 		rcu_read_lock();
2083af43ba4SHou Tao 		err = bpf_fd_array_map_update_elem(map, map_file, key, value,
20915c14a3dSBrian Vazquez 						   flags);
21015c14a3dSBrian Vazquez 		rcu_read_unlock();
21115c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) {
21215c14a3dSBrian Vazquez 		rcu_read_lock();
2133af43ba4SHou Tao 		err = bpf_fd_htab_map_update_elem(map, map_file, key, value,
21415c14a3dSBrian Vazquez 						  flags);
21515c14a3dSBrian Vazquez 		rcu_read_unlock();
21615c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
21715c14a3dSBrian Vazquez 		/* rcu_read_lock() is not needed */
21815c14a3dSBrian Vazquez 		err = bpf_fd_reuseport_array_update_elem(map, key, value,
21915c14a3dSBrian Vazquez 							 flags);
22015c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
2219330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_STACK ||
2229330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) {
22315c14a3dSBrian Vazquez 		err = map->ops->map_push_elem(map, value, flags);
22415c14a3dSBrian Vazquez 	} else {
22515c14a3dSBrian Vazquez 		rcu_read_lock();
22615c14a3dSBrian Vazquez 		err = map->ops->map_update_elem(map, key, value, flags);
22715c14a3dSBrian Vazquez 		rcu_read_unlock();
22815c14a3dSBrian Vazquez 	}
229b6e5dae1SThomas Gleixner 	bpf_enable_instrumentation();
23015c14a3dSBrian Vazquez 	maybe_wait_bpf_programs(map);
23115c14a3dSBrian Vazquez 
23215c14a3dSBrian Vazquez 	return err;
23315c14a3dSBrian Vazquez }
23415c14a3dSBrian Vazquez 
23515c14a3dSBrian Vazquez static int bpf_map_copy_value(struct bpf_map *map, void *key, void *value,
23615c14a3dSBrian Vazquez 			      __u64 flags)
23715c14a3dSBrian Vazquez {
23815c14a3dSBrian Vazquez 	void *ptr;
23915c14a3dSBrian Vazquez 	int err;
24015c14a3dSBrian Vazquez 
241cb4d03abSBrian Vazquez 	if (bpf_map_is_dev_bound(map))
242cb4d03abSBrian Vazquez 		return bpf_map_offload_lookup_elem(map, key, value);
24315c14a3dSBrian Vazquez 
244b6e5dae1SThomas Gleixner 	bpf_disable_instrumentation();
24515c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
24615c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
24715c14a3dSBrian Vazquez 		err = bpf_percpu_hash_copy(map, key, value);
24815c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
24915c14a3dSBrian Vazquez 		err = bpf_percpu_array_copy(map, key, value);
25015c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
25115c14a3dSBrian Vazquez 		err = bpf_percpu_cgroup_storage_copy(map, key, value);
25215c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) {
25315c14a3dSBrian Vazquez 		err = bpf_stackmap_copy(map, key, value);
25415c14a3dSBrian Vazquez 	} else if (IS_FD_ARRAY(map) || IS_FD_PROG_ARRAY(map)) {
25515c14a3dSBrian Vazquez 		err = bpf_fd_array_map_lookup_elem(map, key, value);
25615c14a3dSBrian Vazquez 	} else if (IS_FD_HASH(map)) {
25715c14a3dSBrian Vazquez 		err = bpf_fd_htab_map_lookup_elem(map, key, value);
25815c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
25915c14a3dSBrian Vazquez 		err = bpf_fd_reuseport_array_lookup_elem(map, key, value);
26015c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
2619330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_STACK ||
2629330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) {
26315c14a3dSBrian Vazquez 		err = map->ops->map_peek_elem(map, value);
26415c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
26515c14a3dSBrian Vazquez 		/* struct_ops map requires directly updating "value" */
26615c14a3dSBrian Vazquez 		err = bpf_struct_ops_map_sys_lookup_elem(map, key, value);
26715c14a3dSBrian Vazquez 	} else {
26815c14a3dSBrian Vazquez 		rcu_read_lock();
26915c14a3dSBrian Vazquez 		if (map->ops->map_lookup_elem_sys_only)
27015c14a3dSBrian Vazquez 			ptr = map->ops->map_lookup_elem_sys_only(map, key);
27115c14a3dSBrian Vazquez 		else
27215c14a3dSBrian Vazquez 			ptr = map->ops->map_lookup_elem(map, key);
27315c14a3dSBrian Vazquez 		if (IS_ERR(ptr)) {
27415c14a3dSBrian Vazquez 			err = PTR_ERR(ptr);
27515c14a3dSBrian Vazquez 		} else if (!ptr) {
27615c14a3dSBrian Vazquez 			err = -ENOENT;
27715c14a3dSBrian Vazquez 		} else {
27815c14a3dSBrian Vazquez 			err = 0;
27915c14a3dSBrian Vazquez 			if (flags & BPF_F_LOCK)
28015c14a3dSBrian Vazquez 				/* lock 'ptr' and copy everything but lock */
28115c14a3dSBrian Vazquez 				copy_map_value_locked(map, value, ptr, true);
28215c14a3dSBrian Vazquez 			else
28315c14a3dSBrian Vazquez 				copy_map_value(map, value, ptr);
28468134668SAlexei Starovoitov 			/* mask lock and timer, since value wasn't zero inited */
28568134668SAlexei Starovoitov 			check_and_init_map_value(map, value);
28615c14a3dSBrian Vazquez 		}
28715c14a3dSBrian Vazquez 		rcu_read_unlock();
28815c14a3dSBrian Vazquez 	}
28915c14a3dSBrian Vazquez 
290b6e5dae1SThomas Gleixner 	bpf_enable_instrumentation();
29115c14a3dSBrian Vazquez 	maybe_wait_bpf_programs(map);
29215c14a3dSBrian Vazquez 
29315c14a3dSBrian Vazquez 	return err;
29415c14a3dSBrian Vazquez }
29515c14a3dSBrian Vazquez 
296d5299b67SRoman Gushchin /* Please, do not use this function outside from the map creation path
297d5299b67SRoman Gushchin  * (e.g. in map update path) without taking care of setting the active
298d5299b67SRoman Gushchin  * memory cgroup (see at bpf_map_kmalloc_node() for example).
299d5299b67SRoman Gushchin  */
300196e8ca7SDaniel Borkmann static void *__bpf_map_area_alloc(u64 size, int numa_node, bool mmapable)
301d407bd25SDaniel Borkmann {
302f01a7dbeSMartynas Pumputis 	/* We really just want to fail instead of triggering OOM killer
303f01a7dbeSMartynas Pumputis 	 * under memory pressure, therefore we set __GFP_NORETRY to kmalloc,
304f01a7dbeSMartynas Pumputis 	 * which is used for lower order allocation requests.
305f01a7dbeSMartynas Pumputis 	 *
306f01a7dbeSMartynas Pumputis 	 * It has been observed that higher order allocation requests done by
307f01a7dbeSMartynas Pumputis 	 * vmalloc with __GFP_NORETRY being set might fail due to not trying
308f01a7dbeSMartynas Pumputis 	 * to reclaim memory from the page cache, thus we set
309f01a7dbeSMartynas Pumputis 	 * __GFP_RETRY_MAYFAIL to avoid such situations.
310d407bd25SDaniel Borkmann 	 */
311f01a7dbeSMartynas Pumputis 
312d5299b67SRoman Gushchin 	const gfp_t gfp = __GFP_NOWARN | __GFP_ZERO | __GFP_ACCOUNT;
313041de93fSChristoph Hellwig 	unsigned int flags = 0;
314041de93fSChristoph Hellwig 	unsigned long align = 1;
315d407bd25SDaniel Borkmann 	void *area;
316d407bd25SDaniel Borkmann 
317196e8ca7SDaniel Borkmann 	if (size >= SIZE_MAX)
318196e8ca7SDaniel Borkmann 		return NULL;
319196e8ca7SDaniel Borkmann 
320fc970227SAndrii Nakryiko 	/* kmalloc()'ed memory can't be mmap()'ed */
321041de93fSChristoph Hellwig 	if (mmapable) {
322041de93fSChristoph Hellwig 		BUG_ON(!PAGE_ALIGNED(size));
323041de93fSChristoph Hellwig 		align = SHMLBA;
324041de93fSChristoph Hellwig 		flags = VM_USERMAP;
325041de93fSChristoph Hellwig 	} else if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
326041de93fSChristoph Hellwig 		area = kmalloc_node(size, gfp | GFP_USER | __GFP_NORETRY,
327f01a7dbeSMartynas Pumputis 				    numa_node);
328d407bd25SDaniel Borkmann 		if (area != NULL)
329d407bd25SDaniel Borkmann 			return area;
330d407bd25SDaniel Borkmann 	}
331041de93fSChristoph Hellwig 
332041de93fSChristoph Hellwig 	return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END,
333041de93fSChristoph Hellwig 			gfp | GFP_KERNEL | __GFP_RETRY_MAYFAIL, PAGE_KERNEL,
334041de93fSChristoph Hellwig 			flags, numa_node, __builtin_return_address(0));
335d407bd25SDaniel Borkmann }
336d407bd25SDaniel Borkmann 
337196e8ca7SDaniel Borkmann void *bpf_map_area_alloc(u64 size, int numa_node)
338fc970227SAndrii Nakryiko {
339fc970227SAndrii Nakryiko 	return __bpf_map_area_alloc(size, numa_node, false);
340fc970227SAndrii Nakryiko }
341fc970227SAndrii Nakryiko 
342196e8ca7SDaniel Borkmann void *bpf_map_area_mmapable_alloc(u64 size, int numa_node)
343fc970227SAndrii Nakryiko {
344fc970227SAndrii Nakryiko 	return __bpf_map_area_alloc(size, numa_node, true);
345fc970227SAndrii Nakryiko }
346fc970227SAndrii Nakryiko 
347d407bd25SDaniel Borkmann void bpf_map_area_free(void *area)
348d407bd25SDaniel Borkmann {
349d407bd25SDaniel Borkmann 	kvfree(area);
350d407bd25SDaniel Borkmann }
351d407bd25SDaniel Borkmann 
352be70bcd5SDaniel Borkmann static u32 bpf_map_flags_retain_permanent(u32 flags)
353be70bcd5SDaniel Borkmann {
354be70bcd5SDaniel Borkmann 	/* Some map creation flags are not tied to the map object but
355be70bcd5SDaniel Borkmann 	 * rather to the map fd instead, so they have no meaning upon
356be70bcd5SDaniel Borkmann 	 * map object inspection since multiple file descriptors with
357be70bcd5SDaniel Borkmann 	 * different (access) properties can exist here. Thus, given
358be70bcd5SDaniel Borkmann 	 * this has zero meaning for the map itself, lets clear these
359be70bcd5SDaniel Borkmann 	 * from here.
360be70bcd5SDaniel Borkmann 	 */
361be70bcd5SDaniel Borkmann 	return flags & ~(BPF_F_RDONLY | BPF_F_WRONLY);
362be70bcd5SDaniel Borkmann }
363be70bcd5SDaniel Borkmann 
364bd475643SJakub Kicinski void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr)
365bd475643SJakub Kicinski {
366bd475643SJakub Kicinski 	map->map_type = attr->map_type;
367bd475643SJakub Kicinski 	map->key_size = attr->key_size;
368bd475643SJakub Kicinski 	map->value_size = attr->value_size;
369bd475643SJakub Kicinski 	map->max_entries = attr->max_entries;
370be70bcd5SDaniel Borkmann 	map->map_flags = bpf_map_flags_retain_permanent(attr->map_flags);
371bd475643SJakub Kicinski 	map->numa_node = bpf_map_attr_numa_node(attr);
3729330986cSJoanne Koong 	map->map_extra = attr->map_extra;
373bd475643SJakub Kicinski }
374bd475643SJakub Kicinski 
375f3f1c054SMartin KaFai Lau static int bpf_map_alloc_id(struct bpf_map *map)
376f3f1c054SMartin KaFai Lau {
377f3f1c054SMartin KaFai Lau 	int id;
378f3f1c054SMartin KaFai Lau 
379b76354cdSShaohua Li 	idr_preload(GFP_KERNEL);
380f3f1c054SMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
381f3f1c054SMartin KaFai Lau 	id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC);
382f3f1c054SMartin KaFai Lau 	if (id > 0)
383f3f1c054SMartin KaFai Lau 		map->id = id;
384f3f1c054SMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
385b76354cdSShaohua Li 	idr_preload_end();
386f3f1c054SMartin KaFai Lau 
387f3f1c054SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
388f3f1c054SMartin KaFai Lau 		return -ENOSPC;
389f3f1c054SMartin KaFai Lau 
390f3f1c054SMartin KaFai Lau 	return id > 0 ? 0 : id;
391f3f1c054SMartin KaFai Lau }
392f3f1c054SMartin KaFai Lau 
393a3884572SJakub Kicinski void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock)
394f3f1c054SMartin KaFai Lau {
395930651a7SEric Dumazet 	unsigned long flags;
396930651a7SEric Dumazet 
397a3884572SJakub Kicinski 	/* Offloaded maps are removed from the IDR store when their device
398a3884572SJakub Kicinski 	 * disappears - even if someone holds an fd to them they are unusable,
399a3884572SJakub Kicinski 	 * the memory is gone, all ops will fail; they are simply waiting for
400a3884572SJakub Kicinski 	 * refcnt to drop to be freed.
401a3884572SJakub Kicinski 	 */
402a3884572SJakub Kicinski 	if (!map->id)
403a3884572SJakub Kicinski 		return;
404a3884572SJakub Kicinski 
405bd5f5f4eSMartin KaFai Lau 	if (do_idr_lock)
406930651a7SEric Dumazet 		spin_lock_irqsave(&map_idr_lock, flags);
407bd5f5f4eSMartin KaFai Lau 	else
408bd5f5f4eSMartin KaFai Lau 		__acquire(&map_idr_lock);
409bd5f5f4eSMartin KaFai Lau 
410f3f1c054SMartin KaFai Lau 	idr_remove(&map_idr, map->id);
411a3884572SJakub Kicinski 	map->id = 0;
412bd5f5f4eSMartin KaFai Lau 
413bd5f5f4eSMartin KaFai Lau 	if (do_idr_lock)
414930651a7SEric Dumazet 		spin_unlock_irqrestore(&map_idr_lock, flags);
415bd5f5f4eSMartin KaFai Lau 	else
416bd5f5f4eSMartin KaFai Lau 		__release(&map_idr_lock);
417f3f1c054SMartin KaFai Lau }
418f3f1c054SMartin KaFai Lau 
41948edc1f7SRoman Gushchin #ifdef CONFIG_MEMCG_KMEM
42048edc1f7SRoman Gushchin static void bpf_map_save_memcg(struct bpf_map *map)
42148edc1f7SRoman Gushchin {
4224201d9abSRoman Gushchin 	/* Currently if a map is created by a process belonging to the root
4234201d9abSRoman Gushchin 	 * memory cgroup, get_obj_cgroup_from_current() will return NULL.
4244201d9abSRoman Gushchin 	 * So we have to check map->objcg for being NULL each time it's
4254201d9abSRoman Gushchin 	 * being used.
4264201d9abSRoman Gushchin 	 */
4274201d9abSRoman Gushchin 	map->objcg = get_obj_cgroup_from_current();
42848edc1f7SRoman Gushchin }
42948edc1f7SRoman Gushchin 
43048edc1f7SRoman Gushchin static void bpf_map_release_memcg(struct bpf_map *map)
43148edc1f7SRoman Gushchin {
4324201d9abSRoman Gushchin 	if (map->objcg)
4334201d9abSRoman Gushchin 		obj_cgroup_put(map->objcg);
4344201d9abSRoman Gushchin }
4354201d9abSRoman Gushchin 
4364201d9abSRoman Gushchin static struct mem_cgroup *bpf_map_get_memcg(const struct bpf_map *map)
4374201d9abSRoman Gushchin {
4384201d9abSRoman Gushchin 	if (map->objcg)
4394201d9abSRoman Gushchin 		return get_mem_cgroup_from_objcg(map->objcg);
4404201d9abSRoman Gushchin 
4414201d9abSRoman Gushchin 	return root_mem_cgroup;
44248edc1f7SRoman Gushchin }
44348edc1f7SRoman Gushchin 
44448edc1f7SRoman Gushchin void *bpf_map_kmalloc_node(const struct bpf_map *map, size_t size, gfp_t flags,
44548edc1f7SRoman Gushchin 			   int node)
44648edc1f7SRoman Gushchin {
4474201d9abSRoman Gushchin 	struct mem_cgroup *memcg, *old_memcg;
44848edc1f7SRoman Gushchin 	void *ptr;
44948edc1f7SRoman Gushchin 
4504201d9abSRoman Gushchin 	memcg = bpf_map_get_memcg(map);
4514201d9abSRoman Gushchin 	old_memcg = set_active_memcg(memcg);
45248edc1f7SRoman Gushchin 	ptr = kmalloc_node(size, flags | __GFP_ACCOUNT, node);
45348edc1f7SRoman Gushchin 	set_active_memcg(old_memcg);
4544201d9abSRoman Gushchin 	mem_cgroup_put(memcg);
45548edc1f7SRoman Gushchin 
45648edc1f7SRoman Gushchin 	return ptr;
45748edc1f7SRoman Gushchin }
45848edc1f7SRoman Gushchin 
45948edc1f7SRoman Gushchin void *bpf_map_kzalloc(const struct bpf_map *map, size_t size, gfp_t flags)
46048edc1f7SRoman Gushchin {
4614201d9abSRoman Gushchin 	struct mem_cgroup *memcg, *old_memcg;
46248edc1f7SRoman Gushchin 	void *ptr;
46348edc1f7SRoman Gushchin 
4644201d9abSRoman Gushchin 	memcg = bpf_map_get_memcg(map);
4654201d9abSRoman Gushchin 	old_memcg = set_active_memcg(memcg);
46648edc1f7SRoman Gushchin 	ptr = kzalloc(size, flags | __GFP_ACCOUNT);
46748edc1f7SRoman Gushchin 	set_active_memcg(old_memcg);
4684201d9abSRoman Gushchin 	mem_cgroup_put(memcg);
46948edc1f7SRoman Gushchin 
47048edc1f7SRoman Gushchin 	return ptr;
47148edc1f7SRoman Gushchin }
47248edc1f7SRoman Gushchin 
47348edc1f7SRoman Gushchin void __percpu *bpf_map_alloc_percpu(const struct bpf_map *map, size_t size,
47448edc1f7SRoman Gushchin 				    size_t align, gfp_t flags)
47548edc1f7SRoman Gushchin {
4764201d9abSRoman Gushchin 	struct mem_cgroup *memcg, *old_memcg;
47748edc1f7SRoman Gushchin 	void __percpu *ptr;
47848edc1f7SRoman Gushchin 
4794201d9abSRoman Gushchin 	memcg = bpf_map_get_memcg(map);
4804201d9abSRoman Gushchin 	old_memcg = set_active_memcg(memcg);
48148edc1f7SRoman Gushchin 	ptr = __alloc_percpu_gfp(size, align, flags | __GFP_ACCOUNT);
48248edc1f7SRoman Gushchin 	set_active_memcg(old_memcg);
4834201d9abSRoman Gushchin 	mem_cgroup_put(memcg);
48448edc1f7SRoman Gushchin 
48548edc1f7SRoman Gushchin 	return ptr;
48648edc1f7SRoman Gushchin }
48748edc1f7SRoman Gushchin 
48848edc1f7SRoman Gushchin #else
48948edc1f7SRoman Gushchin static void bpf_map_save_memcg(struct bpf_map *map)
49048edc1f7SRoman Gushchin {
49148edc1f7SRoman Gushchin }
49248edc1f7SRoman Gushchin 
49348edc1f7SRoman Gushchin static void bpf_map_release_memcg(struct bpf_map *map)
49448edc1f7SRoman Gushchin {
49548edc1f7SRoman Gushchin }
49648edc1f7SRoman Gushchin #endif
49748edc1f7SRoman Gushchin 
498aa3496acSKumar Kartikeya Dwivedi static int btf_field_cmp(const void *a, const void *b)
49961df10c7SKumar Kartikeya Dwivedi {
500aa3496acSKumar Kartikeya Dwivedi 	const struct btf_field *f1 = a, *f2 = b;
50161df10c7SKumar Kartikeya Dwivedi 
502aa3496acSKumar Kartikeya Dwivedi 	if (f1->offset < f2->offset)
50361df10c7SKumar Kartikeya Dwivedi 		return -1;
504aa3496acSKumar Kartikeya Dwivedi 	else if (f1->offset > f2->offset)
50561df10c7SKumar Kartikeya Dwivedi 		return 1;
50661df10c7SKumar Kartikeya Dwivedi 	return 0;
50761df10c7SKumar Kartikeya Dwivedi }
50861df10c7SKumar Kartikeya Dwivedi 
509aa3496acSKumar Kartikeya Dwivedi struct btf_field *btf_record_find(const struct btf_record *rec, u32 offset,
510aa3496acSKumar Kartikeya Dwivedi 				  enum btf_field_type type)
51161df10c7SKumar Kartikeya Dwivedi {
512aa3496acSKumar Kartikeya Dwivedi 	struct btf_field *field;
51361df10c7SKumar Kartikeya Dwivedi 
514aa3496acSKumar Kartikeya Dwivedi 	if (IS_ERR_OR_NULL(rec) || !(rec->field_mask & type))
51561df10c7SKumar Kartikeya Dwivedi 		return NULL;
516aa3496acSKumar Kartikeya Dwivedi 	field = bsearch(&offset, rec->fields, rec->cnt, sizeof(rec->fields[0]), btf_field_cmp);
517aa3496acSKumar Kartikeya Dwivedi 	if (!field || !(field->type & type))
518aa3496acSKumar Kartikeya Dwivedi 		return NULL;
519aa3496acSKumar Kartikeya Dwivedi 	return field;
52061df10c7SKumar Kartikeya Dwivedi }
52161df10c7SKumar Kartikeya Dwivedi 
522aa3496acSKumar Kartikeya Dwivedi void btf_record_free(struct btf_record *rec)
52361df10c7SKumar Kartikeya Dwivedi {
52461df10c7SKumar Kartikeya Dwivedi 	int i;
52561df10c7SKumar Kartikeya Dwivedi 
526aa3496acSKumar Kartikeya Dwivedi 	if (IS_ERR_OR_NULL(rec))
52761df10c7SKumar Kartikeya Dwivedi 		return;
528aa3496acSKumar Kartikeya Dwivedi 	for (i = 0; i < rec->cnt; i++) {
529aa3496acSKumar Kartikeya Dwivedi 		switch (rec->fields[i].type) {
530db559117SKumar Kartikeya Dwivedi 		case BPF_SPIN_LOCK:
531db559117SKumar Kartikeya Dwivedi 		case BPF_TIMER:
532db559117SKumar Kartikeya Dwivedi 			break;
533aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_UNREF:
534aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_REF:
535aa3496acSKumar Kartikeya Dwivedi 			if (rec->fields[i].kptr.module)
536aa3496acSKumar Kartikeya Dwivedi 				module_put(rec->fields[i].kptr.module);
537aa3496acSKumar Kartikeya Dwivedi 			btf_put(rec->fields[i].kptr.btf);
538aa3496acSKumar Kartikeya Dwivedi 			break;
539f0c5941fSKumar Kartikeya Dwivedi 		case BPF_LIST_HEAD:
5408ffa5cc1SKumar Kartikeya Dwivedi 		case BPF_LIST_NODE:
541f0c5941fSKumar Kartikeya Dwivedi 			/* Nothing to release for bpf_list_head */
542f0c5941fSKumar Kartikeya Dwivedi 			break;
543aa3496acSKumar Kartikeya Dwivedi 		default:
544aa3496acSKumar Kartikeya Dwivedi 			WARN_ON_ONCE(1);
54514a324f6SKumar Kartikeya Dwivedi 			continue;
54614a324f6SKumar Kartikeya Dwivedi 		}
547aa3496acSKumar Kartikeya Dwivedi 	}
548aa3496acSKumar Kartikeya Dwivedi 	kfree(rec);
549aa3496acSKumar Kartikeya Dwivedi }
550aa3496acSKumar Kartikeya Dwivedi 
551aa3496acSKumar Kartikeya Dwivedi void bpf_map_free_record(struct bpf_map *map)
552aa3496acSKumar Kartikeya Dwivedi {
553aa3496acSKumar Kartikeya Dwivedi 	btf_record_free(map->record);
554aa3496acSKumar Kartikeya Dwivedi 	map->record = NULL;
555aa3496acSKumar Kartikeya Dwivedi }
556aa3496acSKumar Kartikeya Dwivedi 
557aa3496acSKumar Kartikeya Dwivedi struct btf_record *btf_record_dup(const struct btf_record *rec)
558aa3496acSKumar Kartikeya Dwivedi {
559aa3496acSKumar Kartikeya Dwivedi 	const struct btf_field *fields;
560aa3496acSKumar Kartikeya Dwivedi 	struct btf_record *new_rec;
561aa3496acSKumar Kartikeya Dwivedi 	int ret, size, i;
562aa3496acSKumar Kartikeya Dwivedi 
563aa3496acSKumar Kartikeya Dwivedi 	if (IS_ERR_OR_NULL(rec))
564aa3496acSKumar Kartikeya Dwivedi 		return NULL;
565aa3496acSKumar Kartikeya Dwivedi 	size = offsetof(struct btf_record, fields[rec->cnt]);
566aa3496acSKumar Kartikeya Dwivedi 	new_rec = kmemdup(rec, size, GFP_KERNEL | __GFP_NOWARN);
567aa3496acSKumar Kartikeya Dwivedi 	if (!new_rec)
568aa3496acSKumar Kartikeya Dwivedi 		return ERR_PTR(-ENOMEM);
569aa3496acSKumar Kartikeya Dwivedi 	/* Do a deep copy of the btf_record */
570aa3496acSKumar Kartikeya Dwivedi 	fields = rec->fields;
571aa3496acSKumar Kartikeya Dwivedi 	new_rec->cnt = 0;
572aa3496acSKumar Kartikeya Dwivedi 	for (i = 0; i < rec->cnt; i++) {
573aa3496acSKumar Kartikeya Dwivedi 		switch (fields[i].type) {
574db559117SKumar Kartikeya Dwivedi 		case BPF_SPIN_LOCK:
575db559117SKumar Kartikeya Dwivedi 		case BPF_TIMER:
576db559117SKumar Kartikeya Dwivedi 			break;
577aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_UNREF:
578aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_REF:
579aa3496acSKumar Kartikeya Dwivedi 			btf_get(fields[i].kptr.btf);
580aa3496acSKumar Kartikeya Dwivedi 			if (fields[i].kptr.module && !try_module_get(fields[i].kptr.module)) {
581aa3496acSKumar Kartikeya Dwivedi 				ret = -ENXIO;
582aa3496acSKumar Kartikeya Dwivedi 				goto free;
583aa3496acSKumar Kartikeya Dwivedi 			}
584aa3496acSKumar Kartikeya Dwivedi 			break;
585f0c5941fSKumar Kartikeya Dwivedi 		case BPF_LIST_HEAD:
5868ffa5cc1SKumar Kartikeya Dwivedi 		case BPF_LIST_NODE:
587f0c5941fSKumar Kartikeya Dwivedi 			/* Nothing to acquire for bpf_list_head */
588f0c5941fSKumar Kartikeya Dwivedi 			break;
589aa3496acSKumar Kartikeya Dwivedi 		default:
590aa3496acSKumar Kartikeya Dwivedi 			ret = -EFAULT;
591aa3496acSKumar Kartikeya Dwivedi 			WARN_ON_ONCE(1);
592aa3496acSKumar Kartikeya Dwivedi 			goto free;
593aa3496acSKumar Kartikeya Dwivedi 		}
594aa3496acSKumar Kartikeya Dwivedi 		new_rec->cnt++;
595aa3496acSKumar Kartikeya Dwivedi 	}
596aa3496acSKumar Kartikeya Dwivedi 	return new_rec;
597aa3496acSKumar Kartikeya Dwivedi free:
598aa3496acSKumar Kartikeya Dwivedi 	btf_record_free(new_rec);
599aa3496acSKumar Kartikeya Dwivedi 	return ERR_PTR(ret);
600aa3496acSKumar Kartikeya Dwivedi }
601aa3496acSKumar Kartikeya Dwivedi 
602aa3496acSKumar Kartikeya Dwivedi bool btf_record_equal(const struct btf_record *rec_a, const struct btf_record *rec_b)
603aa3496acSKumar Kartikeya Dwivedi {
604aa3496acSKumar Kartikeya Dwivedi 	bool a_has_fields = !IS_ERR_OR_NULL(rec_a), b_has_fields = !IS_ERR_OR_NULL(rec_b);
605aa3496acSKumar Kartikeya Dwivedi 	int size;
606aa3496acSKumar Kartikeya Dwivedi 
607aa3496acSKumar Kartikeya Dwivedi 	if (!a_has_fields && !b_has_fields)
608aa3496acSKumar Kartikeya Dwivedi 		return true;
609aa3496acSKumar Kartikeya Dwivedi 	if (a_has_fields != b_has_fields)
610aa3496acSKumar Kartikeya Dwivedi 		return false;
611aa3496acSKumar Kartikeya Dwivedi 	if (rec_a->cnt != rec_b->cnt)
612aa3496acSKumar Kartikeya Dwivedi 		return false;
613aa3496acSKumar Kartikeya Dwivedi 	size = offsetof(struct btf_record, fields[rec_a->cnt]);
614*c22dfdd2SKumar Kartikeya Dwivedi 	/* btf_parse_fields uses kzalloc to allocate a btf_record, so unused
615*c22dfdd2SKumar Kartikeya Dwivedi 	 * members are zeroed out. So memcmp is safe to do without worrying
616*c22dfdd2SKumar Kartikeya Dwivedi 	 * about padding/unused fields.
617*c22dfdd2SKumar Kartikeya Dwivedi 	 *
618*c22dfdd2SKumar Kartikeya Dwivedi 	 * While spin_lock, timer, and kptr have no relation to map BTF,
619*c22dfdd2SKumar Kartikeya Dwivedi 	 * list_head metadata is specific to map BTF, the btf and value_rec
620*c22dfdd2SKumar Kartikeya Dwivedi 	 * members in particular. btf is the map BTF, while value_rec points to
621*c22dfdd2SKumar Kartikeya Dwivedi 	 * btf_record in that map BTF.
622*c22dfdd2SKumar Kartikeya Dwivedi 	 *
623*c22dfdd2SKumar Kartikeya Dwivedi 	 * So while by default, we don't rely on the map BTF (which the records
624*c22dfdd2SKumar Kartikeya Dwivedi 	 * were parsed from) matching for both records, which is not backwards
625*c22dfdd2SKumar Kartikeya Dwivedi 	 * compatible, in case list_head is part of it, we implicitly rely on
626*c22dfdd2SKumar Kartikeya Dwivedi 	 * that by way of depending on memcmp succeeding for it.
627*c22dfdd2SKumar Kartikeya Dwivedi 	 */
628aa3496acSKumar Kartikeya Dwivedi 	return !memcmp(rec_a, rec_b, size);
629aa3496acSKumar Kartikeya Dwivedi }
630aa3496acSKumar Kartikeya Dwivedi 
631db559117SKumar Kartikeya Dwivedi void bpf_obj_free_timer(const struct btf_record *rec, void *obj)
632db559117SKumar Kartikeya Dwivedi {
633db559117SKumar Kartikeya Dwivedi 	if (WARN_ON_ONCE(!btf_record_has_field(rec, BPF_TIMER)))
634db559117SKumar Kartikeya Dwivedi 		return;
635db559117SKumar Kartikeya Dwivedi 	bpf_timer_cancel_and_free(obj + rec->timer_off);
636db559117SKumar Kartikeya Dwivedi }
637db559117SKumar Kartikeya Dwivedi 
638aa3496acSKumar Kartikeya Dwivedi void bpf_obj_free_fields(const struct btf_record *rec, void *obj)
639aa3496acSKumar Kartikeya Dwivedi {
640aa3496acSKumar Kartikeya Dwivedi 	const struct btf_field *fields;
641aa3496acSKumar Kartikeya Dwivedi 	int i;
642aa3496acSKumar Kartikeya Dwivedi 
643aa3496acSKumar Kartikeya Dwivedi 	if (IS_ERR_OR_NULL(rec))
644aa3496acSKumar Kartikeya Dwivedi 		return;
645aa3496acSKumar Kartikeya Dwivedi 	fields = rec->fields;
646aa3496acSKumar Kartikeya Dwivedi 	for (i = 0; i < rec->cnt; i++) {
647aa3496acSKumar Kartikeya Dwivedi 		const struct btf_field *field = &fields[i];
648aa3496acSKumar Kartikeya Dwivedi 		void *field_ptr = obj + field->offset;
649aa3496acSKumar Kartikeya Dwivedi 
650aa3496acSKumar Kartikeya Dwivedi 		switch (fields[i].type) {
651db559117SKumar Kartikeya Dwivedi 		case BPF_SPIN_LOCK:
652db559117SKumar Kartikeya Dwivedi 			break;
653db559117SKumar Kartikeya Dwivedi 		case BPF_TIMER:
654db559117SKumar Kartikeya Dwivedi 			bpf_timer_cancel_and_free(field_ptr);
655db559117SKumar Kartikeya Dwivedi 			break;
656aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_UNREF:
657aa3496acSKumar Kartikeya Dwivedi 			WRITE_ONCE(*(u64 *)field_ptr, 0);
658aa3496acSKumar Kartikeya Dwivedi 			break;
659aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_REF:
660aa3496acSKumar Kartikeya Dwivedi 			field->kptr.dtor((void *)xchg((unsigned long *)field_ptr, 0));
661aa3496acSKumar Kartikeya Dwivedi 			break;
662f0c5941fSKumar Kartikeya Dwivedi 		case BPF_LIST_HEAD:
663f0c5941fSKumar Kartikeya Dwivedi 			if (WARN_ON_ONCE(rec->spin_lock_off < 0))
664f0c5941fSKumar Kartikeya Dwivedi 				continue;
665f0c5941fSKumar Kartikeya Dwivedi 			bpf_list_head_free(field, field_ptr, obj + rec->spin_lock_off);
666f0c5941fSKumar Kartikeya Dwivedi 			break;
6678ffa5cc1SKumar Kartikeya Dwivedi 		case BPF_LIST_NODE:
6688ffa5cc1SKumar Kartikeya Dwivedi 			break;
669aa3496acSKumar Kartikeya Dwivedi 		default:
670aa3496acSKumar Kartikeya Dwivedi 			WARN_ON_ONCE(1);
671aa3496acSKumar Kartikeya Dwivedi 			continue;
672aa3496acSKumar Kartikeya Dwivedi 		}
67314a324f6SKumar Kartikeya Dwivedi 	}
67414a324f6SKumar Kartikeya Dwivedi }
67514a324f6SKumar Kartikeya Dwivedi 
67699c55f7dSAlexei Starovoitov /* called from workqueue */
67799c55f7dSAlexei Starovoitov static void bpf_map_free_deferred(struct work_struct *work)
67899c55f7dSAlexei Starovoitov {
67999c55f7dSAlexei Starovoitov 	struct bpf_map *map = container_of(work, struct bpf_map, work);
680d7f5ef65SKumar Kartikeya Dwivedi 	struct btf_field_offs *foffs = map->field_offs;
681d7f5ef65SKumar Kartikeya Dwivedi 	struct btf_record *rec = map->record;
68299c55f7dSAlexei Starovoitov 
683afdb09c7SChenbo Feng 	security_bpf_map_free(map);
68448edc1f7SRoman Gushchin 	bpf_map_release_memcg(map);
685d7f5ef65SKumar Kartikeya Dwivedi 	/* implementation dependent freeing */
68699c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
687d7f5ef65SKumar Kartikeya Dwivedi 	/* Delay freeing of field_offs and btf_record for maps, as map_free
688d7f5ef65SKumar Kartikeya Dwivedi 	 * callback usually needs access to them. It is better to do it here
689d7f5ef65SKumar Kartikeya Dwivedi 	 * than require each callback to do the free itself manually.
690d7f5ef65SKumar Kartikeya Dwivedi 	 *
691d7f5ef65SKumar Kartikeya Dwivedi 	 * Note that the btf_record stashed in map->inner_map_meta->record was
692d7f5ef65SKumar Kartikeya Dwivedi 	 * already freed using the map_free callback for map in map case which
693d7f5ef65SKumar Kartikeya Dwivedi 	 * eventually calls bpf_map_free_meta, since inner_map_meta is only a
694d7f5ef65SKumar Kartikeya Dwivedi 	 * template bpf_map struct used during verification.
695d7f5ef65SKumar Kartikeya Dwivedi 	 */
696d7f5ef65SKumar Kartikeya Dwivedi 	kfree(foffs);
697d7f5ef65SKumar Kartikeya Dwivedi 	btf_record_free(rec);
69899c55f7dSAlexei Starovoitov }
69999c55f7dSAlexei Starovoitov 
700c9da161cSDaniel Borkmann static void bpf_map_put_uref(struct bpf_map *map)
701c9da161cSDaniel Borkmann {
7021e0bd5a0SAndrii Nakryiko 	if (atomic64_dec_and_test(&map->usercnt)) {
703ba6b8de4SJohn Fastabend 		if (map->ops->map_release_uref)
704ba6b8de4SJohn Fastabend 			map->ops->map_release_uref(map);
705c9da161cSDaniel Borkmann 	}
706c9da161cSDaniel Borkmann }
707c9da161cSDaniel Borkmann 
70899c55f7dSAlexei Starovoitov /* decrement map refcnt and schedule it for freeing via workqueue
70999c55f7dSAlexei Starovoitov  * (unrelying map implementation ops->map_free() might sleep)
71099c55f7dSAlexei Starovoitov  */
711bd5f5f4eSMartin KaFai Lau static void __bpf_map_put(struct bpf_map *map, bool do_idr_lock)
71299c55f7dSAlexei Starovoitov {
7131e0bd5a0SAndrii Nakryiko 	if (atomic64_dec_and_test(&map->refcnt)) {
71434ad5580SMartin KaFai Lau 		/* bpf_map_free_id() must be called first */
715bd5f5f4eSMartin KaFai Lau 		bpf_map_free_id(map, do_idr_lock);
71678958fcaSMartin KaFai Lau 		btf_put(map->btf);
71799c55f7dSAlexei Starovoitov 		INIT_WORK(&map->work, bpf_map_free_deferred);
7188d5a8011SAlexei Starovoitov 		/* Avoid spawning kworkers, since they all might contend
7198d5a8011SAlexei Starovoitov 		 * for the same mutex like slab_mutex.
7208d5a8011SAlexei Starovoitov 		 */
7218d5a8011SAlexei Starovoitov 		queue_work(system_unbound_wq, &map->work);
72299c55f7dSAlexei Starovoitov 	}
72399c55f7dSAlexei Starovoitov }
72499c55f7dSAlexei Starovoitov 
725bd5f5f4eSMartin KaFai Lau void bpf_map_put(struct bpf_map *map)
726bd5f5f4eSMartin KaFai Lau {
727bd5f5f4eSMartin KaFai Lau 	__bpf_map_put(map, true);
728bd5f5f4eSMartin KaFai Lau }
729630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_put);
730bd5f5f4eSMartin KaFai Lau 
731c9da161cSDaniel Borkmann void bpf_map_put_with_uref(struct bpf_map *map)
732c9da161cSDaniel Borkmann {
733c9da161cSDaniel Borkmann 	bpf_map_put_uref(map);
734c9da161cSDaniel Borkmann 	bpf_map_put(map);
735c9da161cSDaniel Borkmann }
736c9da161cSDaniel Borkmann 
73799c55f7dSAlexei Starovoitov static int bpf_map_release(struct inode *inode, struct file *filp)
73899c55f7dSAlexei Starovoitov {
73961d1b6a4SDaniel Borkmann 	struct bpf_map *map = filp->private_data;
74061d1b6a4SDaniel Borkmann 
74161d1b6a4SDaniel Borkmann 	if (map->ops->map_release)
74261d1b6a4SDaniel Borkmann 		map->ops->map_release(map, filp);
74361d1b6a4SDaniel Borkmann 
74461d1b6a4SDaniel Borkmann 	bpf_map_put_with_uref(map);
74599c55f7dSAlexei Starovoitov 	return 0;
74699c55f7dSAlexei Starovoitov }
74799c55f7dSAlexei Starovoitov 
74887df15deSDaniel Borkmann static fmode_t map_get_sys_perms(struct bpf_map *map, struct fd f)
74987df15deSDaniel Borkmann {
75087df15deSDaniel Borkmann 	fmode_t mode = f.file->f_mode;
75187df15deSDaniel Borkmann 
75287df15deSDaniel Borkmann 	/* Our file permissions may have been overridden by global
75387df15deSDaniel Borkmann 	 * map permissions facing syscall side.
75487df15deSDaniel Borkmann 	 */
75587df15deSDaniel Borkmann 	if (READ_ONCE(map->frozen))
75687df15deSDaniel Borkmann 		mode &= ~FMODE_CAN_WRITE;
75787df15deSDaniel Borkmann 	return mode;
75887df15deSDaniel Borkmann }
75987df15deSDaniel Borkmann 
760f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
76180ee81e0SRoman Gushchin /* Provides an approximation of the map's memory footprint.
76280ee81e0SRoman Gushchin  * Used only to provide a backward compatibility and display
76380ee81e0SRoman Gushchin  * a reasonable "memlock" info.
76480ee81e0SRoman Gushchin  */
76580ee81e0SRoman Gushchin static unsigned long bpf_map_memory_footprint(const struct bpf_map *map)
76680ee81e0SRoman Gushchin {
76780ee81e0SRoman Gushchin 	unsigned long size;
76880ee81e0SRoman Gushchin 
76980ee81e0SRoman Gushchin 	size = round_up(map->key_size + bpf_map_value_size(map), 8);
77080ee81e0SRoman Gushchin 
77180ee81e0SRoman Gushchin 	return round_up(map->max_entries * size, PAGE_SIZE);
77280ee81e0SRoman Gushchin }
77380ee81e0SRoman Gushchin 
774f99bf205SDaniel Borkmann static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)
775f99bf205SDaniel Borkmann {
776f45d5b6cSToke Hoiland-Jorgensen 	struct bpf_map *map = filp->private_data;
7772beee5f5SDaniel Borkmann 	u32 type = 0, jited = 0;
77821116b70SDaniel Borkmann 
779f45d5b6cSToke Hoiland-Jorgensen 	if (map_type_contains_progs(map)) {
780f45d5b6cSToke Hoiland-Jorgensen 		spin_lock(&map->owner.lock);
781f45d5b6cSToke Hoiland-Jorgensen 		type  = map->owner.type;
782f45d5b6cSToke Hoiland-Jorgensen 		jited = map->owner.jited;
783f45d5b6cSToke Hoiland-Jorgensen 		spin_unlock(&map->owner.lock);
78421116b70SDaniel Borkmann 	}
785f99bf205SDaniel Borkmann 
786f99bf205SDaniel Borkmann 	seq_printf(m,
787f99bf205SDaniel Borkmann 		   "map_type:\t%u\n"
788f99bf205SDaniel Borkmann 		   "key_size:\t%u\n"
789f99bf205SDaniel Borkmann 		   "value_size:\t%u\n"
790322cea2fSDaniel Borkmann 		   "max_entries:\t%u\n"
79121116b70SDaniel Borkmann 		   "map_flags:\t%#x\n"
7929330986cSJoanne Koong 		   "map_extra:\t%#llx\n"
79380ee81e0SRoman Gushchin 		   "memlock:\t%lu\n"
79487df15deSDaniel Borkmann 		   "map_id:\t%u\n"
79587df15deSDaniel Borkmann 		   "frozen:\t%u\n",
796f99bf205SDaniel Borkmann 		   map->map_type,
797f99bf205SDaniel Borkmann 		   map->key_size,
798f99bf205SDaniel Borkmann 		   map->value_size,
799322cea2fSDaniel Borkmann 		   map->max_entries,
80021116b70SDaniel Borkmann 		   map->map_flags,
8019330986cSJoanne Koong 		   (unsigned long long)map->map_extra,
80280ee81e0SRoman Gushchin 		   bpf_map_memory_footprint(map),
80387df15deSDaniel Borkmann 		   map->id,
80487df15deSDaniel Borkmann 		   READ_ONCE(map->frozen));
8052beee5f5SDaniel Borkmann 	if (type) {
8062beee5f5SDaniel Borkmann 		seq_printf(m, "owner_prog_type:\t%u\n", type);
8072beee5f5SDaniel Borkmann 		seq_printf(m, "owner_jited:\t%u\n", jited);
8089780c0abSDaniel Borkmann 	}
809f99bf205SDaniel Borkmann }
810f99bf205SDaniel Borkmann #endif
811f99bf205SDaniel Borkmann 
8126e71b04aSChenbo Feng static ssize_t bpf_dummy_read(struct file *filp, char __user *buf, size_t siz,
8136e71b04aSChenbo Feng 			      loff_t *ppos)
8146e71b04aSChenbo Feng {
8156e71b04aSChenbo Feng 	/* We need this handler such that alloc_file() enables
8166e71b04aSChenbo Feng 	 * f_mode with FMODE_CAN_READ.
8176e71b04aSChenbo Feng 	 */
8186e71b04aSChenbo Feng 	return -EINVAL;
8196e71b04aSChenbo Feng }
8206e71b04aSChenbo Feng 
8216e71b04aSChenbo Feng static ssize_t bpf_dummy_write(struct file *filp, const char __user *buf,
8226e71b04aSChenbo Feng 			       size_t siz, loff_t *ppos)
8236e71b04aSChenbo Feng {
8246e71b04aSChenbo Feng 	/* We need this handler such that alloc_file() enables
8256e71b04aSChenbo Feng 	 * f_mode with FMODE_CAN_WRITE.
8266e71b04aSChenbo Feng 	 */
8276e71b04aSChenbo Feng 	return -EINVAL;
8286e71b04aSChenbo Feng }
8296e71b04aSChenbo Feng 
830fc970227SAndrii Nakryiko /* called for any extra memory-mapped regions (except initial) */
831fc970227SAndrii Nakryiko static void bpf_map_mmap_open(struct vm_area_struct *vma)
832fc970227SAndrii Nakryiko {
833fc970227SAndrii Nakryiko 	struct bpf_map *map = vma->vm_file->private_data;
834fc970227SAndrii Nakryiko 
835353050beSDaniel Borkmann 	if (vma->vm_flags & VM_MAYWRITE)
836353050beSDaniel Borkmann 		bpf_map_write_active_inc(map);
837fc970227SAndrii Nakryiko }
838fc970227SAndrii Nakryiko 
839fc970227SAndrii Nakryiko /* called for all unmapped memory region (including initial) */
840fc970227SAndrii Nakryiko static void bpf_map_mmap_close(struct vm_area_struct *vma)
841fc970227SAndrii Nakryiko {
842fc970227SAndrii Nakryiko 	struct bpf_map *map = vma->vm_file->private_data;
843fc970227SAndrii Nakryiko 
844353050beSDaniel Borkmann 	if (vma->vm_flags & VM_MAYWRITE)
845353050beSDaniel Borkmann 		bpf_map_write_active_dec(map);
846fc970227SAndrii Nakryiko }
847fc970227SAndrii Nakryiko 
848fc970227SAndrii Nakryiko static const struct vm_operations_struct bpf_map_default_vmops = {
849fc970227SAndrii Nakryiko 	.open		= bpf_map_mmap_open,
850fc970227SAndrii Nakryiko 	.close		= bpf_map_mmap_close,
851fc970227SAndrii Nakryiko };
852fc970227SAndrii Nakryiko 
853fc970227SAndrii Nakryiko static int bpf_map_mmap(struct file *filp, struct vm_area_struct *vma)
854fc970227SAndrii Nakryiko {
855fc970227SAndrii Nakryiko 	struct bpf_map *map = filp->private_data;
856fc970227SAndrii Nakryiko 	int err;
857fc970227SAndrii Nakryiko 
858db559117SKumar Kartikeya Dwivedi 	if (!map->ops->map_mmap || !IS_ERR_OR_NULL(map->record))
859fc970227SAndrii Nakryiko 		return -ENOTSUPP;
860fc970227SAndrii Nakryiko 
861fc970227SAndrii Nakryiko 	if (!(vma->vm_flags & VM_SHARED))
862fc970227SAndrii Nakryiko 		return -EINVAL;
863fc970227SAndrii Nakryiko 
864fc970227SAndrii Nakryiko 	mutex_lock(&map->freeze_mutex);
865fc970227SAndrii Nakryiko 
866dfeb376dSAndrii Nakryiko 	if (vma->vm_flags & VM_WRITE) {
867dfeb376dSAndrii Nakryiko 		if (map->frozen) {
868fc970227SAndrii Nakryiko 			err = -EPERM;
869fc970227SAndrii Nakryiko 			goto out;
870fc970227SAndrii Nakryiko 		}
871dfeb376dSAndrii Nakryiko 		/* map is meant to be read-only, so do not allow mapping as
872dfeb376dSAndrii Nakryiko 		 * writable, because it's possible to leak a writable page
873dfeb376dSAndrii Nakryiko 		 * reference and allows user-space to still modify it after
874dfeb376dSAndrii Nakryiko 		 * freezing, while verifier will assume contents do not change
875dfeb376dSAndrii Nakryiko 		 */
876dfeb376dSAndrii Nakryiko 		if (map->map_flags & BPF_F_RDONLY_PROG) {
877dfeb376dSAndrii Nakryiko 			err = -EACCES;
878dfeb376dSAndrii Nakryiko 			goto out;
879dfeb376dSAndrii Nakryiko 		}
880dfeb376dSAndrii Nakryiko 	}
881fc970227SAndrii Nakryiko 
882fc970227SAndrii Nakryiko 	/* set default open/close callbacks */
883fc970227SAndrii Nakryiko 	vma->vm_ops = &bpf_map_default_vmops;
884fc970227SAndrii Nakryiko 	vma->vm_private_data = map;
8851f6cb19bSAndrii Nakryiko 	vma->vm_flags &= ~VM_MAYEXEC;
8861f6cb19bSAndrii Nakryiko 	if (!(vma->vm_flags & VM_WRITE))
8871f6cb19bSAndrii Nakryiko 		/* disallow re-mapping with PROT_WRITE */
8881f6cb19bSAndrii Nakryiko 		vma->vm_flags &= ~VM_MAYWRITE;
889fc970227SAndrii Nakryiko 
890fc970227SAndrii Nakryiko 	err = map->ops->map_mmap(map, vma);
891fc970227SAndrii Nakryiko 	if (err)
892fc970227SAndrii Nakryiko 		goto out;
893fc970227SAndrii Nakryiko 
8941f6cb19bSAndrii Nakryiko 	if (vma->vm_flags & VM_MAYWRITE)
895353050beSDaniel Borkmann 		bpf_map_write_active_inc(map);
896fc970227SAndrii Nakryiko out:
897fc970227SAndrii Nakryiko 	mutex_unlock(&map->freeze_mutex);
898fc970227SAndrii Nakryiko 	return err;
899fc970227SAndrii Nakryiko }
900fc970227SAndrii Nakryiko 
901457f4436SAndrii Nakryiko static __poll_t bpf_map_poll(struct file *filp, struct poll_table_struct *pts)
902457f4436SAndrii Nakryiko {
903457f4436SAndrii Nakryiko 	struct bpf_map *map = filp->private_data;
904457f4436SAndrii Nakryiko 
905457f4436SAndrii Nakryiko 	if (map->ops->map_poll)
906457f4436SAndrii Nakryiko 		return map->ops->map_poll(map, filp, pts);
907457f4436SAndrii Nakryiko 
908457f4436SAndrii Nakryiko 	return EPOLLERR;
909457f4436SAndrii Nakryiko }
910457f4436SAndrii Nakryiko 
911f66e448cSChenbo Feng const struct file_operations bpf_map_fops = {
912f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
913f99bf205SDaniel Borkmann 	.show_fdinfo	= bpf_map_show_fdinfo,
914f99bf205SDaniel Borkmann #endif
91599c55f7dSAlexei Starovoitov 	.release	= bpf_map_release,
9166e71b04aSChenbo Feng 	.read		= bpf_dummy_read,
9176e71b04aSChenbo Feng 	.write		= bpf_dummy_write,
918fc970227SAndrii Nakryiko 	.mmap		= bpf_map_mmap,
919457f4436SAndrii Nakryiko 	.poll		= bpf_map_poll,
92099c55f7dSAlexei Starovoitov };
92199c55f7dSAlexei Starovoitov 
9226e71b04aSChenbo Feng int bpf_map_new_fd(struct bpf_map *map, int flags)
923aa79781bSDaniel Borkmann {
924afdb09c7SChenbo Feng 	int ret;
925afdb09c7SChenbo Feng 
926afdb09c7SChenbo Feng 	ret = security_bpf_map(map, OPEN_FMODE(flags));
927afdb09c7SChenbo Feng 	if (ret < 0)
928afdb09c7SChenbo Feng 		return ret;
929afdb09c7SChenbo Feng 
930aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-map", &bpf_map_fops, map,
9316e71b04aSChenbo Feng 				flags | O_CLOEXEC);
9326e71b04aSChenbo Feng }
9336e71b04aSChenbo Feng 
9346e71b04aSChenbo Feng int bpf_get_file_flag(int flags)
9356e71b04aSChenbo Feng {
9366e71b04aSChenbo Feng 	if ((flags & BPF_F_RDONLY) && (flags & BPF_F_WRONLY))
9376e71b04aSChenbo Feng 		return -EINVAL;
9386e71b04aSChenbo Feng 	if (flags & BPF_F_RDONLY)
9396e71b04aSChenbo Feng 		return O_RDONLY;
9406e71b04aSChenbo Feng 	if (flags & BPF_F_WRONLY)
9416e71b04aSChenbo Feng 		return O_WRONLY;
9426e71b04aSChenbo Feng 	return O_RDWR;
943aa79781bSDaniel Borkmann }
944aa79781bSDaniel Borkmann 
94599c55f7dSAlexei Starovoitov /* helper macro to check that unused fields 'union bpf_attr' are zero */
94699c55f7dSAlexei Starovoitov #define CHECK_ATTR(CMD) \
94799c55f7dSAlexei Starovoitov 	memchr_inv((void *) &attr->CMD##_LAST_FIELD + \
94899c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD), 0, \
94999c55f7dSAlexei Starovoitov 		   sizeof(*attr) - \
95099c55f7dSAlexei Starovoitov 		   offsetof(union bpf_attr, CMD##_LAST_FIELD) - \
95199c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD)) != NULL
95299c55f7dSAlexei Starovoitov 
9538e7ae251SMartin KaFai Lau /* dst and src must have at least "size" number of bytes.
9548e7ae251SMartin KaFai Lau  * Return strlen on success and < 0 on error.
955cb4d2b3fSMartin KaFai Lau  */
9568e7ae251SMartin KaFai Lau int bpf_obj_name_cpy(char *dst, const char *src, unsigned int size)
957cb4d2b3fSMartin KaFai Lau {
9588e7ae251SMartin KaFai Lau 	const char *end = src + size;
9598e7ae251SMartin KaFai Lau 	const char *orig_src = src;
960cb4d2b3fSMartin KaFai Lau 
9618e7ae251SMartin KaFai Lau 	memset(dst, 0, size);
9623e0ddc4fSDaniel Borkmann 	/* Copy all isalnum(), '_' and '.' chars. */
963cb4d2b3fSMartin KaFai Lau 	while (src < end && *src) {
9643e0ddc4fSDaniel Borkmann 		if (!isalnum(*src) &&
9653e0ddc4fSDaniel Borkmann 		    *src != '_' && *src != '.')
966cb4d2b3fSMartin KaFai Lau 			return -EINVAL;
967cb4d2b3fSMartin KaFai Lau 		*dst++ = *src++;
968cb4d2b3fSMartin KaFai Lau 	}
969cb4d2b3fSMartin KaFai Lau 
9708e7ae251SMartin KaFai Lau 	/* No '\0' found in "size" number of bytes */
971cb4d2b3fSMartin KaFai Lau 	if (src == end)
972cb4d2b3fSMartin KaFai Lau 		return -EINVAL;
973cb4d2b3fSMartin KaFai Lau 
9748e7ae251SMartin KaFai Lau 	return src - orig_src;
975cb4d2b3fSMartin KaFai Lau }
976cb4d2b3fSMartin KaFai Lau 
977e8d2bec0SDaniel Borkmann int map_check_no_btf(const struct bpf_map *map,
9781b2b234bSRoman Gushchin 		     const struct btf *btf,
979e8d2bec0SDaniel Borkmann 		     const struct btf_type *key_type,
980e8d2bec0SDaniel Borkmann 		     const struct btf_type *value_type)
981e8d2bec0SDaniel Borkmann {
982e8d2bec0SDaniel Borkmann 	return -ENOTSUPP;
983e8d2bec0SDaniel Borkmann }
984e8d2bec0SDaniel Borkmann 
985d83525caSAlexei Starovoitov static int map_check_btf(struct bpf_map *map, const struct btf *btf,
986e8d2bec0SDaniel Borkmann 			 u32 btf_key_id, u32 btf_value_id)
987e8d2bec0SDaniel Borkmann {
988e8d2bec0SDaniel Borkmann 	const struct btf_type *key_type, *value_type;
989e8d2bec0SDaniel Borkmann 	u32 key_size, value_size;
990e8d2bec0SDaniel Borkmann 	int ret = 0;
991e8d2bec0SDaniel Borkmann 
9922824ecb7SDaniel Borkmann 	/* Some maps allow key to be unspecified. */
9932824ecb7SDaniel Borkmann 	if (btf_key_id) {
994e8d2bec0SDaniel Borkmann 		key_type = btf_type_id_size(btf, &btf_key_id, &key_size);
995e8d2bec0SDaniel Borkmann 		if (!key_type || key_size != map->key_size)
996e8d2bec0SDaniel Borkmann 			return -EINVAL;
9972824ecb7SDaniel Borkmann 	} else {
9982824ecb7SDaniel Borkmann 		key_type = btf_type_by_id(btf, 0);
9992824ecb7SDaniel Borkmann 		if (!map->ops->map_check_btf)
10002824ecb7SDaniel Borkmann 			return -EINVAL;
10012824ecb7SDaniel Borkmann 	}
1002e8d2bec0SDaniel Borkmann 
1003e8d2bec0SDaniel Borkmann 	value_type = btf_type_id_size(btf, &btf_value_id, &value_size);
1004e8d2bec0SDaniel Borkmann 	if (!value_type || value_size != map->value_size)
1005e8d2bec0SDaniel Borkmann 		return -EINVAL;
1006e8d2bec0SDaniel Borkmann 
1007f0c5941fSKumar Kartikeya Dwivedi 	map->record = btf_parse_fields(btf, value_type,
1008f0c5941fSKumar Kartikeya Dwivedi 				       BPF_SPIN_LOCK | BPF_TIMER | BPF_KPTR | BPF_LIST_HEAD,
1009db559117SKumar Kartikeya Dwivedi 				       map->value_size);
1010aa3496acSKumar Kartikeya Dwivedi 	if (!IS_ERR_OR_NULL(map->record)) {
1011aa3496acSKumar Kartikeya Dwivedi 		int i;
1012aa3496acSKumar Kartikeya Dwivedi 
101361df10c7SKumar Kartikeya Dwivedi 		if (!bpf_capable()) {
101461df10c7SKumar Kartikeya Dwivedi 			ret = -EPERM;
101561df10c7SKumar Kartikeya Dwivedi 			goto free_map_tab;
101661df10c7SKumar Kartikeya Dwivedi 		}
101761df10c7SKumar Kartikeya Dwivedi 		if (map->map_flags & (BPF_F_RDONLY_PROG | BPF_F_WRONLY_PROG)) {
101861df10c7SKumar Kartikeya Dwivedi 			ret = -EACCES;
101961df10c7SKumar Kartikeya Dwivedi 			goto free_map_tab;
102061df10c7SKumar Kartikeya Dwivedi 		}
1021aa3496acSKumar Kartikeya Dwivedi 		for (i = 0; i < sizeof(map->record->field_mask) * 8; i++) {
1022aa3496acSKumar Kartikeya Dwivedi 			switch (map->record->field_mask & (1 << i)) {
1023aa3496acSKumar Kartikeya Dwivedi 			case 0:
1024aa3496acSKumar Kartikeya Dwivedi 				continue;
1025db559117SKumar Kartikeya Dwivedi 			case BPF_SPIN_LOCK:
1026db559117SKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
1027db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY &&
1028db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_CGROUP_STORAGE &&
1029db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_SK_STORAGE &&
1030db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_INODE_STORAGE &&
1031db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_TASK_STORAGE &&
1032db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_CGRP_STORAGE) {
1033db559117SKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
1034db559117SKumar Kartikeya Dwivedi 					goto free_map_tab;
1035db559117SKumar Kartikeya Dwivedi 				}
1036db559117SKumar Kartikeya Dwivedi 				break;
1037db559117SKumar Kartikeya Dwivedi 			case BPF_TIMER:
1038db559117SKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
1039db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
1040db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY) {
1041c237bfa5SKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
1042db559117SKumar Kartikeya Dwivedi 					goto free_map_tab;
1043db559117SKumar Kartikeya Dwivedi 				}
1044db559117SKumar Kartikeya Dwivedi 				break;
1045aa3496acSKumar Kartikeya Dwivedi 			case BPF_KPTR_UNREF:
1046aa3496acSKumar Kartikeya Dwivedi 			case BPF_KPTR_REF:
104761df10c7SKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
104861df10c7SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
10496df4ea1fSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY &&
10506df4ea1fSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_PERCPU_ARRAY) {
105161df10c7SKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
105261df10c7SKumar Kartikeya Dwivedi 					goto free_map_tab;
105361df10c7SKumar Kartikeya Dwivedi 				}
1054aa3496acSKumar Kartikeya Dwivedi 				break;
1055f0c5941fSKumar Kartikeya Dwivedi 			case BPF_LIST_HEAD:
1056f0c5941fSKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
1057f0c5941fSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
1058f0c5941fSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY) {
1059f0c5941fSKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
1060f0c5941fSKumar Kartikeya Dwivedi 					goto free_map_tab;
1061f0c5941fSKumar Kartikeya Dwivedi 				}
1062f0c5941fSKumar Kartikeya Dwivedi 				break;
1063aa3496acSKumar Kartikeya Dwivedi 			default:
1064aa3496acSKumar Kartikeya Dwivedi 				/* Fail if map_type checks are missing for a field type */
1065aa3496acSKumar Kartikeya Dwivedi 				ret = -EOPNOTSUPP;
1066aa3496acSKumar Kartikeya Dwivedi 				goto free_map_tab;
1067aa3496acSKumar Kartikeya Dwivedi 			}
1068aa3496acSKumar Kartikeya Dwivedi 		}
106961df10c7SKumar Kartikeya Dwivedi 	}
1070e8d2bec0SDaniel Borkmann 
1071865ce09aSKumar Kartikeya Dwivedi 	ret = btf_check_and_fixup_fields(btf, map->record);
1072865ce09aSKumar Kartikeya Dwivedi 	if (ret < 0)
1073865ce09aSKumar Kartikeya Dwivedi 		goto free_map_tab;
1074865ce09aSKumar Kartikeya Dwivedi 
107561df10c7SKumar Kartikeya Dwivedi 	if (map->ops->map_check_btf) {
107661df10c7SKumar Kartikeya Dwivedi 		ret = map->ops->map_check_btf(map, btf, key_type, value_type);
107761df10c7SKumar Kartikeya Dwivedi 		if (ret < 0)
107861df10c7SKumar Kartikeya Dwivedi 			goto free_map_tab;
107961df10c7SKumar Kartikeya Dwivedi 	}
108061df10c7SKumar Kartikeya Dwivedi 
108161df10c7SKumar Kartikeya Dwivedi 	return ret;
108261df10c7SKumar Kartikeya Dwivedi free_map_tab:
1083aa3496acSKumar Kartikeya Dwivedi 	bpf_map_free_record(map);
1084e8d2bec0SDaniel Borkmann 	return ret;
1085e8d2bec0SDaniel Borkmann }
1086e8d2bec0SDaniel Borkmann 
10879330986cSJoanne Koong #define BPF_MAP_CREATE_LAST_FIELD map_extra
108899c55f7dSAlexei Starovoitov /* called via syscall */
108999c55f7dSAlexei Starovoitov static int map_create(union bpf_attr *attr)
109099c55f7dSAlexei Starovoitov {
109196eabe7aSMartin KaFai Lau 	int numa_node = bpf_map_attr_numa_node(attr);
1092f71b2f64SKumar Kartikeya Dwivedi 	struct btf_field_offs *foffs;
109399c55f7dSAlexei Starovoitov 	struct bpf_map *map;
10946e71b04aSChenbo Feng 	int f_flags;
109599c55f7dSAlexei Starovoitov 	int err;
109699c55f7dSAlexei Starovoitov 
109799c55f7dSAlexei Starovoitov 	err = CHECK_ATTR(BPF_MAP_CREATE);
109899c55f7dSAlexei Starovoitov 	if (err)
109999c55f7dSAlexei Starovoitov 		return -EINVAL;
110099c55f7dSAlexei Starovoitov 
110185d33df3SMartin KaFai Lau 	if (attr->btf_vmlinux_value_type_id) {
110285d33df3SMartin KaFai Lau 		if (attr->map_type != BPF_MAP_TYPE_STRUCT_OPS ||
110385d33df3SMartin KaFai Lau 		    attr->btf_key_type_id || attr->btf_value_type_id)
110485d33df3SMartin KaFai Lau 			return -EINVAL;
110585d33df3SMartin KaFai Lau 	} else if (attr->btf_key_type_id && !attr->btf_value_type_id) {
110685d33df3SMartin KaFai Lau 		return -EINVAL;
110785d33df3SMartin KaFai Lau 	}
110885d33df3SMartin KaFai Lau 
11099330986cSJoanne Koong 	if (attr->map_type != BPF_MAP_TYPE_BLOOM_FILTER &&
11109330986cSJoanne Koong 	    attr->map_extra != 0)
11119330986cSJoanne Koong 		return -EINVAL;
11129330986cSJoanne Koong 
11136e71b04aSChenbo Feng 	f_flags = bpf_get_file_flag(attr->map_flags);
11146e71b04aSChenbo Feng 	if (f_flags < 0)
11156e71b04aSChenbo Feng 		return f_flags;
11166e71b04aSChenbo Feng 
111796eabe7aSMartin KaFai Lau 	if (numa_node != NUMA_NO_NODE &&
111896e5ae4eSEric Dumazet 	    ((unsigned int)numa_node >= nr_node_ids ||
111996e5ae4eSEric Dumazet 	     !node_online(numa_node)))
112096eabe7aSMartin KaFai Lau 		return -EINVAL;
112196eabe7aSMartin KaFai Lau 
112299c55f7dSAlexei Starovoitov 	/* find map type and init map: hashtable vs rbtree vs bloom vs ... */
112399c55f7dSAlexei Starovoitov 	map = find_and_alloc_map(attr);
112499c55f7dSAlexei Starovoitov 	if (IS_ERR(map))
112599c55f7dSAlexei Starovoitov 		return PTR_ERR(map);
112699c55f7dSAlexei Starovoitov 
11278e7ae251SMartin KaFai Lau 	err = bpf_obj_name_cpy(map->name, attr->map_name,
11288e7ae251SMartin KaFai Lau 			       sizeof(attr->map_name));
11298e7ae251SMartin KaFai Lau 	if (err < 0)
1130b936ca64SRoman Gushchin 		goto free_map;
1131ad5b177bSMartin KaFai Lau 
11321e0bd5a0SAndrii Nakryiko 	atomic64_set(&map->refcnt, 1);
11331e0bd5a0SAndrii Nakryiko 	atomic64_set(&map->usercnt, 1);
1134fc970227SAndrii Nakryiko 	mutex_init(&map->freeze_mutex);
1135f45d5b6cSToke Hoiland-Jorgensen 	spin_lock_init(&map->owner.lock);
113699c55f7dSAlexei Starovoitov 
113785d33df3SMartin KaFai Lau 	if (attr->btf_key_type_id || attr->btf_value_type_id ||
113885d33df3SMartin KaFai Lau 	    /* Even the map's value is a kernel's struct,
113985d33df3SMartin KaFai Lau 	     * the bpf_prog.o must have BTF to begin with
114085d33df3SMartin KaFai Lau 	     * to figure out the corresponding kernel's
114185d33df3SMartin KaFai Lau 	     * counter part.  Thus, attr->btf_fd has
114285d33df3SMartin KaFai Lau 	     * to be valid also.
114385d33df3SMartin KaFai Lau 	     */
114485d33df3SMartin KaFai Lau 	    attr->btf_vmlinux_value_type_id) {
1145a26ca7c9SMartin KaFai Lau 		struct btf *btf;
1146a26ca7c9SMartin KaFai Lau 
1147a26ca7c9SMartin KaFai Lau 		btf = btf_get_by_fd(attr->btf_fd);
1148a26ca7c9SMartin KaFai Lau 		if (IS_ERR(btf)) {
1149a26ca7c9SMartin KaFai Lau 			err = PTR_ERR(btf);
1150b936ca64SRoman Gushchin 			goto free_map;
1151a26ca7c9SMartin KaFai Lau 		}
1152350a5c4dSAlexei Starovoitov 		if (btf_is_kernel(btf)) {
1153350a5c4dSAlexei Starovoitov 			btf_put(btf);
1154350a5c4dSAlexei Starovoitov 			err = -EACCES;
1155350a5c4dSAlexei Starovoitov 			goto free_map;
1156350a5c4dSAlexei Starovoitov 		}
115785d33df3SMartin KaFai Lau 		map->btf = btf;
1158a26ca7c9SMartin KaFai Lau 
115985d33df3SMartin KaFai Lau 		if (attr->btf_value_type_id) {
1160e8d2bec0SDaniel Borkmann 			err = map_check_btf(map, btf, attr->btf_key_type_id,
11619b2cf328SMartin KaFai Lau 					    attr->btf_value_type_id);
116285d33df3SMartin KaFai Lau 			if (err)
1163b936ca64SRoman Gushchin 				goto free_map;
1164a26ca7c9SMartin KaFai Lau 		}
1165a26ca7c9SMartin KaFai Lau 
11669b2cf328SMartin KaFai Lau 		map->btf_key_type_id = attr->btf_key_type_id;
11679b2cf328SMartin KaFai Lau 		map->btf_value_type_id = attr->btf_value_type_id;
116885d33df3SMartin KaFai Lau 		map->btf_vmlinux_value_type_id =
116985d33df3SMartin KaFai Lau 			attr->btf_vmlinux_value_type_id;
1170a26ca7c9SMartin KaFai Lau 	}
1171a26ca7c9SMartin KaFai Lau 
1172f71b2f64SKumar Kartikeya Dwivedi 
1173f71b2f64SKumar Kartikeya Dwivedi 	foffs = btf_parse_field_offs(map->record);
1174f71b2f64SKumar Kartikeya Dwivedi 	if (IS_ERR(foffs)) {
1175f71b2f64SKumar Kartikeya Dwivedi 		err = PTR_ERR(foffs);
1176b936ca64SRoman Gushchin 		goto free_map;
1177f71b2f64SKumar Kartikeya Dwivedi 	}
1178f71b2f64SKumar Kartikeya Dwivedi 	map->field_offs = foffs;
1179afdb09c7SChenbo Feng 
11804d7d7f69SKumar Kartikeya Dwivedi 	err = security_bpf_map_alloc(map);
11814d7d7f69SKumar Kartikeya Dwivedi 	if (err)
1182f71b2f64SKumar Kartikeya Dwivedi 		goto free_map_field_offs;
11834d7d7f69SKumar Kartikeya Dwivedi 
1184f3f1c054SMartin KaFai Lau 	err = bpf_map_alloc_id(map);
1185f3f1c054SMartin KaFai Lau 	if (err)
1186b936ca64SRoman Gushchin 		goto free_map_sec;
1187f3f1c054SMartin KaFai Lau 
118848edc1f7SRoman Gushchin 	bpf_map_save_memcg(map);
118948edc1f7SRoman Gushchin 
11906e71b04aSChenbo Feng 	err = bpf_map_new_fd(map, f_flags);
1191bd5f5f4eSMartin KaFai Lau 	if (err < 0) {
1192bd5f5f4eSMartin KaFai Lau 		/* failed to allocate fd.
1193352d20d6SPeng Sun 		 * bpf_map_put_with_uref() is needed because the above
1194bd5f5f4eSMartin KaFai Lau 		 * bpf_map_alloc_id() has published the map
1195bd5f5f4eSMartin KaFai Lau 		 * to the userspace and the userspace may
1196bd5f5f4eSMartin KaFai Lau 		 * have refcnt-ed it through BPF_MAP_GET_FD_BY_ID.
1197bd5f5f4eSMartin KaFai Lau 		 */
1198352d20d6SPeng Sun 		bpf_map_put_with_uref(map);
1199bd5f5f4eSMartin KaFai Lau 		return err;
1200bd5f5f4eSMartin KaFai Lau 	}
120199c55f7dSAlexei Starovoitov 
120299c55f7dSAlexei Starovoitov 	return err;
120399c55f7dSAlexei Starovoitov 
1204afdb09c7SChenbo Feng free_map_sec:
1205afdb09c7SChenbo Feng 	security_bpf_map_free(map);
1206f71b2f64SKumar Kartikeya Dwivedi free_map_field_offs:
1207aa3496acSKumar Kartikeya Dwivedi 	kfree(map->field_offs);
1208b936ca64SRoman Gushchin free_map:
1209a26ca7c9SMartin KaFai Lau 	btf_put(map->btf);
121099c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
121199c55f7dSAlexei Starovoitov 	return err;
121299c55f7dSAlexei Starovoitov }
121399c55f7dSAlexei Starovoitov 
1214db20fd2bSAlexei Starovoitov /* if error is returned, fd is released.
1215db20fd2bSAlexei Starovoitov  * On success caller should complete fd access with matching fdput()
1216db20fd2bSAlexei Starovoitov  */
1217c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f)
1218db20fd2bSAlexei Starovoitov {
1219db20fd2bSAlexei Starovoitov 	if (!f.file)
1220db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EBADF);
1221db20fd2bSAlexei Starovoitov 	if (f.file->f_op != &bpf_map_fops) {
1222db20fd2bSAlexei Starovoitov 		fdput(f);
1223db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EINVAL);
1224db20fd2bSAlexei Starovoitov 	}
1225db20fd2bSAlexei Starovoitov 
1226c2101297SDaniel Borkmann 	return f.file->private_data;
1227c2101297SDaniel Borkmann }
1228c2101297SDaniel Borkmann 
12291e0bd5a0SAndrii Nakryiko void bpf_map_inc(struct bpf_map *map)
1230c9da161cSDaniel Borkmann {
12311e0bd5a0SAndrii Nakryiko 	atomic64_inc(&map->refcnt);
1232c9da161cSDaniel Borkmann }
1233630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_inc);
1234c9da161cSDaniel Borkmann 
12351e0bd5a0SAndrii Nakryiko void bpf_map_inc_with_uref(struct bpf_map *map)
12361e0bd5a0SAndrii Nakryiko {
12371e0bd5a0SAndrii Nakryiko 	atomic64_inc(&map->refcnt);
12381e0bd5a0SAndrii Nakryiko 	atomic64_inc(&map->usercnt);
12391e0bd5a0SAndrii Nakryiko }
12401e0bd5a0SAndrii Nakryiko EXPORT_SYMBOL_GPL(bpf_map_inc_with_uref);
12411e0bd5a0SAndrii Nakryiko 
12421ed4d924SMartin KaFai Lau struct bpf_map *bpf_map_get(u32 ufd)
12431ed4d924SMartin KaFai Lau {
12441ed4d924SMartin KaFai Lau 	struct fd f = fdget(ufd);
12451ed4d924SMartin KaFai Lau 	struct bpf_map *map;
12461ed4d924SMartin KaFai Lau 
12471ed4d924SMartin KaFai Lau 	map = __bpf_map_get(f);
12481ed4d924SMartin KaFai Lau 	if (IS_ERR(map))
12491ed4d924SMartin KaFai Lau 		return map;
12501ed4d924SMartin KaFai Lau 
12511ed4d924SMartin KaFai Lau 	bpf_map_inc(map);
12521ed4d924SMartin KaFai Lau 	fdput(f);
12531ed4d924SMartin KaFai Lau 
12541ed4d924SMartin KaFai Lau 	return map;
12551ed4d924SMartin KaFai Lau }
1256b1d18a75SAlexei Starovoitov EXPORT_SYMBOL(bpf_map_get);
12571ed4d924SMartin KaFai Lau 
1258c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd)
1259c2101297SDaniel Borkmann {
1260c2101297SDaniel Borkmann 	struct fd f = fdget(ufd);
1261c2101297SDaniel Borkmann 	struct bpf_map *map;
1262c2101297SDaniel Borkmann 
1263c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1264c2101297SDaniel Borkmann 	if (IS_ERR(map))
1265c2101297SDaniel Borkmann 		return map;
1266c2101297SDaniel Borkmann 
12671e0bd5a0SAndrii Nakryiko 	bpf_map_inc_with_uref(map);
1268c2101297SDaniel Borkmann 	fdput(f);
1269db20fd2bSAlexei Starovoitov 
1270db20fd2bSAlexei Starovoitov 	return map;
1271db20fd2bSAlexei Starovoitov }
1272db20fd2bSAlexei Starovoitov 
1273bd5f5f4eSMartin KaFai Lau /* map_idr_lock should have been held */
12741e0bd5a0SAndrii Nakryiko static struct bpf_map *__bpf_map_inc_not_zero(struct bpf_map *map, bool uref)
1275bd5f5f4eSMartin KaFai Lau {
1276bd5f5f4eSMartin KaFai Lau 	int refold;
1277bd5f5f4eSMartin KaFai Lau 
12781e0bd5a0SAndrii Nakryiko 	refold = atomic64_fetch_add_unless(&map->refcnt, 1, 0);
1279bd5f5f4eSMartin KaFai Lau 	if (!refold)
1280bd5f5f4eSMartin KaFai Lau 		return ERR_PTR(-ENOENT);
1281bd5f5f4eSMartin KaFai Lau 	if (uref)
12821e0bd5a0SAndrii Nakryiko 		atomic64_inc(&map->usercnt);
1283bd5f5f4eSMartin KaFai Lau 
1284bd5f5f4eSMartin KaFai Lau 	return map;
1285bd5f5f4eSMartin KaFai Lau }
1286bd5f5f4eSMartin KaFai Lau 
12871e0bd5a0SAndrii Nakryiko struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map)
1288b0e4701cSStanislav Fomichev {
1289b0e4701cSStanislav Fomichev 	spin_lock_bh(&map_idr_lock);
12901e0bd5a0SAndrii Nakryiko 	map = __bpf_map_inc_not_zero(map, false);
1291b0e4701cSStanislav Fomichev 	spin_unlock_bh(&map_idr_lock);
1292b0e4701cSStanislav Fomichev 
1293b0e4701cSStanislav Fomichev 	return map;
1294b0e4701cSStanislav Fomichev }
1295b0e4701cSStanislav Fomichev EXPORT_SYMBOL_GPL(bpf_map_inc_not_zero);
1296b0e4701cSStanislav Fomichev 
1297b8cdc051SAlexei Starovoitov int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
1298b8cdc051SAlexei Starovoitov {
1299b8cdc051SAlexei Starovoitov 	return -ENOTSUPP;
1300b8cdc051SAlexei Starovoitov }
1301b8cdc051SAlexei Starovoitov 
1302c9d29f46SMauricio Vasquez B static void *__bpf_copy_key(void __user *ukey, u64 key_size)
1303c9d29f46SMauricio Vasquez B {
1304c9d29f46SMauricio Vasquez B 	if (key_size)
130544779a4bSStanislav Fomichev 		return vmemdup_user(ukey, key_size);
1306c9d29f46SMauricio Vasquez B 
1307c9d29f46SMauricio Vasquez B 	if (ukey)
1308c9d29f46SMauricio Vasquez B 		return ERR_PTR(-EINVAL);
1309c9d29f46SMauricio Vasquez B 
1310c9d29f46SMauricio Vasquez B 	return NULL;
1311c9d29f46SMauricio Vasquez B }
1312c9d29f46SMauricio Vasquez B 
1313af2ac3e1SAlexei Starovoitov static void *___bpf_copy_key(bpfptr_t ukey, u64 key_size)
1314af2ac3e1SAlexei Starovoitov {
1315af2ac3e1SAlexei Starovoitov 	if (key_size)
131644779a4bSStanislav Fomichev 		return kvmemdup_bpfptr(ukey, key_size);
1317af2ac3e1SAlexei Starovoitov 
1318af2ac3e1SAlexei Starovoitov 	if (!bpfptr_is_null(ukey))
1319af2ac3e1SAlexei Starovoitov 		return ERR_PTR(-EINVAL);
1320af2ac3e1SAlexei Starovoitov 
1321af2ac3e1SAlexei Starovoitov 	return NULL;
1322af2ac3e1SAlexei Starovoitov }
1323af2ac3e1SAlexei Starovoitov 
1324db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
132596049f3aSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD flags
1326db20fd2bSAlexei Starovoitov 
1327db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr)
1328db20fd2bSAlexei Starovoitov {
1329535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
1330535e7b4bSMickaël Salaün 	void __user *uvalue = u64_to_user_ptr(attr->value);
1331db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1332db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
133315c14a3dSBrian Vazquez 	void *key, *value;
133415a07b33SAlexei Starovoitov 	u32 value_size;
1335592867bfSDaniel Borkmann 	struct fd f;
1336db20fd2bSAlexei Starovoitov 	int err;
1337db20fd2bSAlexei Starovoitov 
1338db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
1339db20fd2bSAlexei Starovoitov 		return -EINVAL;
1340db20fd2bSAlexei Starovoitov 
134196049f3aSAlexei Starovoitov 	if (attr->flags & ~BPF_F_LOCK)
134296049f3aSAlexei Starovoitov 		return -EINVAL;
134396049f3aSAlexei Starovoitov 
1344592867bfSDaniel Borkmann 	f = fdget(ufd);
1345c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1346db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1347db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
134887df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
13496e71b04aSChenbo Feng 		err = -EPERM;
13506e71b04aSChenbo Feng 		goto err_put;
13516e71b04aSChenbo Feng 	}
13526e71b04aSChenbo Feng 
135396049f3aSAlexei Starovoitov 	if ((attr->flags & BPF_F_LOCK) &&
1354db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
135596049f3aSAlexei Starovoitov 		err = -EINVAL;
135696049f3aSAlexei Starovoitov 		goto err_put;
135796049f3aSAlexei Starovoitov 	}
135896049f3aSAlexei Starovoitov 
1359c9d29f46SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
1360e4448ed8SAl Viro 	if (IS_ERR(key)) {
1361e4448ed8SAl Viro 		err = PTR_ERR(key);
1362db20fd2bSAlexei Starovoitov 		goto err_put;
1363e4448ed8SAl Viro 	}
1364db20fd2bSAlexei Starovoitov 
136515c14a3dSBrian Vazquez 	value_size = bpf_map_value_size(map);
136615a07b33SAlexei Starovoitov 
13678ebe667cSAlexei Starovoitov 	err = -ENOMEM;
1368f0dce1d9SStanislav Fomichev 	value = kvmalloc(value_size, GFP_USER | __GFP_NOWARN);
1369db20fd2bSAlexei Starovoitov 	if (!value)
13708ebe667cSAlexei Starovoitov 		goto free_key;
13718ebe667cSAlexei Starovoitov 
13729330986cSJoanne Koong 	if (map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) {
13739330986cSJoanne Koong 		if (copy_from_user(value, uvalue, value_size))
13749330986cSJoanne Koong 			err = -EFAULT;
13759330986cSJoanne Koong 		else
13769330986cSJoanne Koong 			err = bpf_map_copy_value(map, key, value, attr->flags);
13779330986cSJoanne Koong 		goto free_value;
13789330986cSJoanne Koong 	}
13799330986cSJoanne Koong 
138015c14a3dSBrian Vazquez 	err = bpf_map_copy_value(map, key, value, attr->flags);
138115a07b33SAlexei Starovoitov 	if (err)
13828ebe667cSAlexei Starovoitov 		goto free_value;
1383db20fd2bSAlexei Starovoitov 
1384db20fd2bSAlexei Starovoitov 	err = -EFAULT;
138515a07b33SAlexei Starovoitov 	if (copy_to_user(uvalue, value, value_size) != 0)
13868ebe667cSAlexei Starovoitov 		goto free_value;
1387db20fd2bSAlexei Starovoitov 
1388db20fd2bSAlexei Starovoitov 	err = 0;
1389db20fd2bSAlexei Starovoitov 
13908ebe667cSAlexei Starovoitov free_value:
1391f0dce1d9SStanislav Fomichev 	kvfree(value);
1392db20fd2bSAlexei Starovoitov free_key:
139344779a4bSStanislav Fomichev 	kvfree(key);
1394db20fd2bSAlexei Starovoitov err_put:
1395db20fd2bSAlexei Starovoitov 	fdput(f);
1396db20fd2bSAlexei Starovoitov 	return err;
1397db20fd2bSAlexei Starovoitov }
1398db20fd2bSAlexei Starovoitov 
13991ae80cf3SDaniel Colascione 
14003274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags
1401db20fd2bSAlexei Starovoitov 
1402af2ac3e1SAlexei Starovoitov static int map_update_elem(union bpf_attr *attr, bpfptr_t uattr)
1403db20fd2bSAlexei Starovoitov {
1404af2ac3e1SAlexei Starovoitov 	bpfptr_t ukey = make_bpfptr(attr->key, uattr.is_kernel);
1405af2ac3e1SAlexei Starovoitov 	bpfptr_t uvalue = make_bpfptr(attr->value, uattr.is_kernel);
1406db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1407db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
1408db20fd2bSAlexei Starovoitov 	void *key, *value;
140915a07b33SAlexei Starovoitov 	u32 value_size;
1410592867bfSDaniel Borkmann 	struct fd f;
1411db20fd2bSAlexei Starovoitov 	int err;
1412db20fd2bSAlexei Starovoitov 
1413db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM))
1414db20fd2bSAlexei Starovoitov 		return -EINVAL;
1415db20fd2bSAlexei Starovoitov 
1416592867bfSDaniel Borkmann 	f = fdget(ufd);
1417c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1418db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1419db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
1420353050beSDaniel Borkmann 	bpf_map_write_active_inc(map);
142187df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
14226e71b04aSChenbo Feng 		err = -EPERM;
14236e71b04aSChenbo Feng 		goto err_put;
14246e71b04aSChenbo Feng 	}
14256e71b04aSChenbo Feng 
142696049f3aSAlexei Starovoitov 	if ((attr->flags & BPF_F_LOCK) &&
1427db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
142896049f3aSAlexei Starovoitov 		err = -EINVAL;
142996049f3aSAlexei Starovoitov 		goto err_put;
143096049f3aSAlexei Starovoitov 	}
143196049f3aSAlexei Starovoitov 
1432af2ac3e1SAlexei Starovoitov 	key = ___bpf_copy_key(ukey, map->key_size);
1433e4448ed8SAl Viro 	if (IS_ERR(key)) {
1434e4448ed8SAl Viro 		err = PTR_ERR(key);
1435db20fd2bSAlexei Starovoitov 		goto err_put;
1436e4448ed8SAl Viro 	}
1437db20fd2bSAlexei Starovoitov 
1438f0dce1d9SStanislav Fomichev 	value_size = bpf_map_value_size(map);
1439a02c118eSWang Yufen 	value = kvmemdup_bpfptr(uvalue, value_size);
1440a02c118eSWang Yufen 	if (IS_ERR(value)) {
1441a02c118eSWang Yufen 		err = PTR_ERR(value);
1442db20fd2bSAlexei Starovoitov 		goto free_key;
1443a02c118eSWang Yufen 	}
1444db20fd2bSAlexei Starovoitov 
14453af43ba4SHou Tao 	err = bpf_map_update_value(map, f.file, key, value, attr->flags);
14466710e112SJesper Dangaard Brouer 
1447f0dce1d9SStanislav Fomichev 	kvfree(value);
1448db20fd2bSAlexei Starovoitov free_key:
144944779a4bSStanislav Fomichev 	kvfree(key);
1450db20fd2bSAlexei Starovoitov err_put:
1451353050beSDaniel Borkmann 	bpf_map_write_active_dec(map);
1452db20fd2bSAlexei Starovoitov 	fdput(f);
1453db20fd2bSAlexei Starovoitov 	return err;
1454db20fd2bSAlexei Starovoitov }
1455db20fd2bSAlexei Starovoitov 
1456db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key
1457db20fd2bSAlexei Starovoitov 
1458b88df697SBenjamin Tissoires static int map_delete_elem(union bpf_attr *attr, bpfptr_t uattr)
1459db20fd2bSAlexei Starovoitov {
1460b88df697SBenjamin Tissoires 	bpfptr_t ukey = make_bpfptr(attr->key, uattr.is_kernel);
1461db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1462db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
1463592867bfSDaniel Borkmann 	struct fd f;
1464db20fd2bSAlexei Starovoitov 	void *key;
1465db20fd2bSAlexei Starovoitov 	int err;
1466db20fd2bSAlexei Starovoitov 
1467db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_DELETE_ELEM))
1468db20fd2bSAlexei Starovoitov 		return -EINVAL;
1469db20fd2bSAlexei Starovoitov 
1470592867bfSDaniel Borkmann 	f = fdget(ufd);
1471c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1472db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1473db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
1474353050beSDaniel Borkmann 	bpf_map_write_active_inc(map);
147587df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
14766e71b04aSChenbo Feng 		err = -EPERM;
14776e71b04aSChenbo Feng 		goto err_put;
14786e71b04aSChenbo Feng 	}
14796e71b04aSChenbo Feng 
1480b88df697SBenjamin Tissoires 	key = ___bpf_copy_key(ukey, map->key_size);
1481e4448ed8SAl Viro 	if (IS_ERR(key)) {
1482e4448ed8SAl Viro 		err = PTR_ERR(key);
1483db20fd2bSAlexei Starovoitov 		goto err_put;
1484e4448ed8SAl Viro 	}
1485db20fd2bSAlexei Starovoitov 
1486a3884572SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
1487a3884572SJakub Kicinski 		err = bpf_map_offload_delete_elem(map, key);
1488a3884572SJakub Kicinski 		goto out;
148985d33df3SMartin KaFai Lau 	} else if (IS_FD_PROG_ARRAY(map) ||
149085d33df3SMartin KaFai Lau 		   map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
149185d33df3SMartin KaFai Lau 		/* These maps require sleepable context */
1492da765a2fSDaniel Borkmann 		err = map->ops->map_delete_elem(map, key);
1493da765a2fSDaniel Borkmann 		goto out;
1494a3884572SJakub Kicinski 	}
1495a3884572SJakub Kicinski 
1496b6e5dae1SThomas Gleixner 	bpf_disable_instrumentation();
1497db20fd2bSAlexei Starovoitov 	rcu_read_lock();
1498db20fd2bSAlexei Starovoitov 	err = map->ops->map_delete_elem(map, key);
1499db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
1500b6e5dae1SThomas Gleixner 	bpf_enable_instrumentation();
15011ae80cf3SDaniel Colascione 	maybe_wait_bpf_programs(map);
1502a3884572SJakub Kicinski out:
150344779a4bSStanislav Fomichev 	kvfree(key);
1504db20fd2bSAlexei Starovoitov err_put:
1505353050beSDaniel Borkmann 	bpf_map_write_active_dec(map);
1506db20fd2bSAlexei Starovoitov 	fdput(f);
1507db20fd2bSAlexei Starovoitov 	return err;
1508db20fd2bSAlexei Starovoitov }
1509db20fd2bSAlexei Starovoitov 
1510db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
1511db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key
1512db20fd2bSAlexei Starovoitov 
1513db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr)
1514db20fd2bSAlexei Starovoitov {
1515535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
1516535e7b4bSMickaël Salaün 	void __user *unext_key = u64_to_user_ptr(attr->next_key);
1517db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1518db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
1519db20fd2bSAlexei Starovoitov 	void *key, *next_key;
1520592867bfSDaniel Borkmann 	struct fd f;
1521db20fd2bSAlexei Starovoitov 	int err;
1522db20fd2bSAlexei Starovoitov 
1523db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY))
1524db20fd2bSAlexei Starovoitov 		return -EINVAL;
1525db20fd2bSAlexei Starovoitov 
1526592867bfSDaniel Borkmann 	f = fdget(ufd);
1527c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1528db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1529db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
153087df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
15316e71b04aSChenbo Feng 		err = -EPERM;
15326e71b04aSChenbo Feng 		goto err_put;
15336e71b04aSChenbo Feng 	}
15346e71b04aSChenbo Feng 
15358fe45924STeng Qin 	if (ukey) {
1536c9d29f46SMauricio Vasquez B 		key = __bpf_copy_key(ukey, map->key_size);
1537e4448ed8SAl Viro 		if (IS_ERR(key)) {
1538e4448ed8SAl Viro 			err = PTR_ERR(key);
1539db20fd2bSAlexei Starovoitov 			goto err_put;
1540e4448ed8SAl Viro 		}
15418fe45924STeng Qin 	} else {
15428fe45924STeng Qin 		key = NULL;
15438fe45924STeng Qin 	}
1544db20fd2bSAlexei Starovoitov 
1545db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
154644779a4bSStanislav Fomichev 	next_key = kvmalloc(map->key_size, GFP_USER);
1547db20fd2bSAlexei Starovoitov 	if (!next_key)
1548db20fd2bSAlexei Starovoitov 		goto free_key;
1549db20fd2bSAlexei Starovoitov 
1550a3884572SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
1551a3884572SJakub Kicinski 		err = bpf_map_offload_get_next_key(map, key, next_key);
1552a3884572SJakub Kicinski 		goto out;
1553a3884572SJakub Kicinski 	}
1554a3884572SJakub Kicinski 
1555db20fd2bSAlexei Starovoitov 	rcu_read_lock();
1556db20fd2bSAlexei Starovoitov 	err = map->ops->map_get_next_key(map, key, next_key);
1557db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
1558a3884572SJakub Kicinski out:
1559db20fd2bSAlexei Starovoitov 	if (err)
1560db20fd2bSAlexei Starovoitov 		goto free_next_key;
1561db20fd2bSAlexei Starovoitov 
1562db20fd2bSAlexei Starovoitov 	err = -EFAULT;
1563db20fd2bSAlexei Starovoitov 	if (copy_to_user(unext_key, next_key, map->key_size) != 0)
1564db20fd2bSAlexei Starovoitov 		goto free_next_key;
1565db20fd2bSAlexei Starovoitov 
1566db20fd2bSAlexei Starovoitov 	err = 0;
1567db20fd2bSAlexei Starovoitov 
1568db20fd2bSAlexei Starovoitov free_next_key:
156944779a4bSStanislav Fomichev 	kvfree(next_key);
1570db20fd2bSAlexei Starovoitov free_key:
157144779a4bSStanislav Fomichev 	kvfree(key);
1572db20fd2bSAlexei Starovoitov err_put:
1573db20fd2bSAlexei Starovoitov 	fdput(f);
1574db20fd2bSAlexei Starovoitov 	return err;
1575db20fd2bSAlexei Starovoitov }
1576db20fd2bSAlexei Starovoitov 
1577aa2e93b8SBrian Vazquez int generic_map_delete_batch(struct bpf_map *map,
1578aa2e93b8SBrian Vazquez 			     const union bpf_attr *attr,
1579aa2e93b8SBrian Vazquez 			     union bpf_attr __user *uattr)
1580aa2e93b8SBrian Vazquez {
1581aa2e93b8SBrian Vazquez 	void __user *keys = u64_to_user_ptr(attr->batch.keys);
1582aa2e93b8SBrian Vazquez 	u32 cp, max_count;
1583aa2e93b8SBrian Vazquez 	int err = 0;
1584aa2e93b8SBrian Vazquez 	void *key;
1585aa2e93b8SBrian Vazquez 
1586aa2e93b8SBrian Vazquez 	if (attr->batch.elem_flags & ~BPF_F_LOCK)
1587aa2e93b8SBrian Vazquez 		return -EINVAL;
1588aa2e93b8SBrian Vazquez 
1589aa2e93b8SBrian Vazquez 	if ((attr->batch.elem_flags & BPF_F_LOCK) &&
1590db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
1591aa2e93b8SBrian Vazquez 		return -EINVAL;
1592aa2e93b8SBrian Vazquez 	}
1593aa2e93b8SBrian Vazquez 
1594aa2e93b8SBrian Vazquez 	max_count = attr->batch.count;
1595aa2e93b8SBrian Vazquez 	if (!max_count)
1596aa2e93b8SBrian Vazquez 		return 0;
1597aa2e93b8SBrian Vazquez 
159844779a4bSStanislav Fomichev 	key = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN);
15992e3a94aaSBrian Vazquez 	if (!key)
16002e3a94aaSBrian Vazquez 		return -ENOMEM;
16012e3a94aaSBrian Vazquez 
1602aa2e93b8SBrian Vazquez 	for (cp = 0; cp < max_count; cp++) {
16032e3a94aaSBrian Vazquez 		err = -EFAULT;
16042e3a94aaSBrian Vazquez 		if (copy_from_user(key, keys + cp * map->key_size,
16052e3a94aaSBrian Vazquez 				   map->key_size))
1606aa2e93b8SBrian Vazquez 			break;
1607aa2e93b8SBrian Vazquez 
1608aa2e93b8SBrian Vazquez 		if (bpf_map_is_dev_bound(map)) {
1609aa2e93b8SBrian Vazquez 			err = bpf_map_offload_delete_elem(map, key);
1610aa2e93b8SBrian Vazquez 			break;
1611aa2e93b8SBrian Vazquez 		}
1612aa2e93b8SBrian Vazquez 
1613b6e5dae1SThomas Gleixner 		bpf_disable_instrumentation();
1614aa2e93b8SBrian Vazquez 		rcu_read_lock();
1615aa2e93b8SBrian Vazquez 		err = map->ops->map_delete_elem(map, key);
1616aa2e93b8SBrian Vazquez 		rcu_read_unlock();
1617b6e5dae1SThomas Gleixner 		bpf_enable_instrumentation();
1618aa2e93b8SBrian Vazquez 		if (err)
1619aa2e93b8SBrian Vazquez 			break;
162075134f16SEric Dumazet 		cond_resched();
1621aa2e93b8SBrian Vazquez 	}
1622aa2e93b8SBrian Vazquez 	if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp)))
1623aa2e93b8SBrian Vazquez 		err = -EFAULT;
16242e3a94aaSBrian Vazquez 
162544779a4bSStanislav Fomichev 	kvfree(key);
16269087c6ffSEric Dumazet 
16279087c6ffSEric Dumazet 	maybe_wait_bpf_programs(map);
1628aa2e93b8SBrian Vazquez 	return err;
1629aa2e93b8SBrian Vazquez }
1630aa2e93b8SBrian Vazquez 
16313af43ba4SHou Tao int generic_map_update_batch(struct bpf_map *map, struct file *map_file,
1632aa2e93b8SBrian Vazquez 			     const union bpf_attr *attr,
1633aa2e93b8SBrian Vazquez 			     union bpf_attr __user *uattr)
1634aa2e93b8SBrian Vazquez {
1635aa2e93b8SBrian Vazquez 	void __user *values = u64_to_user_ptr(attr->batch.values);
1636aa2e93b8SBrian Vazquez 	void __user *keys = u64_to_user_ptr(attr->batch.keys);
1637aa2e93b8SBrian Vazquez 	u32 value_size, cp, max_count;
1638aa2e93b8SBrian Vazquez 	void *key, *value;
1639aa2e93b8SBrian Vazquez 	int err = 0;
1640aa2e93b8SBrian Vazquez 
1641aa2e93b8SBrian Vazquez 	if (attr->batch.elem_flags & ~BPF_F_LOCK)
1642aa2e93b8SBrian Vazquez 		return -EINVAL;
1643aa2e93b8SBrian Vazquez 
1644aa2e93b8SBrian Vazquez 	if ((attr->batch.elem_flags & BPF_F_LOCK) &&
1645db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
1646aa2e93b8SBrian Vazquez 		return -EINVAL;
1647aa2e93b8SBrian Vazquez 	}
1648aa2e93b8SBrian Vazquez 
1649aa2e93b8SBrian Vazquez 	value_size = bpf_map_value_size(map);
1650aa2e93b8SBrian Vazquez 
1651aa2e93b8SBrian Vazquez 	max_count = attr->batch.count;
1652aa2e93b8SBrian Vazquez 	if (!max_count)
1653aa2e93b8SBrian Vazquez 		return 0;
1654aa2e93b8SBrian Vazquez 
165544779a4bSStanislav Fomichev 	key = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN);
16562e3a94aaSBrian Vazquez 	if (!key)
1657aa2e93b8SBrian Vazquez 		return -ENOMEM;
1658aa2e93b8SBrian Vazquez 
1659f0dce1d9SStanislav Fomichev 	value = kvmalloc(value_size, GFP_USER | __GFP_NOWARN);
16602e3a94aaSBrian Vazquez 	if (!value) {
166144779a4bSStanislav Fomichev 		kvfree(key);
16622e3a94aaSBrian Vazquez 		return -ENOMEM;
1663aa2e93b8SBrian Vazquez 	}
16642e3a94aaSBrian Vazquez 
16652e3a94aaSBrian Vazquez 	for (cp = 0; cp < max_count; cp++) {
1666aa2e93b8SBrian Vazquez 		err = -EFAULT;
16672e3a94aaSBrian Vazquez 		if (copy_from_user(key, keys + cp * map->key_size,
16682e3a94aaSBrian Vazquez 		    map->key_size) ||
16692e3a94aaSBrian Vazquez 		    copy_from_user(value, values + cp * value_size, value_size))
1670aa2e93b8SBrian Vazquez 			break;
1671aa2e93b8SBrian Vazquez 
16723af43ba4SHou Tao 		err = bpf_map_update_value(map, map_file, key, value,
1673aa2e93b8SBrian Vazquez 					   attr->batch.elem_flags);
1674aa2e93b8SBrian Vazquez 
1675aa2e93b8SBrian Vazquez 		if (err)
1676aa2e93b8SBrian Vazquez 			break;
167775134f16SEric Dumazet 		cond_resched();
1678aa2e93b8SBrian Vazquez 	}
1679aa2e93b8SBrian Vazquez 
1680aa2e93b8SBrian Vazquez 	if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp)))
1681aa2e93b8SBrian Vazquez 		err = -EFAULT;
1682aa2e93b8SBrian Vazquez 
1683f0dce1d9SStanislav Fomichev 	kvfree(value);
168444779a4bSStanislav Fomichev 	kvfree(key);
1685aa2e93b8SBrian Vazquez 	return err;
1686aa2e93b8SBrian Vazquez }
1687aa2e93b8SBrian Vazquez 
1688cb4d03abSBrian Vazquez #define MAP_LOOKUP_RETRIES 3
1689cb4d03abSBrian Vazquez 
1690cb4d03abSBrian Vazquez int generic_map_lookup_batch(struct bpf_map *map,
1691cb4d03abSBrian Vazquez 				    const union bpf_attr *attr,
1692cb4d03abSBrian Vazquez 				    union bpf_attr __user *uattr)
1693cb4d03abSBrian Vazquez {
1694cb4d03abSBrian Vazquez 	void __user *uobatch = u64_to_user_ptr(attr->batch.out_batch);
1695cb4d03abSBrian Vazquez 	void __user *ubatch = u64_to_user_ptr(attr->batch.in_batch);
1696cb4d03abSBrian Vazquez 	void __user *values = u64_to_user_ptr(attr->batch.values);
1697cb4d03abSBrian Vazquez 	void __user *keys = u64_to_user_ptr(attr->batch.keys);
1698cb4d03abSBrian Vazquez 	void *buf, *buf_prevkey, *prev_key, *key, *value;
1699cb4d03abSBrian Vazquez 	int err, retry = MAP_LOOKUP_RETRIES;
1700cb4d03abSBrian Vazquez 	u32 value_size, cp, max_count;
1701cb4d03abSBrian Vazquez 
1702cb4d03abSBrian Vazquez 	if (attr->batch.elem_flags & ~BPF_F_LOCK)
1703cb4d03abSBrian Vazquez 		return -EINVAL;
1704cb4d03abSBrian Vazquez 
1705cb4d03abSBrian Vazquez 	if ((attr->batch.elem_flags & BPF_F_LOCK) &&
1706db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK))
1707cb4d03abSBrian Vazquez 		return -EINVAL;
1708cb4d03abSBrian Vazquez 
1709cb4d03abSBrian Vazquez 	value_size = bpf_map_value_size(map);
1710cb4d03abSBrian Vazquez 
1711cb4d03abSBrian Vazquez 	max_count = attr->batch.count;
1712cb4d03abSBrian Vazquez 	if (!max_count)
1713cb4d03abSBrian Vazquez 		return 0;
1714cb4d03abSBrian Vazquez 
1715cb4d03abSBrian Vazquez 	if (put_user(0, &uattr->batch.count))
1716cb4d03abSBrian Vazquez 		return -EFAULT;
1717cb4d03abSBrian Vazquez 
171844779a4bSStanislav Fomichev 	buf_prevkey = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN);
1719cb4d03abSBrian Vazquez 	if (!buf_prevkey)
1720cb4d03abSBrian Vazquez 		return -ENOMEM;
1721cb4d03abSBrian Vazquez 
1722f0dce1d9SStanislav Fomichev 	buf = kvmalloc(map->key_size + value_size, GFP_USER | __GFP_NOWARN);
1723cb4d03abSBrian Vazquez 	if (!buf) {
172444779a4bSStanislav Fomichev 		kvfree(buf_prevkey);
1725cb4d03abSBrian Vazquez 		return -ENOMEM;
1726cb4d03abSBrian Vazquez 	}
1727cb4d03abSBrian Vazquez 
1728cb4d03abSBrian Vazquez 	err = -EFAULT;
1729cb4d03abSBrian Vazquez 	prev_key = NULL;
1730cb4d03abSBrian Vazquez 	if (ubatch && copy_from_user(buf_prevkey, ubatch, map->key_size))
1731cb4d03abSBrian Vazquez 		goto free_buf;
1732cb4d03abSBrian Vazquez 	key = buf;
1733cb4d03abSBrian Vazquez 	value = key + map->key_size;
1734cb4d03abSBrian Vazquez 	if (ubatch)
1735cb4d03abSBrian Vazquez 		prev_key = buf_prevkey;
1736cb4d03abSBrian Vazquez 
1737cb4d03abSBrian Vazquez 	for (cp = 0; cp < max_count;) {
1738cb4d03abSBrian Vazquez 		rcu_read_lock();
1739cb4d03abSBrian Vazquez 		err = map->ops->map_get_next_key(map, prev_key, key);
1740cb4d03abSBrian Vazquez 		rcu_read_unlock();
1741cb4d03abSBrian Vazquez 		if (err)
1742cb4d03abSBrian Vazquez 			break;
1743cb4d03abSBrian Vazquez 		err = bpf_map_copy_value(map, key, value,
1744cb4d03abSBrian Vazquez 					 attr->batch.elem_flags);
1745cb4d03abSBrian Vazquez 
1746cb4d03abSBrian Vazquez 		if (err == -ENOENT) {
1747cb4d03abSBrian Vazquez 			if (retry) {
1748cb4d03abSBrian Vazquez 				retry--;
1749cb4d03abSBrian Vazquez 				continue;
1750cb4d03abSBrian Vazquez 			}
1751cb4d03abSBrian Vazquez 			err = -EINTR;
1752cb4d03abSBrian Vazquez 			break;
1753cb4d03abSBrian Vazquez 		}
1754cb4d03abSBrian Vazquez 
1755cb4d03abSBrian Vazquez 		if (err)
1756cb4d03abSBrian Vazquez 			goto free_buf;
1757cb4d03abSBrian Vazquez 
1758cb4d03abSBrian Vazquez 		if (copy_to_user(keys + cp * map->key_size, key,
1759cb4d03abSBrian Vazquez 				 map->key_size)) {
1760cb4d03abSBrian Vazquez 			err = -EFAULT;
1761cb4d03abSBrian Vazquez 			goto free_buf;
1762cb4d03abSBrian Vazquez 		}
1763cb4d03abSBrian Vazquez 		if (copy_to_user(values + cp * value_size, value, value_size)) {
1764cb4d03abSBrian Vazquez 			err = -EFAULT;
1765cb4d03abSBrian Vazquez 			goto free_buf;
1766cb4d03abSBrian Vazquez 		}
1767cb4d03abSBrian Vazquez 
1768cb4d03abSBrian Vazquez 		if (!prev_key)
1769cb4d03abSBrian Vazquez 			prev_key = buf_prevkey;
1770cb4d03abSBrian Vazquez 
1771cb4d03abSBrian Vazquez 		swap(prev_key, key);
1772cb4d03abSBrian Vazquez 		retry = MAP_LOOKUP_RETRIES;
1773cb4d03abSBrian Vazquez 		cp++;
177475134f16SEric Dumazet 		cond_resched();
1775cb4d03abSBrian Vazquez 	}
1776cb4d03abSBrian Vazquez 
1777cb4d03abSBrian Vazquez 	if (err == -EFAULT)
1778cb4d03abSBrian Vazquez 		goto free_buf;
1779cb4d03abSBrian Vazquez 
1780cb4d03abSBrian Vazquez 	if ((copy_to_user(&uattr->batch.count, &cp, sizeof(cp)) ||
1781cb4d03abSBrian Vazquez 		    (cp && copy_to_user(uobatch, prev_key, map->key_size))))
1782cb4d03abSBrian Vazquez 		err = -EFAULT;
1783cb4d03abSBrian Vazquez 
1784cb4d03abSBrian Vazquez free_buf:
178544779a4bSStanislav Fomichev 	kvfree(buf_prevkey);
1786f0dce1d9SStanislav Fomichev 	kvfree(buf);
1787cb4d03abSBrian Vazquez 	return err;
1788cb4d03abSBrian Vazquez }
1789cb4d03abSBrian Vazquez 
17903e87f192SDenis Salopek #define BPF_MAP_LOOKUP_AND_DELETE_ELEM_LAST_FIELD flags
1791bd513cd0SMauricio Vasquez B 
1792bd513cd0SMauricio Vasquez B static int map_lookup_and_delete_elem(union bpf_attr *attr)
1793bd513cd0SMauricio Vasquez B {
1794bd513cd0SMauricio Vasquez B 	void __user *ukey = u64_to_user_ptr(attr->key);
1795bd513cd0SMauricio Vasquez B 	void __user *uvalue = u64_to_user_ptr(attr->value);
1796bd513cd0SMauricio Vasquez B 	int ufd = attr->map_fd;
1797bd513cd0SMauricio Vasquez B 	struct bpf_map *map;
1798540fefc0SAlexei Starovoitov 	void *key, *value;
1799bd513cd0SMauricio Vasquez B 	u32 value_size;
1800bd513cd0SMauricio Vasquez B 	struct fd f;
1801bd513cd0SMauricio Vasquez B 	int err;
1802bd513cd0SMauricio Vasquez B 
1803bd513cd0SMauricio Vasquez B 	if (CHECK_ATTR(BPF_MAP_LOOKUP_AND_DELETE_ELEM))
1804bd513cd0SMauricio Vasquez B 		return -EINVAL;
1805bd513cd0SMauricio Vasquez B 
18063e87f192SDenis Salopek 	if (attr->flags & ~BPF_F_LOCK)
18073e87f192SDenis Salopek 		return -EINVAL;
18083e87f192SDenis Salopek 
1809bd513cd0SMauricio Vasquez B 	f = fdget(ufd);
1810bd513cd0SMauricio Vasquez B 	map = __bpf_map_get(f);
1811bd513cd0SMauricio Vasquez B 	if (IS_ERR(map))
1812bd513cd0SMauricio Vasquez B 		return PTR_ERR(map);
1813353050beSDaniel Borkmann 	bpf_map_write_active_inc(map);
18141ea0f912SAnton Protopopov 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ) ||
18151ea0f912SAnton Protopopov 	    !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
1816bd513cd0SMauricio Vasquez B 		err = -EPERM;
1817bd513cd0SMauricio Vasquez B 		goto err_put;
1818bd513cd0SMauricio Vasquez B 	}
1819bd513cd0SMauricio Vasquez B 
18203e87f192SDenis Salopek 	if (attr->flags &&
18213e87f192SDenis Salopek 	    (map->map_type == BPF_MAP_TYPE_QUEUE ||
18223e87f192SDenis Salopek 	     map->map_type == BPF_MAP_TYPE_STACK)) {
18233e87f192SDenis Salopek 		err = -EINVAL;
18243e87f192SDenis Salopek 		goto err_put;
18253e87f192SDenis Salopek 	}
18263e87f192SDenis Salopek 
18273e87f192SDenis Salopek 	if ((attr->flags & BPF_F_LOCK) &&
1828db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
18293e87f192SDenis Salopek 		err = -EINVAL;
18303e87f192SDenis Salopek 		goto err_put;
18313e87f192SDenis Salopek 	}
18323e87f192SDenis Salopek 
1833bd513cd0SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
1834bd513cd0SMauricio Vasquez B 	if (IS_ERR(key)) {
1835bd513cd0SMauricio Vasquez B 		err = PTR_ERR(key);
1836bd513cd0SMauricio Vasquez B 		goto err_put;
1837bd513cd0SMauricio Vasquez B 	}
1838bd513cd0SMauricio Vasquez B 
18393e87f192SDenis Salopek 	value_size = bpf_map_value_size(map);
1840bd513cd0SMauricio Vasquez B 
1841bd513cd0SMauricio Vasquez B 	err = -ENOMEM;
1842f0dce1d9SStanislav Fomichev 	value = kvmalloc(value_size, GFP_USER | __GFP_NOWARN);
1843bd513cd0SMauricio Vasquez B 	if (!value)
1844bd513cd0SMauricio Vasquez B 		goto free_key;
1845bd513cd0SMauricio Vasquez B 
18463e87f192SDenis Salopek 	err = -ENOTSUPP;
1847bd513cd0SMauricio Vasquez B 	if (map->map_type == BPF_MAP_TYPE_QUEUE ||
1848bd513cd0SMauricio Vasquez B 	    map->map_type == BPF_MAP_TYPE_STACK) {
1849bd513cd0SMauricio Vasquez B 		err = map->ops->map_pop_elem(map, value);
18503e87f192SDenis Salopek 	} else if (map->map_type == BPF_MAP_TYPE_HASH ||
18513e87f192SDenis Salopek 		   map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
18523e87f192SDenis Salopek 		   map->map_type == BPF_MAP_TYPE_LRU_HASH ||
18533e87f192SDenis Salopek 		   map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
18543e87f192SDenis Salopek 		if (!bpf_map_is_dev_bound(map)) {
18553e87f192SDenis Salopek 			bpf_disable_instrumentation();
18563e87f192SDenis Salopek 			rcu_read_lock();
18573e87f192SDenis Salopek 			err = map->ops->map_lookup_and_delete_elem(map, key, value, attr->flags);
18583e87f192SDenis Salopek 			rcu_read_unlock();
18593e87f192SDenis Salopek 			bpf_enable_instrumentation();
18603e87f192SDenis Salopek 		}
1861bd513cd0SMauricio Vasquez B 	}
1862bd513cd0SMauricio Vasquez B 
1863bd513cd0SMauricio Vasquez B 	if (err)
1864bd513cd0SMauricio Vasquez B 		goto free_value;
1865bd513cd0SMauricio Vasquez B 
18667f645462SWei Yongjun 	if (copy_to_user(uvalue, value, value_size) != 0) {
18677f645462SWei Yongjun 		err = -EFAULT;
1868bd513cd0SMauricio Vasquez B 		goto free_value;
18697f645462SWei Yongjun 	}
1870bd513cd0SMauricio Vasquez B 
1871bd513cd0SMauricio Vasquez B 	err = 0;
1872bd513cd0SMauricio Vasquez B 
1873bd513cd0SMauricio Vasquez B free_value:
1874f0dce1d9SStanislav Fomichev 	kvfree(value);
1875bd513cd0SMauricio Vasquez B free_key:
187644779a4bSStanislav Fomichev 	kvfree(key);
1877bd513cd0SMauricio Vasquez B err_put:
1878353050beSDaniel Borkmann 	bpf_map_write_active_dec(map);
1879bd513cd0SMauricio Vasquez B 	fdput(f);
1880bd513cd0SMauricio Vasquez B 	return err;
1881bd513cd0SMauricio Vasquez B }
1882bd513cd0SMauricio Vasquez B 
188387df15deSDaniel Borkmann #define BPF_MAP_FREEZE_LAST_FIELD map_fd
188487df15deSDaniel Borkmann 
188587df15deSDaniel Borkmann static int map_freeze(const union bpf_attr *attr)
188687df15deSDaniel Borkmann {
188787df15deSDaniel Borkmann 	int err = 0, ufd = attr->map_fd;
188887df15deSDaniel Borkmann 	struct bpf_map *map;
188987df15deSDaniel Borkmann 	struct fd f;
189087df15deSDaniel Borkmann 
189187df15deSDaniel Borkmann 	if (CHECK_ATTR(BPF_MAP_FREEZE))
189287df15deSDaniel Borkmann 		return -EINVAL;
189387df15deSDaniel Borkmann 
189487df15deSDaniel Borkmann 	f = fdget(ufd);
189587df15deSDaniel Borkmann 	map = __bpf_map_get(f);
189687df15deSDaniel Borkmann 	if (IS_ERR(map))
189787df15deSDaniel Borkmann 		return PTR_ERR(map);
1898fc970227SAndrii Nakryiko 
1899db559117SKumar Kartikeya Dwivedi 	if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS || !IS_ERR_OR_NULL(map->record)) {
1900849b4d94SMartin KaFai Lau 		fdput(f);
1901849b4d94SMartin KaFai Lau 		return -ENOTSUPP;
1902849b4d94SMartin KaFai Lau 	}
1903849b4d94SMartin KaFai Lau 
1904fc970227SAndrii Nakryiko 	mutex_lock(&map->freeze_mutex);
1905353050beSDaniel Borkmann 	if (bpf_map_write_active(map)) {
1906fc970227SAndrii Nakryiko 		err = -EBUSY;
1907fc970227SAndrii Nakryiko 		goto err_put;
1908fc970227SAndrii Nakryiko 	}
190987df15deSDaniel Borkmann 	if (READ_ONCE(map->frozen)) {
191087df15deSDaniel Borkmann 		err = -EBUSY;
191187df15deSDaniel Borkmann 		goto err_put;
191287df15deSDaniel Borkmann 	}
19132c78ee89SAlexei Starovoitov 	if (!bpf_capable()) {
191487df15deSDaniel Borkmann 		err = -EPERM;
191587df15deSDaniel Borkmann 		goto err_put;
191687df15deSDaniel Borkmann 	}
191787df15deSDaniel Borkmann 
191887df15deSDaniel Borkmann 	WRITE_ONCE(map->frozen, true);
191987df15deSDaniel Borkmann err_put:
1920fc970227SAndrii Nakryiko 	mutex_unlock(&map->freeze_mutex);
192187df15deSDaniel Borkmann 	fdput(f);
192287df15deSDaniel Borkmann 	return err;
192387df15deSDaniel Borkmann }
192487df15deSDaniel Borkmann 
19257de16e3aSJakub Kicinski static const struct bpf_prog_ops * const bpf_prog_types[] = {
192691cc1a99SAlexei Starovoitov #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \
19277de16e3aSJakub Kicinski 	[_id] = & _name ## _prog_ops,
19287de16e3aSJakub Kicinski #define BPF_MAP_TYPE(_id, _ops)
1929f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name)
19307de16e3aSJakub Kicinski #include <linux/bpf_types.h>
19317de16e3aSJakub Kicinski #undef BPF_PROG_TYPE
19327de16e3aSJakub Kicinski #undef BPF_MAP_TYPE
1933f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE
19347de16e3aSJakub Kicinski };
19357de16e3aSJakub Kicinski 
193609756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
193709756af4SAlexei Starovoitov {
1938d0f1a451SDaniel Borkmann 	const struct bpf_prog_ops *ops;
1939d0f1a451SDaniel Borkmann 
1940d0f1a451SDaniel Borkmann 	if (type >= ARRAY_SIZE(bpf_prog_types))
1941d0f1a451SDaniel Borkmann 		return -EINVAL;
1942d0f1a451SDaniel Borkmann 	type = array_index_nospec(type, ARRAY_SIZE(bpf_prog_types));
1943d0f1a451SDaniel Borkmann 	ops = bpf_prog_types[type];
1944d0f1a451SDaniel Borkmann 	if (!ops)
1945be9370a7SJohannes Berg 		return -EINVAL;
194609756af4SAlexei Starovoitov 
1947ab3f0063SJakub Kicinski 	if (!bpf_prog_is_dev_bound(prog->aux))
1948d0f1a451SDaniel Borkmann 		prog->aux->ops = ops;
1949ab3f0063SJakub Kicinski 	else
1950ab3f0063SJakub Kicinski 		prog->aux->ops = &bpf_offload_prog_ops;
195124701eceSDaniel Borkmann 	prog->type = type;
195209756af4SAlexei Starovoitov 	return 0;
195309756af4SAlexei Starovoitov }
195409756af4SAlexei Starovoitov 
1955bae141f5SDaniel Borkmann enum bpf_audit {
1956bae141f5SDaniel Borkmann 	BPF_AUDIT_LOAD,
1957bae141f5SDaniel Borkmann 	BPF_AUDIT_UNLOAD,
1958bae141f5SDaniel Borkmann 	BPF_AUDIT_MAX,
1959bae141f5SDaniel Borkmann };
1960bae141f5SDaniel Borkmann 
1961bae141f5SDaniel Borkmann static const char * const bpf_audit_str[BPF_AUDIT_MAX] = {
1962bae141f5SDaniel Borkmann 	[BPF_AUDIT_LOAD]   = "LOAD",
1963bae141f5SDaniel Borkmann 	[BPF_AUDIT_UNLOAD] = "UNLOAD",
1964bae141f5SDaniel Borkmann };
1965bae141f5SDaniel Borkmann 
1966bae141f5SDaniel Borkmann static void bpf_audit_prog(const struct bpf_prog *prog, unsigned int op)
1967bae141f5SDaniel Borkmann {
1968bae141f5SDaniel Borkmann 	struct audit_context *ctx = NULL;
1969bae141f5SDaniel Borkmann 	struct audit_buffer *ab;
1970bae141f5SDaniel Borkmann 
1971bae141f5SDaniel Borkmann 	if (WARN_ON_ONCE(op >= BPF_AUDIT_MAX))
1972bae141f5SDaniel Borkmann 		return;
1973bae141f5SDaniel Borkmann 	if (audit_enabled == AUDIT_OFF)
1974bae141f5SDaniel Borkmann 		return;
1975bae141f5SDaniel Borkmann 	if (op == BPF_AUDIT_LOAD)
1976bae141f5SDaniel Borkmann 		ctx = audit_context();
1977bae141f5SDaniel Borkmann 	ab = audit_log_start(ctx, GFP_ATOMIC, AUDIT_BPF);
1978bae141f5SDaniel Borkmann 	if (unlikely(!ab))
1979bae141f5SDaniel Borkmann 		return;
1980bae141f5SDaniel Borkmann 	audit_log_format(ab, "prog-id=%u op=%s",
1981bae141f5SDaniel Borkmann 			 prog->aux->id, bpf_audit_str[op]);
1982bae141f5SDaniel Borkmann 	audit_log_end(ab);
1983bae141f5SDaniel Borkmann }
1984bae141f5SDaniel Borkmann 
1985dc4bb0e2SMartin KaFai Lau static int bpf_prog_alloc_id(struct bpf_prog *prog)
1986dc4bb0e2SMartin KaFai Lau {
1987dc4bb0e2SMartin KaFai Lau 	int id;
1988dc4bb0e2SMartin KaFai Lau 
1989b76354cdSShaohua Li 	idr_preload(GFP_KERNEL);
1990dc4bb0e2SMartin KaFai Lau 	spin_lock_bh(&prog_idr_lock);
1991dc4bb0e2SMartin KaFai Lau 	id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC);
1992dc4bb0e2SMartin KaFai Lau 	if (id > 0)
1993dc4bb0e2SMartin KaFai Lau 		prog->aux->id = id;
1994dc4bb0e2SMartin KaFai Lau 	spin_unlock_bh(&prog_idr_lock);
1995b76354cdSShaohua Li 	idr_preload_end();
1996dc4bb0e2SMartin KaFai Lau 
1997dc4bb0e2SMartin KaFai Lau 	/* id is in [1, INT_MAX) */
1998dc4bb0e2SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
1999dc4bb0e2SMartin KaFai Lau 		return -ENOSPC;
2000dc4bb0e2SMartin KaFai Lau 
2001dc4bb0e2SMartin KaFai Lau 	return id > 0 ? 0 : id;
2002dc4bb0e2SMartin KaFai Lau }
2003dc4bb0e2SMartin KaFai Lau 
2004ad8ad79fSJakub Kicinski void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
2005dc4bb0e2SMartin KaFai Lau {
2006d809e134SAlexei Starovoitov 	unsigned long flags;
2007d809e134SAlexei Starovoitov 
2008ad8ad79fSJakub Kicinski 	/* cBPF to eBPF migrations are currently not in the idr store.
2009ad8ad79fSJakub Kicinski 	 * Offloaded programs are removed from the store when their device
2010ad8ad79fSJakub Kicinski 	 * disappears - even if someone grabs an fd to them they are unusable,
2011ad8ad79fSJakub Kicinski 	 * simply waiting for refcnt to drop to be freed.
2012ad8ad79fSJakub Kicinski 	 */
2013dc4bb0e2SMartin KaFai Lau 	if (!prog->aux->id)
2014dc4bb0e2SMartin KaFai Lau 		return;
2015dc4bb0e2SMartin KaFai Lau 
2016b16d9aa4SMartin KaFai Lau 	if (do_idr_lock)
2017d809e134SAlexei Starovoitov 		spin_lock_irqsave(&prog_idr_lock, flags);
2018b16d9aa4SMartin KaFai Lau 	else
2019b16d9aa4SMartin KaFai Lau 		__acquire(&prog_idr_lock);
2020b16d9aa4SMartin KaFai Lau 
2021dc4bb0e2SMartin KaFai Lau 	idr_remove(&prog_idr, prog->aux->id);
2022ad8ad79fSJakub Kicinski 	prog->aux->id = 0;
2023b16d9aa4SMartin KaFai Lau 
2024b16d9aa4SMartin KaFai Lau 	if (do_idr_lock)
2025d809e134SAlexei Starovoitov 		spin_unlock_irqrestore(&prog_idr_lock, flags);
2026b16d9aa4SMartin KaFai Lau 	else
2027b16d9aa4SMartin KaFai Lau 		__release(&prog_idr_lock);
2028dc4bb0e2SMartin KaFai Lau }
2029dc4bb0e2SMartin KaFai Lau 
20301aacde3dSDaniel Borkmann static void __bpf_prog_put_rcu(struct rcu_head *rcu)
2031abf2e7d6SAlexei Starovoitov {
2032abf2e7d6SAlexei Starovoitov 	struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
2033abf2e7d6SAlexei Starovoitov 
20343b4d9eb2SDaniel Borkmann 	kvfree(aux->func_info);
20358c1b6e69SAlexei Starovoitov 	kfree(aux->func_info_aux);
20363ac1f01bSRoman Gushchin 	free_uid(aux->user);
2037afdb09c7SChenbo Feng 	security_bpf_prog_free(aux);
2038abf2e7d6SAlexei Starovoitov 	bpf_prog_free(aux->prog);
2039abf2e7d6SAlexei Starovoitov }
2040abf2e7d6SAlexei Starovoitov 
2041cd7455f1SDaniel Borkmann static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
2042cd7455f1SDaniel Borkmann {
2043cd7455f1SDaniel Borkmann 	bpf_prog_kallsyms_del_all(prog);
2044cd7455f1SDaniel Borkmann 	btf_put(prog->aux->btf);
2045e16301fbSMartin KaFai Lau 	kvfree(prog->aux->jited_linfo);
2046e16301fbSMartin KaFai Lau 	kvfree(prog->aux->linfo);
2047e6ac2450SMartin KaFai Lau 	kfree(prog->aux->kfunc_tab);
204822dc4a0fSAndrii Nakryiko 	if (prog->aux->attach_btf)
204922dc4a0fSAndrii Nakryiko 		btf_put(prog->aux->attach_btf);
2050cd7455f1SDaniel Borkmann 
20511e6c62a8SAlexei Starovoitov 	if (deferred) {
20521e6c62a8SAlexei Starovoitov 		if (prog->aux->sleepable)
20531e6c62a8SAlexei Starovoitov 			call_rcu_tasks_trace(&prog->aux->rcu, __bpf_prog_put_rcu);
2054cd7455f1SDaniel Borkmann 		else
20551e6c62a8SAlexei Starovoitov 			call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
20561e6c62a8SAlexei Starovoitov 	} else {
2057cd7455f1SDaniel Borkmann 		__bpf_prog_put_rcu(&prog->aux->rcu);
2058cd7455f1SDaniel Borkmann 	}
20591e6c62a8SAlexei Starovoitov }
2060cd7455f1SDaniel Borkmann 
2061d809e134SAlexei Starovoitov static void bpf_prog_put_deferred(struct work_struct *work)
206209756af4SAlexei Starovoitov {
2063d809e134SAlexei Starovoitov 	struct bpf_prog_aux *aux;
2064d809e134SAlexei Starovoitov 	struct bpf_prog *prog;
2065d809e134SAlexei Starovoitov 
2066d809e134SAlexei Starovoitov 	aux = container_of(work, struct bpf_prog_aux, work);
2067d809e134SAlexei Starovoitov 	prog = aux->prog;
20686ee52e2aSSong Liu 	perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0);
2069bae141f5SDaniel Borkmann 	bpf_audit_prog(prog, BPF_AUDIT_UNLOAD);
2070d809e134SAlexei Starovoitov 	__bpf_prog_put_noref(prog, true);
2071d809e134SAlexei Starovoitov }
2072d809e134SAlexei Starovoitov 
2073d809e134SAlexei Starovoitov static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock)
2074d809e134SAlexei Starovoitov {
2075d809e134SAlexei Starovoitov 	struct bpf_prog_aux *aux = prog->aux;
2076d809e134SAlexei Starovoitov 
2077d809e134SAlexei Starovoitov 	if (atomic64_dec_and_test(&aux->refcnt)) {
207834ad5580SMartin KaFai Lau 		/* bpf_prog_free_id() must be called first */
2079b16d9aa4SMartin KaFai Lau 		bpf_prog_free_id(prog, do_idr_lock);
2080d809e134SAlexei Starovoitov 
2081d809e134SAlexei Starovoitov 		if (in_irq() || irqs_disabled()) {
2082d809e134SAlexei Starovoitov 			INIT_WORK(&aux->work, bpf_prog_put_deferred);
2083d809e134SAlexei Starovoitov 			schedule_work(&aux->work);
2084d809e134SAlexei Starovoitov 		} else {
2085d809e134SAlexei Starovoitov 			bpf_prog_put_deferred(&aux->work);
2086d809e134SAlexei Starovoitov 		}
208709756af4SAlexei Starovoitov 	}
2088a67edbf4SDaniel Borkmann }
2089b16d9aa4SMartin KaFai Lau 
2090b16d9aa4SMartin KaFai Lau void bpf_prog_put(struct bpf_prog *prog)
2091b16d9aa4SMartin KaFai Lau {
2092b16d9aa4SMartin KaFai Lau 	__bpf_prog_put(prog, true);
2093b16d9aa4SMartin KaFai Lau }
2094e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put);
209509756af4SAlexei Starovoitov 
209609756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp)
209709756af4SAlexei Starovoitov {
209809756af4SAlexei Starovoitov 	struct bpf_prog *prog = filp->private_data;
209909756af4SAlexei Starovoitov 
21001aacde3dSDaniel Borkmann 	bpf_prog_put(prog);
210109756af4SAlexei Starovoitov 	return 0;
210209756af4SAlexei Starovoitov }
210309756af4SAlexei Starovoitov 
210461a0abaeSEric Dumazet struct bpf_prog_kstats {
210561a0abaeSEric Dumazet 	u64 nsecs;
210661a0abaeSEric Dumazet 	u64 cnt;
210761a0abaeSEric Dumazet 	u64 misses;
210861a0abaeSEric Dumazet };
210961a0abaeSEric Dumazet 
211005b24ff9SJiri Olsa void notrace bpf_prog_inc_misses_counter(struct bpf_prog *prog)
211105b24ff9SJiri Olsa {
211205b24ff9SJiri Olsa 	struct bpf_prog_stats *stats;
211305b24ff9SJiri Olsa 	unsigned int flags;
211405b24ff9SJiri Olsa 
211505b24ff9SJiri Olsa 	stats = this_cpu_ptr(prog->stats);
211605b24ff9SJiri Olsa 	flags = u64_stats_update_begin_irqsave(&stats->syncp);
211705b24ff9SJiri Olsa 	u64_stats_inc(&stats->misses);
211805b24ff9SJiri Olsa 	u64_stats_update_end_irqrestore(&stats->syncp, flags);
211905b24ff9SJiri Olsa }
212005b24ff9SJiri Olsa 
2121492ecee8SAlexei Starovoitov static void bpf_prog_get_stats(const struct bpf_prog *prog,
212261a0abaeSEric Dumazet 			       struct bpf_prog_kstats *stats)
2123492ecee8SAlexei Starovoitov {
21249ed9e9baSAlexei Starovoitov 	u64 nsecs = 0, cnt = 0, misses = 0;
2125492ecee8SAlexei Starovoitov 	int cpu;
2126492ecee8SAlexei Starovoitov 
2127492ecee8SAlexei Starovoitov 	for_each_possible_cpu(cpu) {
2128492ecee8SAlexei Starovoitov 		const struct bpf_prog_stats *st;
2129492ecee8SAlexei Starovoitov 		unsigned int start;
21309ed9e9baSAlexei Starovoitov 		u64 tnsecs, tcnt, tmisses;
2131492ecee8SAlexei Starovoitov 
2132700d4796SAlexei Starovoitov 		st = per_cpu_ptr(prog->stats, cpu);
2133492ecee8SAlexei Starovoitov 		do {
213497c4090bSThomas Gleixner 			start = u64_stats_fetch_begin(&st->syncp);
213561a0abaeSEric Dumazet 			tnsecs = u64_stats_read(&st->nsecs);
213661a0abaeSEric Dumazet 			tcnt = u64_stats_read(&st->cnt);
213761a0abaeSEric Dumazet 			tmisses = u64_stats_read(&st->misses);
213897c4090bSThomas Gleixner 		} while (u64_stats_fetch_retry(&st->syncp, start));
2139492ecee8SAlexei Starovoitov 		nsecs += tnsecs;
2140492ecee8SAlexei Starovoitov 		cnt += tcnt;
21419ed9e9baSAlexei Starovoitov 		misses += tmisses;
2142492ecee8SAlexei Starovoitov 	}
2143492ecee8SAlexei Starovoitov 	stats->nsecs = nsecs;
2144492ecee8SAlexei Starovoitov 	stats->cnt = cnt;
21459ed9e9baSAlexei Starovoitov 	stats->misses = misses;
2146492ecee8SAlexei Starovoitov }
2147492ecee8SAlexei Starovoitov 
21487bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
21497bd509e3SDaniel Borkmann static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp)
21507bd509e3SDaniel Borkmann {
21517bd509e3SDaniel Borkmann 	const struct bpf_prog *prog = filp->private_data;
2152f1f7714eSDaniel Borkmann 	char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
215361a0abaeSEric Dumazet 	struct bpf_prog_kstats stats;
21547bd509e3SDaniel Borkmann 
2155492ecee8SAlexei Starovoitov 	bpf_prog_get_stats(prog, &stats);
2156f1f7714eSDaniel Borkmann 	bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
21577bd509e3SDaniel Borkmann 	seq_printf(m,
21587bd509e3SDaniel Borkmann 		   "prog_type:\t%u\n"
21597bd509e3SDaniel Borkmann 		   "prog_jited:\t%u\n"
2160f1f7714eSDaniel Borkmann 		   "prog_tag:\t%s\n"
21614316b409SDaniel Borkmann 		   "memlock:\t%llu\n"
2162492ecee8SAlexei Starovoitov 		   "prog_id:\t%u\n"
2163492ecee8SAlexei Starovoitov 		   "run_time_ns:\t%llu\n"
21649ed9e9baSAlexei Starovoitov 		   "run_cnt:\t%llu\n"
2165aba64c7dSDave Marchevsky 		   "recursion_misses:\t%llu\n"
2166aba64c7dSDave Marchevsky 		   "verified_insns:\t%u\n",
21677bd509e3SDaniel Borkmann 		   prog->type,
21687bd509e3SDaniel Borkmann 		   prog->jited,
2169f1f7714eSDaniel Borkmann 		   prog_tag,
21704316b409SDaniel Borkmann 		   prog->pages * 1ULL << PAGE_SHIFT,
2171492ecee8SAlexei Starovoitov 		   prog->aux->id,
2172492ecee8SAlexei Starovoitov 		   stats.nsecs,
21739ed9e9baSAlexei Starovoitov 		   stats.cnt,
2174aba64c7dSDave Marchevsky 		   stats.misses,
2175aba64c7dSDave Marchevsky 		   prog->aux->verified_insns);
21767bd509e3SDaniel Borkmann }
21777bd509e3SDaniel Borkmann #endif
21787bd509e3SDaniel Borkmann 
2179f66e448cSChenbo Feng const struct file_operations bpf_prog_fops = {
21807bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
21817bd509e3SDaniel Borkmann 	.show_fdinfo	= bpf_prog_show_fdinfo,
21827bd509e3SDaniel Borkmann #endif
218309756af4SAlexei Starovoitov 	.release	= bpf_prog_release,
21846e71b04aSChenbo Feng 	.read		= bpf_dummy_read,
21856e71b04aSChenbo Feng 	.write		= bpf_dummy_write,
218609756af4SAlexei Starovoitov };
218709756af4SAlexei Starovoitov 
2188b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog)
2189aa79781bSDaniel Borkmann {
2190afdb09c7SChenbo Feng 	int ret;
2191afdb09c7SChenbo Feng 
2192afdb09c7SChenbo Feng 	ret = security_bpf_prog(prog);
2193afdb09c7SChenbo Feng 	if (ret < 0)
2194afdb09c7SChenbo Feng 		return ret;
2195afdb09c7SChenbo Feng 
2196aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog,
2197aa79781bSDaniel Borkmann 				O_RDWR | O_CLOEXEC);
2198aa79781bSDaniel Borkmann }
2199aa79781bSDaniel Borkmann 
2200113214beSDaniel Borkmann static struct bpf_prog *____bpf_prog_get(struct fd f)
220109756af4SAlexei Starovoitov {
220209756af4SAlexei Starovoitov 	if (!f.file)
220309756af4SAlexei Starovoitov 		return ERR_PTR(-EBADF);
220409756af4SAlexei Starovoitov 	if (f.file->f_op != &bpf_prog_fops) {
220509756af4SAlexei Starovoitov 		fdput(f);
220609756af4SAlexei Starovoitov 		return ERR_PTR(-EINVAL);
220709756af4SAlexei Starovoitov 	}
220809756af4SAlexei Starovoitov 
2209c2101297SDaniel Borkmann 	return f.file->private_data;
221009756af4SAlexei Starovoitov }
221109756af4SAlexei Starovoitov 
221285192dbfSAndrii Nakryiko void bpf_prog_add(struct bpf_prog *prog, int i)
221392117d84SAlexei Starovoitov {
221485192dbfSAndrii Nakryiko 	atomic64_add(i, &prog->aux->refcnt);
221592117d84SAlexei Starovoitov }
221659d3656dSBrenden Blanco EXPORT_SYMBOL_GPL(bpf_prog_add);
221759d3656dSBrenden Blanco 
2218c540594fSDaniel Borkmann void bpf_prog_sub(struct bpf_prog *prog, int i)
2219c540594fSDaniel Borkmann {
2220c540594fSDaniel Borkmann 	/* Only to be used for undoing previous bpf_prog_add() in some
2221c540594fSDaniel Borkmann 	 * error path. We still know that another entity in our call
2222c540594fSDaniel Borkmann 	 * path holds a reference to the program, thus atomic_sub() can
2223c540594fSDaniel Borkmann 	 * be safely used in such cases!
2224c540594fSDaniel Borkmann 	 */
222585192dbfSAndrii Nakryiko 	WARN_ON(atomic64_sub_return(i, &prog->aux->refcnt) == 0);
2226c540594fSDaniel Borkmann }
2227c540594fSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_sub);
2228c540594fSDaniel Borkmann 
222985192dbfSAndrii Nakryiko void bpf_prog_inc(struct bpf_prog *prog)
223059d3656dSBrenden Blanco {
223185192dbfSAndrii Nakryiko 	atomic64_inc(&prog->aux->refcnt);
223259d3656dSBrenden Blanco }
223397bc402dSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_inc);
223492117d84SAlexei Starovoitov 
2235b16d9aa4SMartin KaFai Lau /* prog_idr_lock should have been held */
2236a6f6df69SJohn Fastabend struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog)
2237b16d9aa4SMartin KaFai Lau {
2238b16d9aa4SMartin KaFai Lau 	int refold;
2239b16d9aa4SMartin KaFai Lau 
224085192dbfSAndrii Nakryiko 	refold = atomic64_fetch_add_unless(&prog->aux->refcnt, 1, 0);
2241b16d9aa4SMartin KaFai Lau 
2242b16d9aa4SMartin KaFai Lau 	if (!refold)
2243b16d9aa4SMartin KaFai Lau 		return ERR_PTR(-ENOENT);
2244b16d9aa4SMartin KaFai Lau 
2245b16d9aa4SMartin KaFai Lau 	return prog;
2246b16d9aa4SMartin KaFai Lau }
2247a6f6df69SJohn Fastabend EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero);
2248b16d9aa4SMartin KaFai Lau 
2249040ee692SAl Viro bool bpf_prog_get_ok(struct bpf_prog *prog,
2250288b3de5SJakub Kicinski 			    enum bpf_prog_type *attach_type, bool attach_drv)
2251248f346fSJakub Kicinski {
2252288b3de5SJakub Kicinski 	/* not an attachment, just a refcount inc, always allow */
2253288b3de5SJakub Kicinski 	if (!attach_type)
2254288b3de5SJakub Kicinski 		return true;
2255248f346fSJakub Kicinski 
2256248f346fSJakub Kicinski 	if (prog->type != *attach_type)
2257248f346fSJakub Kicinski 		return false;
2258288b3de5SJakub Kicinski 	if (bpf_prog_is_dev_bound(prog->aux) && !attach_drv)
2259248f346fSJakub Kicinski 		return false;
2260248f346fSJakub Kicinski 
2261248f346fSJakub Kicinski 	return true;
2262248f346fSJakub Kicinski }
2263248f346fSJakub Kicinski 
2264248f346fSJakub Kicinski static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type,
2265288b3de5SJakub Kicinski 				       bool attach_drv)
226609756af4SAlexei Starovoitov {
226709756af4SAlexei Starovoitov 	struct fd f = fdget(ufd);
226809756af4SAlexei Starovoitov 	struct bpf_prog *prog;
226909756af4SAlexei Starovoitov 
2270113214beSDaniel Borkmann 	prog = ____bpf_prog_get(f);
227109756af4SAlexei Starovoitov 	if (IS_ERR(prog))
227209756af4SAlexei Starovoitov 		return prog;
2273288b3de5SJakub Kicinski 	if (!bpf_prog_get_ok(prog, attach_type, attach_drv)) {
2274113214beSDaniel Borkmann 		prog = ERR_PTR(-EINVAL);
2275113214beSDaniel Borkmann 		goto out;
2276113214beSDaniel Borkmann 	}
227709756af4SAlexei Starovoitov 
227885192dbfSAndrii Nakryiko 	bpf_prog_inc(prog);
2279113214beSDaniel Borkmann out:
228009756af4SAlexei Starovoitov 	fdput(f);
228109756af4SAlexei Starovoitov 	return prog;
228209756af4SAlexei Starovoitov }
2283113214beSDaniel Borkmann 
2284113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get(u32 ufd)
2285113214beSDaniel Borkmann {
2286288b3de5SJakub Kicinski 	return __bpf_prog_get(ufd, NULL, false);
2287113214beSDaniel Borkmann }
2288113214beSDaniel Borkmann 
2289248f346fSJakub Kicinski struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type,
2290288b3de5SJakub Kicinski 				       bool attach_drv)
2291248f346fSJakub Kicinski {
22924d220ed0SAlexei Starovoitov 	return __bpf_prog_get(ufd, &type, attach_drv);
2293248f346fSJakub Kicinski }
22946c8dfe21SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_prog_get_type_dev);
2295248f346fSJakub Kicinski 
2296aac3fc32SAndrey Ignatov /* Initially all BPF programs could be loaded w/o specifying
2297aac3fc32SAndrey Ignatov  * expected_attach_type. Later for some of them specifying expected_attach_type
2298aac3fc32SAndrey Ignatov  * at load time became required so that program could be validated properly.
2299aac3fc32SAndrey Ignatov  * Programs of types that are allowed to be loaded both w/ and w/o (for
2300aac3fc32SAndrey Ignatov  * backward compatibility) expected_attach_type, should have the default attach
2301aac3fc32SAndrey Ignatov  * type assigned to expected_attach_type for the latter case, so that it can be
2302aac3fc32SAndrey Ignatov  * validated later at attach time.
2303aac3fc32SAndrey Ignatov  *
2304aac3fc32SAndrey Ignatov  * bpf_prog_load_fixup_attach_type() sets expected_attach_type in @attr if
2305aac3fc32SAndrey Ignatov  * prog type requires it but has some attach types that have to be backward
2306aac3fc32SAndrey Ignatov  * compatible.
2307aac3fc32SAndrey Ignatov  */
2308aac3fc32SAndrey Ignatov static void bpf_prog_load_fixup_attach_type(union bpf_attr *attr)
2309aac3fc32SAndrey Ignatov {
2310aac3fc32SAndrey Ignatov 	switch (attr->prog_type) {
2311aac3fc32SAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK:
2312aac3fc32SAndrey Ignatov 		/* Unfortunately BPF_ATTACH_TYPE_UNSPEC enumeration doesn't
2313aac3fc32SAndrey Ignatov 		 * exist so checking for non-zero is the way to go here.
2314aac3fc32SAndrey Ignatov 		 */
2315aac3fc32SAndrey Ignatov 		if (!attr->expected_attach_type)
2316aac3fc32SAndrey Ignatov 			attr->expected_attach_type =
2317aac3fc32SAndrey Ignatov 				BPF_CGROUP_INET_SOCK_CREATE;
2318aac3fc32SAndrey Ignatov 		break;
2319d5e4ddaeSKuniyuki Iwashima 	case BPF_PROG_TYPE_SK_REUSEPORT:
2320d5e4ddaeSKuniyuki Iwashima 		if (!attr->expected_attach_type)
2321d5e4ddaeSKuniyuki Iwashima 			attr->expected_attach_type =
2322d5e4ddaeSKuniyuki Iwashima 				BPF_SK_REUSEPORT_SELECT;
2323d5e4ddaeSKuniyuki Iwashima 		break;
2324aac3fc32SAndrey Ignatov 	}
2325aac3fc32SAndrey Ignatov }
2326aac3fc32SAndrey Ignatov 
23275e43f899SAndrey Ignatov static int
2328ccfe29ebSAlexei Starovoitov bpf_prog_load_check_attach(enum bpf_prog_type prog_type,
2329ccfe29ebSAlexei Starovoitov 			   enum bpf_attach_type expected_attach_type,
2330290248a5SAndrii Nakryiko 			   struct btf *attach_btf, u32 btf_id,
2331290248a5SAndrii Nakryiko 			   struct bpf_prog *dst_prog)
23325e43f899SAndrey Ignatov {
233327ae7997SMartin KaFai Lau 	if (btf_id) {
2334c108e3c1SAlexei Starovoitov 		if (btf_id > BTF_MAX_TYPE)
2335c108e3c1SAlexei Starovoitov 			return -EINVAL;
233627ae7997SMartin KaFai Lau 
2337290248a5SAndrii Nakryiko 		if (!attach_btf && !dst_prog)
2338290248a5SAndrii Nakryiko 			return -EINVAL;
2339290248a5SAndrii Nakryiko 
234027ae7997SMartin KaFai Lau 		switch (prog_type) {
234127ae7997SMartin KaFai Lau 		case BPF_PROG_TYPE_TRACING:
23429e4e01dfSKP Singh 		case BPF_PROG_TYPE_LSM:
234327ae7997SMartin KaFai Lau 		case BPF_PROG_TYPE_STRUCT_OPS:
2344be8704ffSAlexei Starovoitov 		case BPF_PROG_TYPE_EXT:
2345c108e3c1SAlexei Starovoitov 			break;
2346c108e3c1SAlexei Starovoitov 		default:
2347c108e3c1SAlexei Starovoitov 			return -EINVAL;
2348c108e3c1SAlexei Starovoitov 		}
234927ae7997SMartin KaFai Lau 	}
235027ae7997SMartin KaFai Lau 
2351290248a5SAndrii Nakryiko 	if (attach_btf && (!btf_id || dst_prog))
2352290248a5SAndrii Nakryiko 		return -EINVAL;
2353290248a5SAndrii Nakryiko 
2354290248a5SAndrii Nakryiko 	if (dst_prog && prog_type != BPF_PROG_TYPE_TRACING &&
2355be8704ffSAlexei Starovoitov 	    prog_type != BPF_PROG_TYPE_EXT)
235627ae7997SMartin KaFai Lau 		return -EINVAL;
2357c108e3c1SAlexei Starovoitov 
2358c108e3c1SAlexei Starovoitov 	switch (prog_type) {
2359aac3fc32SAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK:
2360aac3fc32SAndrey Ignatov 		switch (expected_attach_type) {
2361aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET_SOCK_CREATE:
2362f5836749SStanislav Fomichev 		case BPF_CGROUP_INET_SOCK_RELEASE:
2363aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET4_POST_BIND:
2364aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET6_POST_BIND:
2365aac3fc32SAndrey Ignatov 			return 0;
2366aac3fc32SAndrey Ignatov 		default:
2367aac3fc32SAndrey Ignatov 			return -EINVAL;
2368aac3fc32SAndrey Ignatov 		}
23694fbac77dSAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
23704fbac77dSAndrey Ignatov 		switch (expected_attach_type) {
23714fbac77dSAndrey Ignatov 		case BPF_CGROUP_INET4_BIND:
23724fbac77dSAndrey Ignatov 		case BPF_CGROUP_INET6_BIND:
2373d74bad4eSAndrey Ignatov 		case BPF_CGROUP_INET4_CONNECT:
2374d74bad4eSAndrey Ignatov 		case BPF_CGROUP_INET6_CONNECT:
23751b66d253SDaniel Borkmann 		case BPF_CGROUP_INET4_GETPEERNAME:
23761b66d253SDaniel Borkmann 		case BPF_CGROUP_INET6_GETPEERNAME:
23771b66d253SDaniel Borkmann 		case BPF_CGROUP_INET4_GETSOCKNAME:
23781b66d253SDaniel Borkmann 		case BPF_CGROUP_INET6_GETSOCKNAME:
23791cedee13SAndrey Ignatov 		case BPF_CGROUP_UDP4_SENDMSG:
23801cedee13SAndrey Ignatov 		case BPF_CGROUP_UDP6_SENDMSG:
2381983695faSDaniel Borkmann 		case BPF_CGROUP_UDP4_RECVMSG:
2382983695faSDaniel Borkmann 		case BPF_CGROUP_UDP6_RECVMSG:
23835e43f899SAndrey Ignatov 			return 0;
23844fbac77dSAndrey Ignatov 		default:
23854fbac77dSAndrey Ignatov 			return -EINVAL;
23864fbac77dSAndrey Ignatov 		}
23875cf1e914Sbrakmo 	case BPF_PROG_TYPE_CGROUP_SKB:
23885cf1e914Sbrakmo 		switch (expected_attach_type) {
23895cf1e914Sbrakmo 		case BPF_CGROUP_INET_INGRESS:
23905cf1e914Sbrakmo 		case BPF_CGROUP_INET_EGRESS:
23915cf1e914Sbrakmo 			return 0;
23925cf1e914Sbrakmo 		default:
23935cf1e914Sbrakmo 			return -EINVAL;
23945cf1e914Sbrakmo 		}
23950d01da6aSStanislav Fomichev 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
23960d01da6aSStanislav Fomichev 		switch (expected_attach_type) {
23970d01da6aSStanislav Fomichev 		case BPF_CGROUP_SETSOCKOPT:
23980d01da6aSStanislav Fomichev 		case BPF_CGROUP_GETSOCKOPT:
23990d01da6aSStanislav Fomichev 			return 0;
24000d01da6aSStanislav Fomichev 		default:
24010d01da6aSStanislav Fomichev 			return -EINVAL;
24020d01da6aSStanislav Fomichev 		}
2403e9ddbb77SJakub Sitnicki 	case BPF_PROG_TYPE_SK_LOOKUP:
2404e9ddbb77SJakub Sitnicki 		if (expected_attach_type == BPF_SK_LOOKUP)
2405e9ddbb77SJakub Sitnicki 			return 0;
2406e9ddbb77SJakub Sitnicki 		return -EINVAL;
2407d5e4ddaeSKuniyuki Iwashima 	case BPF_PROG_TYPE_SK_REUSEPORT:
2408d5e4ddaeSKuniyuki Iwashima 		switch (expected_attach_type) {
2409d5e4ddaeSKuniyuki Iwashima 		case BPF_SK_REUSEPORT_SELECT:
2410d5e4ddaeSKuniyuki Iwashima 		case BPF_SK_REUSEPORT_SELECT_OR_MIGRATE:
2411d5e4ddaeSKuniyuki Iwashima 			return 0;
2412d5e4ddaeSKuniyuki Iwashima 		default:
2413d5e4ddaeSKuniyuki Iwashima 			return -EINVAL;
2414d5e4ddaeSKuniyuki Iwashima 		}
241579a7f8bdSAlexei Starovoitov 	case BPF_PROG_TYPE_SYSCALL:
2416be8704ffSAlexei Starovoitov 	case BPF_PROG_TYPE_EXT:
2417be8704ffSAlexei Starovoitov 		if (expected_attach_type)
2418be8704ffSAlexei Starovoitov 			return -EINVAL;
2419df561f66SGustavo A. R. Silva 		fallthrough;
24204fbac77dSAndrey Ignatov 	default:
24214fbac77dSAndrey Ignatov 		return 0;
24224fbac77dSAndrey Ignatov 	}
24235e43f899SAndrey Ignatov }
24245e43f899SAndrey Ignatov 
24252c78ee89SAlexei Starovoitov static bool is_net_admin_prog_type(enum bpf_prog_type prog_type)
24262c78ee89SAlexei Starovoitov {
24272c78ee89SAlexei Starovoitov 	switch (prog_type) {
24282c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SCHED_CLS:
24292c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SCHED_ACT:
24302c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_XDP:
24312c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_IN:
24322c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_OUT:
24332c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_XMIT:
24342c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_SEG6LOCAL:
24352c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SK_SKB:
24362c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SK_MSG:
24372c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LIRC_MODE2:
24382c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
24392c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_DEVICE:
24402c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SOCK:
24412c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
24422c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
24432c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
24442c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SOCK_OPS:
24452c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_EXT: /* extends any prog */
24462c78ee89SAlexei Starovoitov 		return true;
24472c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SKB:
24482c78ee89SAlexei Starovoitov 		/* always unpriv */
24492c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SK_REUSEPORT:
24502c78ee89SAlexei Starovoitov 		/* equivalent to SOCKET_FILTER. need CAP_BPF only */
24512c78ee89SAlexei Starovoitov 	default:
24522c78ee89SAlexei Starovoitov 		return false;
24532c78ee89SAlexei Starovoitov 	}
24542c78ee89SAlexei Starovoitov }
24552c78ee89SAlexei Starovoitov 
24562c78ee89SAlexei Starovoitov static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
24572c78ee89SAlexei Starovoitov {
24582c78ee89SAlexei Starovoitov 	switch (prog_type) {
24592c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_KPROBE:
24602c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_TRACEPOINT:
24612c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_PERF_EVENT:
24622c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_RAW_TRACEPOINT:
24632c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
24642c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_TRACING:
24652c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LSM:
24662c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_STRUCT_OPS: /* has access to struct sock */
24672c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_EXT: /* extends any prog */
24682c78ee89SAlexei Starovoitov 		return true;
24692c78ee89SAlexei Starovoitov 	default:
24702c78ee89SAlexei Starovoitov 		return false;
24712c78ee89SAlexei Starovoitov 	}
24722c78ee89SAlexei Starovoitov }
24732c78ee89SAlexei Starovoitov 
247409756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
2475fbd94c7aSAlexei Starovoitov #define	BPF_PROG_LOAD_LAST_FIELD core_relo_rec_size
247609756af4SAlexei Starovoitov 
2477af2ac3e1SAlexei Starovoitov static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr)
247809756af4SAlexei Starovoitov {
247909756af4SAlexei Starovoitov 	enum bpf_prog_type type = attr->prog_type;
2480290248a5SAndrii Nakryiko 	struct bpf_prog *prog, *dst_prog = NULL;
2481290248a5SAndrii Nakryiko 	struct btf *attach_btf = NULL;
248209756af4SAlexei Starovoitov 	int err;
248309756af4SAlexei Starovoitov 	char license[128];
248409756af4SAlexei Starovoitov 	bool is_gpl;
248509756af4SAlexei Starovoitov 
248609756af4SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_LOAD))
248709756af4SAlexei Starovoitov 		return -EINVAL;
248809756af4SAlexei Starovoitov 
2489c240eff6SJiong Wang 	if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT |
2490c240eff6SJiong Wang 				 BPF_F_ANY_ALIGNMENT |
249110d274e8SAlexei Starovoitov 				 BPF_F_TEST_STATE_FREQ |
24921e6c62a8SAlexei Starovoitov 				 BPF_F_SLEEPABLE |
2493c2f2cdbeSLorenzo Bianconi 				 BPF_F_TEST_RND_HI32 |
2494c2f2cdbeSLorenzo Bianconi 				 BPF_F_XDP_HAS_FRAGS))
2495e07b98d9SDavid S. Miller 		return -EINVAL;
2496e07b98d9SDavid S. Miller 
2497e9ee9efcSDavid Miller 	if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
2498e9ee9efcSDavid Miller 	    (attr->prog_flags & BPF_F_ANY_ALIGNMENT) &&
24992c78ee89SAlexei Starovoitov 	    !bpf_capable())
2500e9ee9efcSDavid Miller 		return -EPERM;
2501e9ee9efcSDavid Miller 
250209756af4SAlexei Starovoitov 	/* copy eBPF program license from user space */
2503af2ac3e1SAlexei Starovoitov 	if (strncpy_from_bpfptr(license,
2504af2ac3e1SAlexei Starovoitov 				make_bpfptr(attr->license, uattr.is_kernel),
250509756af4SAlexei Starovoitov 				sizeof(license) - 1) < 0)
250609756af4SAlexei Starovoitov 		return -EFAULT;
250709756af4SAlexei Starovoitov 	license[sizeof(license) - 1] = 0;
250809756af4SAlexei Starovoitov 
250909756af4SAlexei Starovoitov 	/* eBPF programs must be GPL compatible to use GPL-ed functions */
251009756af4SAlexei Starovoitov 	is_gpl = license_is_gpl_compatible(license);
251109756af4SAlexei Starovoitov 
2512c04c0d2bSAlexei Starovoitov 	if (attr->insn_cnt == 0 ||
25132c78ee89SAlexei Starovoitov 	    attr->insn_cnt > (bpf_capable() ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS))
2514ef0915caSDaniel Borkmann 		return -E2BIG;
251580b7d819SChenbo Feng 	if (type != BPF_PROG_TYPE_SOCKET_FILTER &&
251680b7d819SChenbo Feng 	    type != BPF_PROG_TYPE_CGROUP_SKB &&
25172c78ee89SAlexei Starovoitov 	    !bpf_capable())
25182c78ee89SAlexei Starovoitov 		return -EPERM;
25192c78ee89SAlexei Starovoitov 
2520b338cb92SMaciej Żenczykowski 	if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN) && !capable(CAP_SYS_ADMIN))
25212c78ee89SAlexei Starovoitov 		return -EPERM;
25222c78ee89SAlexei Starovoitov 	if (is_perfmon_prog_type(type) && !perfmon_capable())
25231be7f75dSAlexei Starovoitov 		return -EPERM;
25241be7f75dSAlexei Starovoitov 
2525290248a5SAndrii Nakryiko 	/* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog
2526290248a5SAndrii Nakryiko 	 * or btf, we need to check which one it is
2527290248a5SAndrii Nakryiko 	 */
2528290248a5SAndrii Nakryiko 	if (attr->attach_prog_fd) {
2529290248a5SAndrii Nakryiko 		dst_prog = bpf_prog_get(attr->attach_prog_fd);
2530290248a5SAndrii Nakryiko 		if (IS_ERR(dst_prog)) {
2531290248a5SAndrii Nakryiko 			dst_prog = NULL;
2532290248a5SAndrii Nakryiko 			attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd);
2533290248a5SAndrii Nakryiko 			if (IS_ERR(attach_btf))
2534290248a5SAndrii Nakryiko 				return -EINVAL;
2535290248a5SAndrii Nakryiko 			if (!btf_is_kernel(attach_btf)) {
25368bdd8e27SAndrii Nakryiko 				/* attaching through specifying bpf_prog's BTF
25378bdd8e27SAndrii Nakryiko 				 * objects directly might be supported eventually
25388bdd8e27SAndrii Nakryiko 				 */
2539290248a5SAndrii Nakryiko 				btf_put(attach_btf);
25408bdd8e27SAndrii Nakryiko 				return -ENOTSUPP;
2541290248a5SAndrii Nakryiko 			}
2542290248a5SAndrii Nakryiko 		}
2543290248a5SAndrii Nakryiko 	} else if (attr->attach_btf_id) {
2544290248a5SAndrii Nakryiko 		/* fall back to vmlinux BTF, if BTF type ID is specified */
2545290248a5SAndrii Nakryiko 		attach_btf = bpf_get_btf_vmlinux();
2546290248a5SAndrii Nakryiko 		if (IS_ERR(attach_btf))
2547290248a5SAndrii Nakryiko 			return PTR_ERR(attach_btf);
2548290248a5SAndrii Nakryiko 		if (!attach_btf)
2549290248a5SAndrii Nakryiko 			return -EINVAL;
2550290248a5SAndrii Nakryiko 		btf_get(attach_btf);
2551290248a5SAndrii Nakryiko 	}
2552290248a5SAndrii Nakryiko 
2553aac3fc32SAndrey Ignatov 	bpf_prog_load_fixup_attach_type(attr);
2554ccfe29ebSAlexei Starovoitov 	if (bpf_prog_load_check_attach(type, attr->expected_attach_type,
2555290248a5SAndrii Nakryiko 				       attach_btf, attr->attach_btf_id,
2556290248a5SAndrii Nakryiko 				       dst_prog)) {
2557290248a5SAndrii Nakryiko 		if (dst_prog)
2558290248a5SAndrii Nakryiko 			bpf_prog_put(dst_prog);
2559290248a5SAndrii Nakryiko 		if (attach_btf)
2560290248a5SAndrii Nakryiko 			btf_put(attach_btf);
25615e43f899SAndrey Ignatov 		return -EINVAL;
2562290248a5SAndrii Nakryiko 	}
25635e43f899SAndrey Ignatov 
256409756af4SAlexei Starovoitov 	/* plain bpf_prog allocation */
256509756af4SAlexei Starovoitov 	prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
2566290248a5SAndrii Nakryiko 	if (!prog) {
2567290248a5SAndrii Nakryiko 		if (dst_prog)
2568290248a5SAndrii Nakryiko 			bpf_prog_put(dst_prog);
2569290248a5SAndrii Nakryiko 		if (attach_btf)
2570290248a5SAndrii Nakryiko 			btf_put(attach_btf);
257109756af4SAlexei Starovoitov 		return -ENOMEM;
2572290248a5SAndrii Nakryiko 	}
257309756af4SAlexei Starovoitov 
25745e43f899SAndrey Ignatov 	prog->expected_attach_type = attr->expected_attach_type;
2575290248a5SAndrii Nakryiko 	prog->aux->attach_btf = attach_btf;
2576ccfe29ebSAlexei Starovoitov 	prog->aux->attach_btf_id = attr->attach_btf_id;
25773aac1eadSToke Høiland-Jørgensen 	prog->aux->dst_prog = dst_prog;
25789a18eedbSJakub Kicinski 	prog->aux->offload_requested = !!attr->prog_ifindex;
25791e6c62a8SAlexei Starovoitov 	prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE;
2580c2f2cdbeSLorenzo Bianconi 	prog->aux->xdp_has_frags = attr->prog_flags & BPF_F_XDP_HAS_FRAGS;
25819a18eedbSJakub Kicinski 
2582afdb09c7SChenbo Feng 	err = security_bpf_prog_alloc(prog->aux);
2583aaac3ba9SAlexei Starovoitov 	if (err)
25843ac1f01bSRoman Gushchin 		goto free_prog;
2585aaac3ba9SAlexei Starovoitov 
25863ac1f01bSRoman Gushchin 	prog->aux->user = get_current_user();
258709756af4SAlexei Starovoitov 	prog->len = attr->insn_cnt;
258809756af4SAlexei Starovoitov 
258909756af4SAlexei Starovoitov 	err = -EFAULT;
2590af2ac3e1SAlexei Starovoitov 	if (copy_from_bpfptr(prog->insns,
2591af2ac3e1SAlexei Starovoitov 			     make_bpfptr(attr->insns, uattr.is_kernel),
2592aafe6ae9SDaniel Borkmann 			     bpf_prog_insn_size(prog)) != 0)
25933ac1f01bSRoman Gushchin 		goto free_prog_sec;
259409756af4SAlexei Starovoitov 
259509756af4SAlexei Starovoitov 	prog->orig_prog = NULL;
2596a91263d5SDaniel Borkmann 	prog->jited = 0;
259709756af4SAlexei Starovoitov 
259885192dbfSAndrii Nakryiko 	atomic64_set(&prog->aux->refcnt, 1);
2599a91263d5SDaniel Borkmann 	prog->gpl_compatible = is_gpl ? 1 : 0;
260009756af4SAlexei Starovoitov 
26019a18eedbSJakub Kicinski 	if (bpf_prog_is_dev_bound(prog->aux)) {
2602ab3f0063SJakub Kicinski 		err = bpf_prog_offload_init(prog, attr);
2603ab3f0063SJakub Kicinski 		if (err)
26043ac1f01bSRoman Gushchin 			goto free_prog_sec;
2605ab3f0063SJakub Kicinski 	}
2606ab3f0063SJakub Kicinski 
260709756af4SAlexei Starovoitov 	/* find program type: socket_filter vs tracing_filter */
260809756af4SAlexei Starovoitov 	err = find_prog_type(type, prog);
260909756af4SAlexei Starovoitov 	if (err < 0)
26103ac1f01bSRoman Gushchin 		goto free_prog_sec;
261109756af4SAlexei Starovoitov 
26129285ec4cSJason A. Donenfeld 	prog->aux->load_time = ktime_get_boottime_ns();
26138e7ae251SMartin KaFai Lau 	err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name,
26148e7ae251SMartin KaFai Lau 			       sizeof(attr->prog_name));
26158e7ae251SMartin KaFai Lau 	if (err < 0)
26163ac1f01bSRoman Gushchin 		goto free_prog_sec;
2617cb4d2b3fSMartin KaFai Lau 
261809756af4SAlexei Starovoitov 	/* run eBPF verifier */
2619838e9690SYonghong Song 	err = bpf_check(&prog, attr, uattr);
262009756af4SAlexei Starovoitov 	if (err < 0)
262109756af4SAlexei Starovoitov 		goto free_used_maps;
262209756af4SAlexei Starovoitov 
2623d1c55ab5SDaniel Borkmann 	prog = bpf_prog_select_runtime(prog, &err);
262404fd61abSAlexei Starovoitov 	if (err < 0)
262504fd61abSAlexei Starovoitov 		goto free_used_maps;
262609756af4SAlexei Starovoitov 
2627dc4bb0e2SMartin KaFai Lau 	err = bpf_prog_alloc_id(prog);
2628dc4bb0e2SMartin KaFai Lau 	if (err)
2629dc4bb0e2SMartin KaFai Lau 		goto free_used_maps;
2630dc4bb0e2SMartin KaFai Lau 
2631c751798aSDaniel Borkmann 	/* Upon success of bpf_prog_alloc_id(), the BPF prog is
2632c751798aSDaniel Borkmann 	 * effectively publicly exposed. However, retrieving via
2633c751798aSDaniel Borkmann 	 * bpf_prog_get_fd_by_id() will take another reference,
2634c751798aSDaniel Borkmann 	 * therefore it cannot be gone underneath us.
2635c751798aSDaniel Borkmann 	 *
2636c751798aSDaniel Borkmann 	 * Only for the time /after/ successful bpf_prog_new_fd()
2637c751798aSDaniel Borkmann 	 * and before returning to userspace, we might just hold
2638c751798aSDaniel Borkmann 	 * one reference and any parallel close on that fd could
2639c751798aSDaniel Borkmann 	 * rip everything out. Hence, below notifications must
2640c751798aSDaniel Borkmann 	 * happen before bpf_prog_new_fd().
2641c751798aSDaniel Borkmann 	 *
2642c751798aSDaniel Borkmann 	 * Also, any failure handling from this point onwards must
2643c751798aSDaniel Borkmann 	 * be using bpf_prog_put() given the program is exposed.
2644b16d9aa4SMartin KaFai Lau 	 */
264574451e66SDaniel Borkmann 	bpf_prog_kallsyms_add(prog);
26466ee52e2aSSong Liu 	perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0);
2647bae141f5SDaniel Borkmann 	bpf_audit_prog(prog, BPF_AUDIT_LOAD);
2648c751798aSDaniel Borkmann 
2649c751798aSDaniel Borkmann 	err = bpf_prog_new_fd(prog);
2650c751798aSDaniel Borkmann 	if (err < 0)
2651c751798aSDaniel Borkmann 		bpf_prog_put(prog);
265209756af4SAlexei Starovoitov 	return err;
265309756af4SAlexei Starovoitov 
265409756af4SAlexei Starovoitov free_used_maps:
2655cd7455f1SDaniel Borkmann 	/* In case we have subprogs, we need to wait for a grace
2656cd7455f1SDaniel Borkmann 	 * period before we can tear down JIT memory since symbols
2657cd7455f1SDaniel Borkmann 	 * are already exposed under kallsyms.
2658cd7455f1SDaniel Borkmann 	 */
2659cd7455f1SDaniel Borkmann 	__bpf_prog_put_noref(prog, prog->aux->func_cnt);
2660cd7455f1SDaniel Borkmann 	return err;
2661afdb09c7SChenbo Feng free_prog_sec:
26623ac1f01bSRoman Gushchin 	free_uid(prog->aux->user);
2663afdb09c7SChenbo Feng 	security_bpf_prog_free(prog->aux);
26643ac1f01bSRoman Gushchin free_prog:
266522dc4a0fSAndrii Nakryiko 	if (prog->aux->attach_btf)
266622dc4a0fSAndrii Nakryiko 		btf_put(prog->aux->attach_btf);
266709756af4SAlexei Starovoitov 	bpf_prog_free(prog);
266809756af4SAlexei Starovoitov 	return err;
266909756af4SAlexei Starovoitov }
267009756af4SAlexei Starovoitov 
26716e71b04aSChenbo Feng #define BPF_OBJ_LAST_FIELD file_flags
2672b2197755SDaniel Borkmann 
2673b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr)
2674b2197755SDaniel Borkmann {
26756e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_OBJ) || attr->file_flags != 0)
2676b2197755SDaniel Borkmann 		return -EINVAL;
2677b2197755SDaniel Borkmann 
2678535e7b4bSMickaël Salaün 	return bpf_obj_pin_user(attr->bpf_fd, u64_to_user_ptr(attr->pathname));
2679b2197755SDaniel Borkmann }
2680b2197755SDaniel Borkmann 
2681b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr)
2682b2197755SDaniel Borkmann {
26836e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0 ||
26846e71b04aSChenbo Feng 	    attr->file_flags & ~BPF_OBJ_FLAG_MASK)
2685b2197755SDaniel Borkmann 		return -EINVAL;
2686b2197755SDaniel Borkmann 
26876e71b04aSChenbo Feng 	return bpf_obj_get_user(u64_to_user_ptr(attr->pathname),
26886e71b04aSChenbo Feng 				attr->file_flags);
2689b2197755SDaniel Borkmann }
2690b2197755SDaniel Borkmann 
2691f2e10bffSAndrii Nakryiko void bpf_link_init(struct bpf_link *link, enum bpf_link_type type,
2692a3b80e10SAndrii Nakryiko 		   const struct bpf_link_ops *ops, struct bpf_prog *prog)
269370ed506cSAndrii Nakryiko {
269470ed506cSAndrii Nakryiko 	atomic64_set(&link->refcnt, 1);
2695f2e10bffSAndrii Nakryiko 	link->type = type;
2696a3b80e10SAndrii Nakryiko 	link->id = 0;
269770ed506cSAndrii Nakryiko 	link->ops = ops;
269870ed506cSAndrii Nakryiko 	link->prog = prog;
269970ed506cSAndrii Nakryiko }
270070ed506cSAndrii Nakryiko 
2701a3b80e10SAndrii Nakryiko static void bpf_link_free_id(int id)
2702a3b80e10SAndrii Nakryiko {
2703a3b80e10SAndrii Nakryiko 	if (!id)
2704a3b80e10SAndrii Nakryiko 		return;
2705a3b80e10SAndrii Nakryiko 
2706a3b80e10SAndrii Nakryiko 	spin_lock_bh(&link_idr_lock);
2707a3b80e10SAndrii Nakryiko 	idr_remove(&link_idr, id);
2708a3b80e10SAndrii Nakryiko 	spin_unlock_bh(&link_idr_lock);
2709a3b80e10SAndrii Nakryiko }
2710a3b80e10SAndrii Nakryiko 
271198868668SAndrii Nakryiko /* Clean up bpf_link and corresponding anon_inode file and FD. After
271298868668SAndrii Nakryiko  * anon_inode is created, bpf_link can't be just kfree()'d due to deferred
2713a3b80e10SAndrii Nakryiko  * anon_inode's release() call. This helper marksbpf_link as
2714a3b80e10SAndrii Nakryiko  * defunct, releases anon_inode file and puts reserved FD. bpf_prog's refcnt
2715a3b80e10SAndrii Nakryiko  * is not decremented, it's the responsibility of a calling code that failed
2716a3b80e10SAndrii Nakryiko  * to complete bpf_link initialization.
271798868668SAndrii Nakryiko  */
2718a3b80e10SAndrii Nakryiko void bpf_link_cleanup(struct bpf_link_primer *primer)
2719babf3164SAndrii Nakryiko {
2720a3b80e10SAndrii Nakryiko 	primer->link->prog = NULL;
2721a3b80e10SAndrii Nakryiko 	bpf_link_free_id(primer->id);
2722a3b80e10SAndrii Nakryiko 	fput(primer->file);
2723a3b80e10SAndrii Nakryiko 	put_unused_fd(primer->fd);
2724babf3164SAndrii Nakryiko }
2725babf3164SAndrii Nakryiko 
272670ed506cSAndrii Nakryiko void bpf_link_inc(struct bpf_link *link)
272770ed506cSAndrii Nakryiko {
272870ed506cSAndrii Nakryiko 	atomic64_inc(&link->refcnt);
272970ed506cSAndrii Nakryiko }
273070ed506cSAndrii Nakryiko 
273170ed506cSAndrii Nakryiko /* bpf_link_free is guaranteed to be called from process context */
273270ed506cSAndrii Nakryiko static void bpf_link_free(struct bpf_link *link)
273370ed506cSAndrii Nakryiko {
2734a3b80e10SAndrii Nakryiko 	bpf_link_free_id(link->id);
2735babf3164SAndrii Nakryiko 	if (link->prog) {
2736babf3164SAndrii Nakryiko 		/* detach BPF program, clean up used resources */
273770ed506cSAndrii Nakryiko 		link->ops->release(link);
2738babf3164SAndrii Nakryiko 		bpf_prog_put(link->prog);
2739babf3164SAndrii Nakryiko 	}
2740babf3164SAndrii Nakryiko 	/* free bpf_link and its containing memory */
2741babf3164SAndrii Nakryiko 	link->ops->dealloc(link);
274270ed506cSAndrii Nakryiko }
274370ed506cSAndrii Nakryiko 
274470ed506cSAndrii Nakryiko static void bpf_link_put_deferred(struct work_struct *work)
274570ed506cSAndrii Nakryiko {
274670ed506cSAndrii Nakryiko 	struct bpf_link *link = container_of(work, struct bpf_link, work);
274770ed506cSAndrii Nakryiko 
274870ed506cSAndrii Nakryiko 	bpf_link_free(link);
274970ed506cSAndrii Nakryiko }
275070ed506cSAndrii Nakryiko 
275170ed506cSAndrii Nakryiko /* bpf_link_put can be called from atomic context, but ensures that resources
275270ed506cSAndrii Nakryiko  * are freed from process context
275370ed506cSAndrii Nakryiko  */
275470ed506cSAndrii Nakryiko void bpf_link_put(struct bpf_link *link)
275570ed506cSAndrii Nakryiko {
275670ed506cSAndrii Nakryiko 	if (!atomic64_dec_and_test(&link->refcnt))
275770ed506cSAndrii Nakryiko 		return;
275870ed506cSAndrii Nakryiko 
2759f00f2f7fSAlexei Starovoitov 	if (in_atomic()) {
276070ed506cSAndrii Nakryiko 		INIT_WORK(&link->work, bpf_link_put_deferred);
276170ed506cSAndrii Nakryiko 		schedule_work(&link->work);
2762f00f2f7fSAlexei Starovoitov 	} else {
2763f00f2f7fSAlexei Starovoitov 		bpf_link_free(link);
2764f00f2f7fSAlexei Starovoitov 	}
276570ed506cSAndrii Nakryiko }
2766cb80ddc6SAlexei Starovoitov EXPORT_SYMBOL(bpf_link_put);
276770ed506cSAndrii Nakryiko 
276870ed506cSAndrii Nakryiko static int bpf_link_release(struct inode *inode, struct file *filp)
276970ed506cSAndrii Nakryiko {
277070ed506cSAndrii Nakryiko 	struct bpf_link *link = filp->private_data;
277170ed506cSAndrii Nakryiko 
277270ed506cSAndrii Nakryiko 	bpf_link_put(link);
2773fec56f58SAlexei Starovoitov 	return 0;
2774fec56f58SAlexei Starovoitov }
2775fec56f58SAlexei Starovoitov 
277670ed506cSAndrii Nakryiko #ifdef CONFIG_PROC_FS
2777f2e10bffSAndrii Nakryiko #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type)
2778f2e10bffSAndrii Nakryiko #define BPF_MAP_TYPE(_id, _ops)
2779f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name) [_id] = #_name,
2780f2e10bffSAndrii Nakryiko static const char *bpf_link_type_strs[] = {
2781f2e10bffSAndrii Nakryiko 	[BPF_LINK_TYPE_UNSPEC] = "<invalid>",
2782f2e10bffSAndrii Nakryiko #include <linux/bpf_types.h>
2783f2e10bffSAndrii Nakryiko };
2784f2e10bffSAndrii Nakryiko #undef BPF_PROG_TYPE
2785f2e10bffSAndrii Nakryiko #undef BPF_MAP_TYPE
2786f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE
278770ed506cSAndrii Nakryiko 
278870ed506cSAndrii Nakryiko static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
278970ed506cSAndrii Nakryiko {
279070ed506cSAndrii Nakryiko 	const struct bpf_link *link = filp->private_data;
279170ed506cSAndrii Nakryiko 	const struct bpf_prog *prog = link->prog;
279270ed506cSAndrii Nakryiko 	char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
279370ed506cSAndrii Nakryiko 
279470ed506cSAndrii Nakryiko 	bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
279570ed506cSAndrii Nakryiko 	seq_printf(m,
279670ed506cSAndrii Nakryiko 		   "link_type:\t%s\n"
2797a3b80e10SAndrii Nakryiko 		   "link_id:\t%u\n"
279870ed506cSAndrii Nakryiko 		   "prog_tag:\t%s\n"
279970ed506cSAndrii Nakryiko 		   "prog_id:\t%u\n",
2800f2e10bffSAndrii Nakryiko 		   bpf_link_type_strs[link->type],
2801a3b80e10SAndrii Nakryiko 		   link->id,
280270ed506cSAndrii Nakryiko 		   prog_tag,
280370ed506cSAndrii Nakryiko 		   prog->aux->id);
2804f2e10bffSAndrii Nakryiko 	if (link->ops->show_fdinfo)
2805f2e10bffSAndrii Nakryiko 		link->ops->show_fdinfo(link, m);
280670ed506cSAndrii Nakryiko }
280770ed506cSAndrii Nakryiko #endif
280870ed506cSAndrii Nakryiko 
28096f302bfbSZou Wei static const struct file_operations bpf_link_fops = {
281070ed506cSAndrii Nakryiko #ifdef CONFIG_PROC_FS
281170ed506cSAndrii Nakryiko 	.show_fdinfo	= bpf_link_show_fdinfo,
281270ed506cSAndrii Nakryiko #endif
281370ed506cSAndrii Nakryiko 	.release	= bpf_link_release,
2814fec56f58SAlexei Starovoitov 	.read		= bpf_dummy_read,
2815fec56f58SAlexei Starovoitov 	.write		= bpf_dummy_write,
2816fec56f58SAlexei Starovoitov };
2817fec56f58SAlexei Starovoitov 
2818a3b80e10SAndrii Nakryiko static int bpf_link_alloc_id(struct bpf_link *link)
281970ed506cSAndrii Nakryiko {
2820a3b80e10SAndrii Nakryiko 	int id;
2821a3b80e10SAndrii Nakryiko 
2822a3b80e10SAndrii Nakryiko 	idr_preload(GFP_KERNEL);
2823a3b80e10SAndrii Nakryiko 	spin_lock_bh(&link_idr_lock);
2824a3b80e10SAndrii Nakryiko 	id = idr_alloc_cyclic(&link_idr, link, 1, INT_MAX, GFP_ATOMIC);
2825a3b80e10SAndrii Nakryiko 	spin_unlock_bh(&link_idr_lock);
2826a3b80e10SAndrii Nakryiko 	idr_preload_end();
2827a3b80e10SAndrii Nakryiko 
2828a3b80e10SAndrii Nakryiko 	return id;
282970ed506cSAndrii Nakryiko }
283070ed506cSAndrii Nakryiko 
2831a3b80e10SAndrii Nakryiko /* Prepare bpf_link to be exposed to user-space by allocating anon_inode file,
2832a3b80e10SAndrii Nakryiko  * reserving unused FD and allocating ID from link_idr. This is to be paired
2833a3b80e10SAndrii Nakryiko  * with bpf_link_settle() to install FD and ID and expose bpf_link to
2834a3b80e10SAndrii Nakryiko  * user-space, if bpf_link is successfully attached. If not, bpf_link and
2835a3b80e10SAndrii Nakryiko  * pre-allocated resources are to be freed with bpf_cleanup() call. All the
2836a3b80e10SAndrii Nakryiko  * transient state is passed around in struct bpf_link_primer.
2837a3b80e10SAndrii Nakryiko  * This is preferred way to create and initialize bpf_link, especially when
2838a3b80e10SAndrii Nakryiko  * there are complicated and expensive operations in between creating bpf_link
2839a3b80e10SAndrii Nakryiko  * itself and attaching it to BPF hook. By using bpf_link_prime() and
2840a3b80e10SAndrii Nakryiko  * bpf_link_settle() kernel code using bpf_link doesn't have to perform
2841a3b80e10SAndrii Nakryiko  * expensive (and potentially failing) roll back operations in a rare case
2842a3b80e10SAndrii Nakryiko  * that file, FD, or ID can't be allocated.
2843babf3164SAndrii Nakryiko  */
2844a3b80e10SAndrii Nakryiko int bpf_link_prime(struct bpf_link *link, struct bpf_link_primer *primer)
2845babf3164SAndrii Nakryiko {
2846babf3164SAndrii Nakryiko 	struct file *file;
2847a3b80e10SAndrii Nakryiko 	int fd, id;
2848babf3164SAndrii Nakryiko 
2849babf3164SAndrii Nakryiko 	fd = get_unused_fd_flags(O_CLOEXEC);
2850babf3164SAndrii Nakryiko 	if (fd < 0)
2851a3b80e10SAndrii Nakryiko 		return fd;
2852babf3164SAndrii Nakryiko 
2853babf3164SAndrii Nakryiko 
2854a3b80e10SAndrii Nakryiko 	id = bpf_link_alloc_id(link);
2855a3b80e10SAndrii Nakryiko 	if (id < 0) {
2856a3b80e10SAndrii Nakryiko 		put_unused_fd(fd);
2857a3b80e10SAndrii Nakryiko 		return id;
2858a3b80e10SAndrii Nakryiko 	}
2859babf3164SAndrii Nakryiko 
2860babf3164SAndrii Nakryiko 	file = anon_inode_getfile("bpf_link", &bpf_link_fops, link, O_CLOEXEC);
2861babf3164SAndrii Nakryiko 	if (IS_ERR(file)) {
2862138c6767SAndrii Nakryiko 		bpf_link_free_id(id);
2863babf3164SAndrii Nakryiko 		put_unused_fd(fd);
2864138c6767SAndrii Nakryiko 		return PTR_ERR(file);
2865babf3164SAndrii Nakryiko 	}
2866babf3164SAndrii Nakryiko 
2867a3b80e10SAndrii Nakryiko 	primer->link = link;
2868a3b80e10SAndrii Nakryiko 	primer->file = file;
2869a3b80e10SAndrii Nakryiko 	primer->fd = fd;
2870a3b80e10SAndrii Nakryiko 	primer->id = id;
2871a3b80e10SAndrii Nakryiko 	return 0;
2872a3b80e10SAndrii Nakryiko }
2873a3b80e10SAndrii Nakryiko 
2874a3b80e10SAndrii Nakryiko int bpf_link_settle(struct bpf_link_primer *primer)
2875a3b80e10SAndrii Nakryiko {
2876a3b80e10SAndrii Nakryiko 	/* make bpf_link fetchable by ID */
2877a3b80e10SAndrii Nakryiko 	spin_lock_bh(&link_idr_lock);
2878a3b80e10SAndrii Nakryiko 	primer->link->id = primer->id;
2879a3b80e10SAndrii Nakryiko 	spin_unlock_bh(&link_idr_lock);
2880a3b80e10SAndrii Nakryiko 	/* make bpf_link fetchable by FD */
2881a3b80e10SAndrii Nakryiko 	fd_install(primer->fd, primer->file);
2882a3b80e10SAndrii Nakryiko 	/* pass through installed FD */
2883a3b80e10SAndrii Nakryiko 	return primer->fd;
2884a3b80e10SAndrii Nakryiko }
2885a3b80e10SAndrii Nakryiko 
2886a3b80e10SAndrii Nakryiko int bpf_link_new_fd(struct bpf_link *link)
2887a3b80e10SAndrii Nakryiko {
2888a3b80e10SAndrii Nakryiko 	return anon_inode_getfd("bpf-link", &bpf_link_fops, link, O_CLOEXEC);
2889babf3164SAndrii Nakryiko }
2890babf3164SAndrii Nakryiko 
289170ed506cSAndrii Nakryiko struct bpf_link *bpf_link_get_from_fd(u32 ufd)
289270ed506cSAndrii Nakryiko {
289370ed506cSAndrii Nakryiko 	struct fd f = fdget(ufd);
289470ed506cSAndrii Nakryiko 	struct bpf_link *link;
289570ed506cSAndrii Nakryiko 
289670ed506cSAndrii Nakryiko 	if (!f.file)
289770ed506cSAndrii Nakryiko 		return ERR_PTR(-EBADF);
289870ed506cSAndrii Nakryiko 	if (f.file->f_op != &bpf_link_fops) {
289970ed506cSAndrii Nakryiko 		fdput(f);
290070ed506cSAndrii Nakryiko 		return ERR_PTR(-EINVAL);
290170ed506cSAndrii Nakryiko 	}
290270ed506cSAndrii Nakryiko 
290370ed506cSAndrii Nakryiko 	link = f.file->private_data;
290470ed506cSAndrii Nakryiko 	bpf_link_inc(link);
290570ed506cSAndrii Nakryiko 	fdput(f);
290670ed506cSAndrii Nakryiko 
290770ed506cSAndrii Nakryiko 	return link;
290870ed506cSAndrii Nakryiko }
2909cb80ddc6SAlexei Starovoitov EXPORT_SYMBOL(bpf_link_get_from_fd);
291070ed506cSAndrii Nakryiko 
291170ed506cSAndrii Nakryiko static void bpf_tracing_link_release(struct bpf_link *link)
291270ed506cSAndrii Nakryiko {
29133aac1eadSToke Høiland-Jørgensen 	struct bpf_tracing_link *tr_link =
2914f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
29153aac1eadSToke Høiland-Jørgensen 
2916f7e0beafSKui-Feng Lee 	WARN_ON_ONCE(bpf_trampoline_unlink_prog(&tr_link->link,
29173aac1eadSToke Høiland-Jørgensen 						tr_link->trampoline));
29183aac1eadSToke Høiland-Jørgensen 
29193aac1eadSToke Høiland-Jørgensen 	bpf_trampoline_put(tr_link->trampoline);
29203aac1eadSToke Høiland-Jørgensen 
29213aac1eadSToke Høiland-Jørgensen 	/* tgt_prog is NULL if target is a kernel function */
29223aac1eadSToke Høiland-Jørgensen 	if (tr_link->tgt_prog)
29233aac1eadSToke Høiland-Jørgensen 		bpf_prog_put(tr_link->tgt_prog);
2924babf3164SAndrii Nakryiko }
2925babf3164SAndrii Nakryiko 
2926babf3164SAndrii Nakryiko static void bpf_tracing_link_dealloc(struct bpf_link *link)
2927babf3164SAndrii Nakryiko {
292870ed506cSAndrii Nakryiko 	struct bpf_tracing_link *tr_link =
2929f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
293070ed506cSAndrii Nakryiko 
293170ed506cSAndrii Nakryiko 	kfree(tr_link);
293270ed506cSAndrii Nakryiko }
293370ed506cSAndrii Nakryiko 
2934f2e10bffSAndrii Nakryiko static void bpf_tracing_link_show_fdinfo(const struct bpf_link *link,
2935f2e10bffSAndrii Nakryiko 					 struct seq_file *seq)
2936f2e10bffSAndrii Nakryiko {
2937f2e10bffSAndrii Nakryiko 	struct bpf_tracing_link *tr_link =
2938f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
2939f2e10bffSAndrii Nakryiko 
2940f2e10bffSAndrii Nakryiko 	seq_printf(seq,
2941f2e10bffSAndrii Nakryiko 		   "attach_type:\t%d\n",
2942f2e10bffSAndrii Nakryiko 		   tr_link->attach_type);
2943f2e10bffSAndrii Nakryiko }
2944f2e10bffSAndrii Nakryiko 
2945f2e10bffSAndrii Nakryiko static int bpf_tracing_link_fill_link_info(const struct bpf_link *link,
2946f2e10bffSAndrii Nakryiko 					   struct bpf_link_info *info)
2947f2e10bffSAndrii Nakryiko {
2948f2e10bffSAndrii Nakryiko 	struct bpf_tracing_link *tr_link =
2949f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
2950f2e10bffSAndrii Nakryiko 
2951f2e10bffSAndrii Nakryiko 	info->tracing.attach_type = tr_link->attach_type;
2952441e8c66SToke Høiland-Jørgensen 	bpf_trampoline_unpack_key(tr_link->trampoline->key,
2953441e8c66SToke Høiland-Jørgensen 				  &info->tracing.target_obj_id,
2954441e8c66SToke Høiland-Jørgensen 				  &info->tracing.target_btf_id);
2955f2e10bffSAndrii Nakryiko 
2956f2e10bffSAndrii Nakryiko 	return 0;
2957f2e10bffSAndrii Nakryiko }
2958f2e10bffSAndrii Nakryiko 
295970ed506cSAndrii Nakryiko static const struct bpf_link_ops bpf_tracing_link_lops = {
296070ed506cSAndrii Nakryiko 	.release = bpf_tracing_link_release,
2961babf3164SAndrii Nakryiko 	.dealloc = bpf_tracing_link_dealloc,
2962f2e10bffSAndrii Nakryiko 	.show_fdinfo = bpf_tracing_link_show_fdinfo,
2963f2e10bffSAndrii Nakryiko 	.fill_link_info = bpf_tracing_link_fill_link_info,
296470ed506cSAndrii Nakryiko };
296570ed506cSAndrii Nakryiko 
29664a1e7c0cSToke Høiland-Jørgensen static int bpf_tracing_prog_attach(struct bpf_prog *prog,
29674a1e7c0cSToke Høiland-Jørgensen 				   int tgt_prog_fd,
29682fcc8241SKui-Feng Lee 				   u32 btf_id,
29692fcc8241SKui-Feng Lee 				   u64 bpf_cookie)
2970fec56f58SAlexei Starovoitov {
2971a3b80e10SAndrii Nakryiko 	struct bpf_link_primer link_primer;
29723aac1eadSToke Høiland-Jørgensen 	struct bpf_prog *tgt_prog = NULL;
29734a1e7c0cSToke Høiland-Jørgensen 	struct bpf_trampoline *tr = NULL;
297470ed506cSAndrii Nakryiko 	struct bpf_tracing_link *link;
29754a1e7c0cSToke Høiland-Jørgensen 	u64 key = 0;
2976a3b80e10SAndrii Nakryiko 	int err;
2977fec56f58SAlexei Starovoitov 
29789e4e01dfSKP Singh 	switch (prog->type) {
29799e4e01dfSKP Singh 	case BPF_PROG_TYPE_TRACING:
2980fec56f58SAlexei Starovoitov 		if (prog->expected_attach_type != BPF_TRACE_FENTRY &&
2981be8704ffSAlexei Starovoitov 		    prog->expected_attach_type != BPF_TRACE_FEXIT &&
29829e4e01dfSKP Singh 		    prog->expected_attach_type != BPF_MODIFY_RETURN) {
29839e4e01dfSKP Singh 			err = -EINVAL;
29849e4e01dfSKP Singh 			goto out_put_prog;
29859e4e01dfSKP Singh 		}
29869e4e01dfSKP Singh 		break;
29879e4e01dfSKP Singh 	case BPF_PROG_TYPE_EXT:
29889e4e01dfSKP Singh 		if (prog->expected_attach_type != 0) {
29899e4e01dfSKP Singh 			err = -EINVAL;
29909e4e01dfSKP Singh 			goto out_put_prog;
29919e4e01dfSKP Singh 		}
29929e4e01dfSKP Singh 		break;
29939e4e01dfSKP Singh 	case BPF_PROG_TYPE_LSM:
29949e4e01dfSKP Singh 		if (prog->expected_attach_type != BPF_LSM_MAC) {
29959e4e01dfSKP Singh 			err = -EINVAL;
29969e4e01dfSKP Singh 			goto out_put_prog;
29979e4e01dfSKP Singh 		}
29989e4e01dfSKP Singh 		break;
29999e4e01dfSKP Singh 	default:
3000fec56f58SAlexei Starovoitov 		err = -EINVAL;
3001fec56f58SAlexei Starovoitov 		goto out_put_prog;
3002fec56f58SAlexei Starovoitov 	}
3003fec56f58SAlexei Starovoitov 
30044a1e7c0cSToke Høiland-Jørgensen 	if (!!tgt_prog_fd != !!btf_id) {
30054a1e7c0cSToke Høiland-Jørgensen 		err = -EINVAL;
30064a1e7c0cSToke Høiland-Jørgensen 		goto out_put_prog;
30074a1e7c0cSToke Høiland-Jørgensen 	}
30084a1e7c0cSToke Høiland-Jørgensen 
30094a1e7c0cSToke Høiland-Jørgensen 	if (tgt_prog_fd) {
30104a1e7c0cSToke Høiland-Jørgensen 		/* For now we only allow new targets for BPF_PROG_TYPE_EXT */
30114a1e7c0cSToke Høiland-Jørgensen 		if (prog->type != BPF_PROG_TYPE_EXT) {
30124a1e7c0cSToke Høiland-Jørgensen 			err = -EINVAL;
30134a1e7c0cSToke Høiland-Jørgensen 			goto out_put_prog;
30144a1e7c0cSToke Høiland-Jørgensen 		}
30154a1e7c0cSToke Høiland-Jørgensen 
30164a1e7c0cSToke Høiland-Jørgensen 		tgt_prog = bpf_prog_get(tgt_prog_fd);
30174a1e7c0cSToke Høiland-Jørgensen 		if (IS_ERR(tgt_prog)) {
30184a1e7c0cSToke Høiland-Jørgensen 			err = PTR_ERR(tgt_prog);
30194a1e7c0cSToke Høiland-Jørgensen 			tgt_prog = NULL;
30204a1e7c0cSToke Høiland-Jørgensen 			goto out_put_prog;
30214a1e7c0cSToke Høiland-Jørgensen 		}
30224a1e7c0cSToke Høiland-Jørgensen 
302322dc4a0fSAndrii Nakryiko 		key = bpf_trampoline_compute_key(tgt_prog, NULL, btf_id);
30244a1e7c0cSToke Høiland-Jørgensen 	}
30254a1e7c0cSToke Høiland-Jørgensen 
302670ed506cSAndrii Nakryiko 	link = kzalloc(sizeof(*link), GFP_USER);
302770ed506cSAndrii Nakryiko 	if (!link) {
302870ed506cSAndrii Nakryiko 		err = -ENOMEM;
3029fec56f58SAlexei Starovoitov 		goto out_put_prog;
3030fec56f58SAlexei Starovoitov 	}
3031f7e0beafSKui-Feng Lee 	bpf_link_init(&link->link.link, BPF_LINK_TYPE_TRACING,
3032f2e10bffSAndrii Nakryiko 		      &bpf_tracing_link_lops, prog);
3033f2e10bffSAndrii Nakryiko 	link->attach_type = prog->expected_attach_type;
30342fcc8241SKui-Feng Lee 	link->link.cookie = bpf_cookie;
3035fec56f58SAlexei Starovoitov 
30363aac1eadSToke Høiland-Jørgensen 	mutex_lock(&prog->aux->dst_mutex);
3037babf3164SAndrii Nakryiko 
30384a1e7c0cSToke Høiland-Jørgensen 	/* There are a few possible cases here:
30394a1e7c0cSToke Høiland-Jørgensen 	 *
30404a1e7c0cSToke Høiland-Jørgensen 	 * - if prog->aux->dst_trampoline is set, the program was just loaded
30414a1e7c0cSToke Høiland-Jørgensen 	 *   and not yet attached to anything, so we can use the values stored
30424a1e7c0cSToke Høiland-Jørgensen 	 *   in prog->aux
30434a1e7c0cSToke Høiland-Jørgensen 	 *
30444a1e7c0cSToke Høiland-Jørgensen 	 * - if prog->aux->dst_trampoline is NULL, the program has already been
30454a1e7c0cSToke Høiland-Jørgensen          *   attached to a target and its initial target was cleared (below)
30464a1e7c0cSToke Høiland-Jørgensen 	 *
30474a1e7c0cSToke Høiland-Jørgensen 	 * - if tgt_prog != NULL, the caller specified tgt_prog_fd +
30484a1e7c0cSToke Høiland-Jørgensen 	 *   target_btf_id using the link_create API.
30494a1e7c0cSToke Høiland-Jørgensen 	 *
30504a1e7c0cSToke Høiland-Jørgensen 	 * - if tgt_prog == NULL when this function was called using the old
30514a1e7c0cSToke Høiland-Jørgensen 	 *   raw_tracepoint_open API, and we need a target from prog->aux
30524a1e7c0cSToke Høiland-Jørgensen 	 *
3053f3a95075SJiri Olsa 	 * - if prog->aux->dst_trampoline and tgt_prog is NULL, the program
3054f3a95075SJiri Olsa 	 *   was detached and is going for re-attachment.
30554a1e7c0cSToke Høiland-Jørgensen 	 */
30564a1e7c0cSToke Høiland-Jørgensen 	if (!prog->aux->dst_trampoline && !tgt_prog) {
3057f3a95075SJiri Olsa 		/*
3058f3a95075SJiri Olsa 		 * Allow re-attach for TRACING and LSM programs. If it's
3059f3a95075SJiri Olsa 		 * currently linked, bpf_trampoline_link_prog will fail.
3060f3a95075SJiri Olsa 		 * EXT programs need to specify tgt_prog_fd, so they
3061f3a95075SJiri Olsa 		 * re-attach in separate code path.
3062f3a95075SJiri Olsa 		 */
3063f3a95075SJiri Olsa 		if (prog->type != BPF_PROG_TYPE_TRACING &&
3064f3a95075SJiri Olsa 		    prog->type != BPF_PROG_TYPE_LSM) {
3065f3a95075SJiri Olsa 			err = -EINVAL;
30663aac1eadSToke Høiland-Jørgensen 			goto out_unlock;
30673aac1eadSToke Høiland-Jørgensen 		}
3068f3a95075SJiri Olsa 		btf_id = prog->aux->attach_btf_id;
3069f3a95075SJiri Olsa 		key = bpf_trampoline_compute_key(NULL, prog->aux->attach_btf, btf_id);
3070f3a95075SJiri Olsa 	}
30714a1e7c0cSToke Høiland-Jørgensen 
30724a1e7c0cSToke Høiland-Jørgensen 	if (!prog->aux->dst_trampoline ||
30734a1e7c0cSToke Høiland-Jørgensen 	    (key && key != prog->aux->dst_trampoline->key)) {
30744a1e7c0cSToke Høiland-Jørgensen 		/* If there is no saved target, or the specified target is
30754a1e7c0cSToke Høiland-Jørgensen 		 * different from the destination specified at load time, we
30764a1e7c0cSToke Høiland-Jørgensen 		 * need a new trampoline and a check for compatibility
30774a1e7c0cSToke Høiland-Jørgensen 		 */
30784a1e7c0cSToke Høiland-Jørgensen 		struct bpf_attach_target_info tgt_info = {};
30794a1e7c0cSToke Høiland-Jørgensen 
30804a1e7c0cSToke Høiland-Jørgensen 		err = bpf_check_attach_target(NULL, prog, tgt_prog, btf_id,
30814a1e7c0cSToke Høiland-Jørgensen 					      &tgt_info);
30824a1e7c0cSToke Høiland-Jørgensen 		if (err)
30834a1e7c0cSToke Høiland-Jørgensen 			goto out_unlock;
30844a1e7c0cSToke Høiland-Jørgensen 
30854a1e7c0cSToke Høiland-Jørgensen 		tr = bpf_trampoline_get(key, &tgt_info);
30864a1e7c0cSToke Høiland-Jørgensen 		if (!tr) {
30874a1e7c0cSToke Høiland-Jørgensen 			err = -ENOMEM;
30884a1e7c0cSToke Høiland-Jørgensen 			goto out_unlock;
30894a1e7c0cSToke Høiland-Jørgensen 		}
30904a1e7c0cSToke Høiland-Jørgensen 	} else {
30914a1e7c0cSToke Høiland-Jørgensen 		/* The caller didn't specify a target, or the target was the
30924a1e7c0cSToke Høiland-Jørgensen 		 * same as the destination supplied during program load. This
30934a1e7c0cSToke Høiland-Jørgensen 		 * means we can reuse the trampoline and reference from program
30944a1e7c0cSToke Høiland-Jørgensen 		 * load time, and there is no need to allocate a new one. This
30954a1e7c0cSToke Høiland-Jørgensen 		 * can only happen once for any program, as the saved values in
30964a1e7c0cSToke Høiland-Jørgensen 		 * prog->aux are cleared below.
30974a1e7c0cSToke Høiland-Jørgensen 		 */
30983aac1eadSToke Høiland-Jørgensen 		tr = prog->aux->dst_trampoline;
30993aac1eadSToke Høiland-Jørgensen 		tgt_prog = prog->aux->dst_prog;
31004a1e7c0cSToke Høiland-Jørgensen 	}
31013aac1eadSToke Høiland-Jørgensen 
3102f7e0beafSKui-Feng Lee 	err = bpf_link_prime(&link->link.link, &link_primer);
31033aac1eadSToke Høiland-Jørgensen 	if (err)
31043aac1eadSToke Høiland-Jørgensen 		goto out_unlock;
31053aac1eadSToke Høiland-Jørgensen 
3106f7e0beafSKui-Feng Lee 	err = bpf_trampoline_link_prog(&link->link, tr);
3107babf3164SAndrii Nakryiko 	if (err) {
3108a3b80e10SAndrii Nakryiko 		bpf_link_cleanup(&link_primer);
31093aac1eadSToke Høiland-Jørgensen 		link = NULL;
31103aac1eadSToke Høiland-Jørgensen 		goto out_unlock;
3111babf3164SAndrii Nakryiko 	}
3112babf3164SAndrii Nakryiko 
31133aac1eadSToke Høiland-Jørgensen 	link->tgt_prog = tgt_prog;
31143aac1eadSToke Høiland-Jørgensen 	link->trampoline = tr;
31153aac1eadSToke Høiland-Jørgensen 
31164a1e7c0cSToke Høiland-Jørgensen 	/* Always clear the trampoline and target prog from prog->aux to make
31174a1e7c0cSToke Høiland-Jørgensen 	 * sure the original attach destination is not kept alive after a
31184a1e7c0cSToke Høiland-Jørgensen 	 * program is (re-)attached to another target.
31194a1e7c0cSToke Høiland-Jørgensen 	 */
31204a1e7c0cSToke Høiland-Jørgensen 	if (prog->aux->dst_prog &&
31214a1e7c0cSToke Høiland-Jørgensen 	    (tgt_prog_fd || tr != prog->aux->dst_trampoline))
31224a1e7c0cSToke Høiland-Jørgensen 		/* got extra prog ref from syscall, or attaching to different prog */
31234a1e7c0cSToke Høiland-Jørgensen 		bpf_prog_put(prog->aux->dst_prog);
31244a1e7c0cSToke Høiland-Jørgensen 	if (prog->aux->dst_trampoline && tr != prog->aux->dst_trampoline)
31254a1e7c0cSToke Høiland-Jørgensen 		/* we allocated a new trampoline, so free the old one */
31264a1e7c0cSToke Høiland-Jørgensen 		bpf_trampoline_put(prog->aux->dst_trampoline);
31274a1e7c0cSToke Høiland-Jørgensen 
31283aac1eadSToke Høiland-Jørgensen 	prog->aux->dst_prog = NULL;
31293aac1eadSToke Høiland-Jørgensen 	prog->aux->dst_trampoline = NULL;
31303aac1eadSToke Høiland-Jørgensen 	mutex_unlock(&prog->aux->dst_mutex);
31313aac1eadSToke Høiland-Jørgensen 
3132a3b80e10SAndrii Nakryiko 	return bpf_link_settle(&link_primer);
31333aac1eadSToke Høiland-Jørgensen out_unlock:
31344a1e7c0cSToke Høiland-Jørgensen 	if (tr && tr != prog->aux->dst_trampoline)
31354a1e7c0cSToke Høiland-Jørgensen 		bpf_trampoline_put(tr);
31363aac1eadSToke Høiland-Jørgensen 	mutex_unlock(&prog->aux->dst_mutex);
31373aac1eadSToke Høiland-Jørgensen 	kfree(link);
3138fec56f58SAlexei Starovoitov out_put_prog:
31394a1e7c0cSToke Høiland-Jørgensen 	if (tgt_prog_fd && tgt_prog)
31404a1e7c0cSToke Høiland-Jørgensen 		bpf_prog_put(tgt_prog);
3141fec56f58SAlexei Starovoitov 	return err;
3142fec56f58SAlexei Starovoitov }
3143fec56f58SAlexei Starovoitov 
314470ed506cSAndrii Nakryiko struct bpf_raw_tp_link {
314570ed506cSAndrii Nakryiko 	struct bpf_link link;
3146c4f6699dSAlexei Starovoitov 	struct bpf_raw_event_map *btp;
3147c4f6699dSAlexei Starovoitov };
3148c4f6699dSAlexei Starovoitov 
314970ed506cSAndrii Nakryiko static void bpf_raw_tp_link_release(struct bpf_link *link)
3150c4f6699dSAlexei Starovoitov {
315170ed506cSAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp =
315270ed506cSAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3153c4f6699dSAlexei Starovoitov 
315470ed506cSAndrii Nakryiko 	bpf_probe_unregister(raw_tp->btp, raw_tp->link.prog);
3155a38d1107SMatt Mullins 	bpf_put_raw_tracepoint(raw_tp->btp);
3156babf3164SAndrii Nakryiko }
3157babf3164SAndrii Nakryiko 
3158babf3164SAndrii Nakryiko static void bpf_raw_tp_link_dealloc(struct bpf_link *link)
3159babf3164SAndrii Nakryiko {
3160babf3164SAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp =
3161babf3164SAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3162babf3164SAndrii Nakryiko 
3163c4f6699dSAlexei Starovoitov 	kfree(raw_tp);
3164c4f6699dSAlexei Starovoitov }
3165c4f6699dSAlexei Starovoitov 
3166f2e10bffSAndrii Nakryiko static void bpf_raw_tp_link_show_fdinfo(const struct bpf_link *link,
3167f2e10bffSAndrii Nakryiko 					struct seq_file *seq)
3168f2e10bffSAndrii Nakryiko {
3169f2e10bffSAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp_link =
3170f2e10bffSAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3171f2e10bffSAndrii Nakryiko 
3172f2e10bffSAndrii Nakryiko 	seq_printf(seq,
3173f2e10bffSAndrii Nakryiko 		   "tp_name:\t%s\n",
3174f2e10bffSAndrii Nakryiko 		   raw_tp_link->btp->tp->name);
3175f2e10bffSAndrii Nakryiko }
3176f2e10bffSAndrii Nakryiko 
3177f2e10bffSAndrii Nakryiko static int bpf_raw_tp_link_fill_link_info(const struct bpf_link *link,
3178f2e10bffSAndrii Nakryiko 					  struct bpf_link_info *info)
3179f2e10bffSAndrii Nakryiko {
3180f2e10bffSAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp_link =
3181f2e10bffSAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3182f2e10bffSAndrii Nakryiko 	char __user *ubuf = u64_to_user_ptr(info->raw_tracepoint.tp_name);
3183f2e10bffSAndrii Nakryiko 	const char *tp_name = raw_tp_link->btp->tp->name;
3184f2e10bffSAndrii Nakryiko 	u32 ulen = info->raw_tracepoint.tp_name_len;
3185f2e10bffSAndrii Nakryiko 	size_t tp_len = strlen(tp_name);
3186f2e10bffSAndrii Nakryiko 
3187b474959dSYonghong Song 	if (!ulen ^ !ubuf)
3188f2e10bffSAndrii Nakryiko 		return -EINVAL;
3189f2e10bffSAndrii Nakryiko 
3190f2e10bffSAndrii Nakryiko 	info->raw_tracepoint.tp_name_len = tp_len + 1;
3191f2e10bffSAndrii Nakryiko 
3192f2e10bffSAndrii Nakryiko 	if (!ubuf)
3193f2e10bffSAndrii Nakryiko 		return 0;
3194f2e10bffSAndrii Nakryiko 
3195f2e10bffSAndrii Nakryiko 	if (ulen >= tp_len + 1) {
3196f2e10bffSAndrii Nakryiko 		if (copy_to_user(ubuf, tp_name, tp_len + 1))
3197f2e10bffSAndrii Nakryiko 			return -EFAULT;
3198f2e10bffSAndrii Nakryiko 	} else {
3199f2e10bffSAndrii Nakryiko 		char zero = '\0';
3200f2e10bffSAndrii Nakryiko 
3201f2e10bffSAndrii Nakryiko 		if (copy_to_user(ubuf, tp_name, ulen - 1))
3202f2e10bffSAndrii Nakryiko 			return -EFAULT;
3203f2e10bffSAndrii Nakryiko 		if (put_user(zero, ubuf + ulen - 1))
3204f2e10bffSAndrii Nakryiko 			return -EFAULT;
3205f2e10bffSAndrii Nakryiko 		return -ENOSPC;
3206f2e10bffSAndrii Nakryiko 	}
3207f2e10bffSAndrii Nakryiko 
3208f2e10bffSAndrii Nakryiko 	return 0;
3209f2e10bffSAndrii Nakryiko }
3210f2e10bffSAndrii Nakryiko 
3211a3b80e10SAndrii Nakryiko static const struct bpf_link_ops bpf_raw_tp_link_lops = {
321270ed506cSAndrii Nakryiko 	.release = bpf_raw_tp_link_release,
3213babf3164SAndrii Nakryiko 	.dealloc = bpf_raw_tp_link_dealloc,
3214f2e10bffSAndrii Nakryiko 	.show_fdinfo = bpf_raw_tp_link_show_fdinfo,
3215f2e10bffSAndrii Nakryiko 	.fill_link_info = bpf_raw_tp_link_fill_link_info,
3216c4f6699dSAlexei Starovoitov };
3217c4f6699dSAlexei Starovoitov 
3218b89fbfbbSAndrii Nakryiko #ifdef CONFIG_PERF_EVENTS
3219b89fbfbbSAndrii Nakryiko struct bpf_perf_link {
3220b89fbfbbSAndrii Nakryiko 	struct bpf_link link;
3221b89fbfbbSAndrii Nakryiko 	struct file *perf_file;
3222b89fbfbbSAndrii Nakryiko };
3223b89fbfbbSAndrii Nakryiko 
3224b89fbfbbSAndrii Nakryiko static void bpf_perf_link_release(struct bpf_link *link)
3225b89fbfbbSAndrii Nakryiko {
3226b89fbfbbSAndrii Nakryiko 	struct bpf_perf_link *perf_link = container_of(link, struct bpf_perf_link, link);
3227b89fbfbbSAndrii Nakryiko 	struct perf_event *event = perf_link->perf_file->private_data;
3228b89fbfbbSAndrii Nakryiko 
3229b89fbfbbSAndrii Nakryiko 	perf_event_free_bpf_prog(event);
3230b89fbfbbSAndrii Nakryiko 	fput(perf_link->perf_file);
3231b89fbfbbSAndrii Nakryiko }
3232b89fbfbbSAndrii Nakryiko 
3233b89fbfbbSAndrii Nakryiko static void bpf_perf_link_dealloc(struct bpf_link *link)
3234b89fbfbbSAndrii Nakryiko {
3235b89fbfbbSAndrii Nakryiko 	struct bpf_perf_link *perf_link = container_of(link, struct bpf_perf_link, link);
3236b89fbfbbSAndrii Nakryiko 
3237b89fbfbbSAndrii Nakryiko 	kfree(perf_link);
3238b89fbfbbSAndrii Nakryiko }
3239b89fbfbbSAndrii Nakryiko 
3240b89fbfbbSAndrii Nakryiko static const struct bpf_link_ops bpf_perf_link_lops = {
3241b89fbfbbSAndrii Nakryiko 	.release = bpf_perf_link_release,
3242b89fbfbbSAndrii Nakryiko 	.dealloc = bpf_perf_link_dealloc,
3243b89fbfbbSAndrii Nakryiko };
3244b89fbfbbSAndrii Nakryiko 
3245b89fbfbbSAndrii Nakryiko static int bpf_perf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
3246b89fbfbbSAndrii Nakryiko {
3247b89fbfbbSAndrii Nakryiko 	struct bpf_link_primer link_primer;
3248b89fbfbbSAndrii Nakryiko 	struct bpf_perf_link *link;
3249b89fbfbbSAndrii Nakryiko 	struct perf_event *event;
3250b89fbfbbSAndrii Nakryiko 	struct file *perf_file;
3251b89fbfbbSAndrii Nakryiko 	int err;
3252b89fbfbbSAndrii Nakryiko 
3253b89fbfbbSAndrii Nakryiko 	if (attr->link_create.flags)
3254b89fbfbbSAndrii Nakryiko 		return -EINVAL;
3255b89fbfbbSAndrii Nakryiko 
3256b89fbfbbSAndrii Nakryiko 	perf_file = perf_event_get(attr->link_create.target_fd);
3257b89fbfbbSAndrii Nakryiko 	if (IS_ERR(perf_file))
3258b89fbfbbSAndrii Nakryiko 		return PTR_ERR(perf_file);
3259b89fbfbbSAndrii Nakryiko 
3260b89fbfbbSAndrii Nakryiko 	link = kzalloc(sizeof(*link), GFP_USER);
3261b89fbfbbSAndrii Nakryiko 	if (!link) {
3262b89fbfbbSAndrii Nakryiko 		err = -ENOMEM;
3263b89fbfbbSAndrii Nakryiko 		goto out_put_file;
3264b89fbfbbSAndrii Nakryiko 	}
3265b89fbfbbSAndrii Nakryiko 	bpf_link_init(&link->link, BPF_LINK_TYPE_PERF_EVENT, &bpf_perf_link_lops, prog);
3266b89fbfbbSAndrii Nakryiko 	link->perf_file = perf_file;
3267b89fbfbbSAndrii Nakryiko 
3268b89fbfbbSAndrii Nakryiko 	err = bpf_link_prime(&link->link, &link_primer);
3269b89fbfbbSAndrii Nakryiko 	if (err) {
3270b89fbfbbSAndrii Nakryiko 		kfree(link);
3271b89fbfbbSAndrii Nakryiko 		goto out_put_file;
3272b89fbfbbSAndrii Nakryiko 	}
3273b89fbfbbSAndrii Nakryiko 
3274b89fbfbbSAndrii Nakryiko 	event = perf_file->private_data;
327582e6b1eeSAndrii Nakryiko 	err = perf_event_set_bpf_prog(event, prog, attr->link_create.perf_event.bpf_cookie);
3276b89fbfbbSAndrii Nakryiko 	if (err) {
3277b89fbfbbSAndrii Nakryiko 		bpf_link_cleanup(&link_primer);
3278b89fbfbbSAndrii Nakryiko 		goto out_put_file;
3279b89fbfbbSAndrii Nakryiko 	}
3280b89fbfbbSAndrii Nakryiko 	/* perf_event_set_bpf_prog() doesn't take its own refcnt on prog */
3281b89fbfbbSAndrii Nakryiko 	bpf_prog_inc(prog);
3282b89fbfbbSAndrii Nakryiko 
3283b89fbfbbSAndrii Nakryiko 	return bpf_link_settle(&link_primer);
3284b89fbfbbSAndrii Nakryiko 
3285b89fbfbbSAndrii Nakryiko out_put_file:
3286b89fbfbbSAndrii Nakryiko 	fput(perf_file);
3287b89fbfbbSAndrii Nakryiko 	return err;
3288b89fbfbbSAndrii Nakryiko }
32890dcac272SJiri Olsa #else
32900dcac272SJiri Olsa static int bpf_perf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
32910dcac272SJiri Olsa {
32920dcac272SJiri Olsa 	return -EOPNOTSUPP;
32930dcac272SJiri Olsa }
3294b89fbfbbSAndrii Nakryiko #endif /* CONFIG_PERF_EVENTS */
3295b89fbfbbSAndrii Nakryiko 
3296df86ca0dSAndrii Nakryiko static int bpf_raw_tp_link_attach(struct bpf_prog *prog,
3297df86ca0dSAndrii Nakryiko 				  const char __user *user_tp_name)
3298c4f6699dSAlexei Starovoitov {
3299a3b80e10SAndrii Nakryiko 	struct bpf_link_primer link_primer;
3300babf3164SAndrii Nakryiko 	struct bpf_raw_tp_link *link;
3301c4f6699dSAlexei Starovoitov 	struct bpf_raw_event_map *btp;
3302ac4414b5SAlexei Starovoitov 	const char *tp_name;
3303ac4414b5SAlexei Starovoitov 	char buf[128];
3304a3b80e10SAndrii Nakryiko 	int err;
3305c4f6699dSAlexei Starovoitov 
33069e4e01dfSKP Singh 	switch (prog->type) {
33079e4e01dfSKP Singh 	case BPF_PROG_TYPE_TRACING:
33089e4e01dfSKP Singh 	case BPF_PROG_TYPE_EXT:
33099e4e01dfSKP Singh 	case BPF_PROG_TYPE_LSM:
3310df86ca0dSAndrii Nakryiko 		if (user_tp_name)
3311fec56f58SAlexei Starovoitov 			/* The attach point for this category of programs
3312fec56f58SAlexei Starovoitov 			 * should be specified via btf_id during program load.
3313ac4414b5SAlexei Starovoitov 			 */
3314df86ca0dSAndrii Nakryiko 			return -EINVAL;
33159e4e01dfSKP Singh 		if (prog->type == BPF_PROG_TYPE_TRACING &&
33169e4e01dfSKP Singh 		    prog->expected_attach_type == BPF_TRACE_RAW_TP) {
331738207291SMartin KaFai Lau 			tp_name = prog->aux->attach_func_name;
33189e4e01dfSKP Singh 			break;
33199e4e01dfSKP Singh 		}
33202fcc8241SKui-Feng Lee 		return bpf_tracing_prog_attach(prog, 0, 0, 0);
33219e4e01dfSKP Singh 	case BPF_PROG_TYPE_RAW_TRACEPOINT:
33229e4e01dfSKP Singh 	case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
3323df86ca0dSAndrii Nakryiko 		if (strncpy_from_user(buf, user_tp_name, sizeof(buf) - 1) < 0)
3324df86ca0dSAndrii Nakryiko 			return -EFAULT;
3325ac4414b5SAlexei Starovoitov 		buf[sizeof(buf) - 1] = 0;
3326ac4414b5SAlexei Starovoitov 		tp_name = buf;
33279e4e01dfSKP Singh 		break;
33289e4e01dfSKP Singh 	default:
3329df86ca0dSAndrii Nakryiko 		return -EINVAL;
3330ac4414b5SAlexei Starovoitov 	}
3331c4f6699dSAlexei Starovoitov 
3332a38d1107SMatt Mullins 	btp = bpf_get_raw_tracepoint(tp_name);
3333df86ca0dSAndrii Nakryiko 	if (!btp)
3334df86ca0dSAndrii Nakryiko 		return -ENOENT;
3335c4f6699dSAlexei Starovoitov 
3336babf3164SAndrii Nakryiko 	link = kzalloc(sizeof(*link), GFP_USER);
3337babf3164SAndrii Nakryiko 	if (!link) {
3338a38d1107SMatt Mullins 		err = -ENOMEM;
3339a38d1107SMatt Mullins 		goto out_put_btp;
3340a38d1107SMatt Mullins 	}
3341f2e10bffSAndrii Nakryiko 	bpf_link_init(&link->link, BPF_LINK_TYPE_RAW_TRACEPOINT,
3342f2e10bffSAndrii Nakryiko 		      &bpf_raw_tp_link_lops, prog);
3343babf3164SAndrii Nakryiko 	link->btp = btp;
3344c4f6699dSAlexei Starovoitov 
3345a3b80e10SAndrii Nakryiko 	err = bpf_link_prime(&link->link, &link_primer);
3346a3b80e10SAndrii Nakryiko 	if (err) {
3347babf3164SAndrii Nakryiko 		kfree(link);
3348babf3164SAndrii Nakryiko 		goto out_put_btp;
3349c4f6699dSAlexei Starovoitov 	}
3350babf3164SAndrii Nakryiko 
3351babf3164SAndrii Nakryiko 	err = bpf_probe_register(link->btp, prog);
3352babf3164SAndrii Nakryiko 	if (err) {
3353a3b80e10SAndrii Nakryiko 		bpf_link_cleanup(&link_primer);
3354babf3164SAndrii Nakryiko 		goto out_put_btp;
3355babf3164SAndrii Nakryiko 	}
3356babf3164SAndrii Nakryiko 
3357a3b80e10SAndrii Nakryiko 	return bpf_link_settle(&link_primer);
3358c4f6699dSAlexei Starovoitov 
3359a38d1107SMatt Mullins out_put_btp:
3360a38d1107SMatt Mullins 	bpf_put_raw_tracepoint(btp);
3361c4f6699dSAlexei Starovoitov 	return err;
3362c4f6699dSAlexei Starovoitov }
3363c4f6699dSAlexei Starovoitov 
3364df86ca0dSAndrii Nakryiko #define BPF_RAW_TRACEPOINT_OPEN_LAST_FIELD raw_tracepoint.prog_fd
3365df86ca0dSAndrii Nakryiko 
3366df86ca0dSAndrii Nakryiko static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
3367df86ca0dSAndrii Nakryiko {
3368df86ca0dSAndrii Nakryiko 	struct bpf_prog *prog;
3369df86ca0dSAndrii Nakryiko 	int fd;
3370df86ca0dSAndrii Nakryiko 
3371df86ca0dSAndrii Nakryiko 	if (CHECK_ATTR(BPF_RAW_TRACEPOINT_OPEN))
3372df86ca0dSAndrii Nakryiko 		return -EINVAL;
3373df86ca0dSAndrii Nakryiko 
3374df86ca0dSAndrii Nakryiko 	prog = bpf_prog_get(attr->raw_tracepoint.prog_fd);
3375df86ca0dSAndrii Nakryiko 	if (IS_ERR(prog))
3376df86ca0dSAndrii Nakryiko 		return PTR_ERR(prog);
3377df86ca0dSAndrii Nakryiko 
3378df86ca0dSAndrii Nakryiko 	fd = bpf_raw_tp_link_attach(prog, u64_to_user_ptr(attr->raw_tracepoint.name));
3379df86ca0dSAndrii Nakryiko 	if (fd < 0)
3380df86ca0dSAndrii Nakryiko 		bpf_prog_put(prog);
3381df86ca0dSAndrii Nakryiko 	return fd;
3382df86ca0dSAndrii Nakryiko }
3383df86ca0dSAndrii Nakryiko 
338433491588SAnders Roxell static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog,
338533491588SAnders Roxell 					     enum bpf_attach_type attach_type)
338633491588SAnders Roxell {
338733491588SAnders Roxell 	switch (prog->type) {
338833491588SAnders Roxell 	case BPF_PROG_TYPE_CGROUP_SOCK:
338933491588SAnders Roxell 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
33900d01da6aSStanislav Fomichev 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
3391e9ddbb77SJakub Sitnicki 	case BPF_PROG_TYPE_SK_LOOKUP:
339233491588SAnders Roxell 		return attach_type == prog->expected_attach_type ? 0 : -EINVAL;
33935cf1e914Sbrakmo 	case BPF_PROG_TYPE_CGROUP_SKB:
33942c78ee89SAlexei Starovoitov 		if (!capable(CAP_NET_ADMIN))
33952c78ee89SAlexei Starovoitov 			/* cg-skb progs can be loaded by unpriv user.
33962c78ee89SAlexei Starovoitov 			 * check permissions at attach time.
33972c78ee89SAlexei Starovoitov 			 */
33982c78ee89SAlexei Starovoitov 			return -EPERM;
33995cf1e914Sbrakmo 		return prog->enforce_expected_attach_type &&
34005cf1e914Sbrakmo 			prog->expected_attach_type != attach_type ?
34015cf1e914Sbrakmo 			-EINVAL : 0;
340233491588SAnders Roxell 	default:
340333491588SAnders Roxell 		return 0;
340433491588SAnders Roxell 	}
340533491588SAnders Roxell }
340633491588SAnders Roxell 
3407e28784e3SAndrii Nakryiko static enum bpf_prog_type
3408e28784e3SAndrii Nakryiko attach_type_to_prog_type(enum bpf_attach_type attach_type)
3409e28784e3SAndrii Nakryiko {
3410e28784e3SAndrii Nakryiko 	switch (attach_type) {
3411e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET_INGRESS:
3412e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET_EGRESS:
3413e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SKB;
3414e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET_SOCK_CREATE:
3415f5836749SStanislav Fomichev 	case BPF_CGROUP_INET_SOCK_RELEASE:
3416e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET4_POST_BIND:
3417e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET6_POST_BIND:
3418e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SOCK;
3419e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET4_BIND:
3420e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET6_BIND:
3421e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET4_CONNECT:
3422e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET6_CONNECT:
34231b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETPEERNAME:
34241b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETPEERNAME:
34251b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETSOCKNAME:
34261b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETSOCKNAME:
3427e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP4_SENDMSG:
3428e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP6_SENDMSG:
3429e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP4_RECVMSG:
3430e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP6_RECVMSG:
3431e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
3432e28784e3SAndrii Nakryiko 	case BPF_CGROUP_SOCK_OPS:
3433e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_SOCK_OPS;
3434e28784e3SAndrii Nakryiko 	case BPF_CGROUP_DEVICE:
3435e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_DEVICE;
3436e28784e3SAndrii Nakryiko 	case BPF_SK_MSG_VERDICT:
3437e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_SK_MSG;
3438e28784e3SAndrii Nakryiko 	case BPF_SK_SKB_STREAM_PARSER:
3439e28784e3SAndrii Nakryiko 	case BPF_SK_SKB_STREAM_VERDICT:
3440a7ba4558SCong Wang 	case BPF_SK_SKB_VERDICT:
3441e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_SK_SKB;
3442e28784e3SAndrii Nakryiko 	case BPF_LIRC_MODE2:
3443e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_LIRC_MODE2;
3444e28784e3SAndrii Nakryiko 	case BPF_FLOW_DISSECTOR:
3445e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_FLOW_DISSECTOR;
3446e28784e3SAndrii Nakryiko 	case BPF_CGROUP_SYSCTL:
3447e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SYSCTL;
3448e28784e3SAndrii Nakryiko 	case BPF_CGROUP_GETSOCKOPT:
3449e28784e3SAndrii Nakryiko 	case BPF_CGROUP_SETSOCKOPT:
3450e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SOCKOPT;
3451de4e05caSYonghong Song 	case BPF_TRACE_ITER:
3452df86ca0dSAndrii Nakryiko 	case BPF_TRACE_RAW_TP:
3453df86ca0dSAndrii Nakryiko 	case BPF_TRACE_FENTRY:
3454df86ca0dSAndrii Nakryiko 	case BPF_TRACE_FEXIT:
3455df86ca0dSAndrii Nakryiko 	case BPF_MODIFY_RETURN:
3456de4e05caSYonghong Song 		return BPF_PROG_TYPE_TRACING;
3457df86ca0dSAndrii Nakryiko 	case BPF_LSM_MAC:
3458df86ca0dSAndrii Nakryiko 		return BPF_PROG_TYPE_LSM;
3459e9ddbb77SJakub Sitnicki 	case BPF_SK_LOOKUP:
3460e9ddbb77SJakub Sitnicki 		return BPF_PROG_TYPE_SK_LOOKUP;
3461aa8d3a71SAndrii Nakryiko 	case BPF_XDP:
3462aa8d3a71SAndrii Nakryiko 		return BPF_PROG_TYPE_XDP;
346369fd337aSStanislav Fomichev 	case BPF_LSM_CGROUP:
346469fd337aSStanislav Fomichev 		return BPF_PROG_TYPE_LSM;
3465e28784e3SAndrii Nakryiko 	default:
3466e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_UNSPEC;
3467e28784e3SAndrii Nakryiko 	}
3468e28784e3SAndrii Nakryiko }
3469e28784e3SAndrii Nakryiko 
34707dd68b32SAndrey Ignatov #define BPF_PROG_ATTACH_LAST_FIELD replace_bpf_fd
3471174a79ffSJohn Fastabend 
3472324bda9eSAlexei Starovoitov #define BPF_F_ATTACH_MASK \
34737dd68b32SAndrey Ignatov 	(BPF_F_ALLOW_OVERRIDE | BPF_F_ALLOW_MULTI | BPF_F_REPLACE)
3474324bda9eSAlexei Starovoitov 
3475f4324551SDaniel Mack static int bpf_prog_attach(const union bpf_attr *attr)
3476f4324551SDaniel Mack {
34777f677633SAlexei Starovoitov 	enum bpf_prog_type ptype;
3478f4324551SDaniel Mack 	struct bpf_prog *prog;
34797f677633SAlexei Starovoitov 	int ret;
3480f4324551SDaniel Mack 
3481f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_ATTACH))
3482f4324551SDaniel Mack 		return -EINVAL;
3483f4324551SDaniel Mack 
3484324bda9eSAlexei Starovoitov 	if (attr->attach_flags & ~BPF_F_ATTACH_MASK)
34857f677633SAlexei Starovoitov 		return -EINVAL;
34867f677633SAlexei Starovoitov 
3487e28784e3SAndrii Nakryiko 	ptype = attach_type_to_prog_type(attr->attach_type);
3488e28784e3SAndrii Nakryiko 	if (ptype == BPF_PROG_TYPE_UNSPEC)
3489b2cd1257SDavid Ahern 		return -EINVAL;
3490b2cd1257SDavid Ahern 
3491b2cd1257SDavid Ahern 	prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
3492f4324551SDaniel Mack 	if (IS_ERR(prog))
3493f4324551SDaniel Mack 		return PTR_ERR(prog);
3494f4324551SDaniel Mack 
34955e43f899SAndrey Ignatov 	if (bpf_prog_attach_check_attach_type(prog, attr->attach_type)) {
34965e43f899SAndrey Ignatov 		bpf_prog_put(prog);
34975e43f899SAndrey Ignatov 		return -EINVAL;
34985e43f899SAndrey Ignatov 	}
34995e43f899SAndrey Ignatov 
3500fdb5c453SSean Young 	switch (ptype) {
3501fdb5c453SSean Young 	case BPF_PROG_TYPE_SK_SKB:
3502fdb5c453SSean Young 	case BPF_PROG_TYPE_SK_MSG:
3503604326b4SDaniel Borkmann 		ret = sock_map_get_from_fd(attr, prog);
3504fdb5c453SSean Young 		break;
3505fdb5c453SSean Young 	case BPF_PROG_TYPE_LIRC_MODE2:
3506fdb5c453SSean Young 		ret = lirc_prog_attach(attr, prog);
3507fdb5c453SSean Young 		break;
3508d58e468bSPetar Penkov 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
3509a3fd7ceeSJakub Sitnicki 		ret = netns_bpf_prog_attach(attr, prog);
3510d58e468bSPetar Penkov 		break;
3511e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_DEVICE:
3512e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SKB:
3513e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK:
3514e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
3515e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
3516e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
3517e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SOCK_OPS:
351869fd337aSStanislav Fomichev 	case BPF_PROG_TYPE_LSM:
351969fd337aSStanislav Fomichev 		if (ptype == BPF_PROG_TYPE_LSM &&
352069fd337aSStanislav Fomichev 		    prog->expected_attach_type != BPF_LSM_CGROUP)
352169fd337aSStanislav Fomichev 			return -EINVAL;
352269fd337aSStanislav Fomichev 
3523fdb5c453SSean Young 		ret = cgroup_bpf_prog_attach(attr, ptype, prog);
3524e28784e3SAndrii Nakryiko 		break;
3525e28784e3SAndrii Nakryiko 	default:
3526e28784e3SAndrii Nakryiko 		ret = -EINVAL;
3527f4324551SDaniel Mack 	}
3528f4324551SDaniel Mack 
35297f677633SAlexei Starovoitov 	if (ret)
35307f677633SAlexei Starovoitov 		bpf_prog_put(prog);
35317f677633SAlexei Starovoitov 	return ret;
3532f4324551SDaniel Mack }
3533f4324551SDaniel Mack 
3534f4324551SDaniel Mack #define BPF_PROG_DETACH_LAST_FIELD attach_type
3535f4324551SDaniel Mack 
3536f4324551SDaniel Mack static int bpf_prog_detach(const union bpf_attr *attr)
3537f4324551SDaniel Mack {
3538324bda9eSAlexei Starovoitov 	enum bpf_prog_type ptype;
3539f4324551SDaniel Mack 
3540f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_DETACH))
3541f4324551SDaniel Mack 		return -EINVAL;
3542f4324551SDaniel Mack 
3543e28784e3SAndrii Nakryiko 	ptype = attach_type_to_prog_type(attr->attach_type);
3544e28784e3SAndrii Nakryiko 
3545e28784e3SAndrii Nakryiko 	switch (ptype) {
3546e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SK_MSG:
3547e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SK_SKB:
3548bb0de313SLorenz Bauer 		return sock_map_prog_detach(attr, ptype);
3549e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_LIRC_MODE2:
3550f4364dcfSSean Young 		return lirc_prog_detach(attr);
3551e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
35524ac2add6SLorenz Bauer 		return netns_bpf_prog_detach(attr, ptype);
3553e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_DEVICE:
3554e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SKB:
3555e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK:
3556e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
3557e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
3558e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
3559e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SOCK_OPS:
356069fd337aSStanislav Fomichev 	case BPF_PROG_TYPE_LSM:
3561e28784e3SAndrii Nakryiko 		return cgroup_bpf_prog_detach(attr, ptype);
3562f4324551SDaniel Mack 	default:
3563f4324551SDaniel Mack 		return -EINVAL;
3564f4324551SDaniel Mack 	}
3565f4324551SDaniel Mack }
356640304b2aSLawrence Brakmo 
3567b79c9fc9SStanislav Fomichev #define BPF_PROG_QUERY_LAST_FIELD query.prog_attach_flags
3568468e2f64SAlexei Starovoitov 
3569468e2f64SAlexei Starovoitov static int bpf_prog_query(const union bpf_attr *attr,
3570468e2f64SAlexei Starovoitov 			  union bpf_attr __user *uattr)
3571468e2f64SAlexei Starovoitov {
3572468e2f64SAlexei Starovoitov 	if (!capable(CAP_NET_ADMIN))
3573468e2f64SAlexei Starovoitov 		return -EPERM;
3574468e2f64SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_QUERY))
3575468e2f64SAlexei Starovoitov 		return -EINVAL;
3576468e2f64SAlexei Starovoitov 	if (attr->query.query_flags & ~BPF_F_QUERY_EFFECTIVE)
3577468e2f64SAlexei Starovoitov 		return -EINVAL;
3578468e2f64SAlexei Starovoitov 
3579468e2f64SAlexei Starovoitov 	switch (attr->query.attach_type) {
3580468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_INGRESS:
3581468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_EGRESS:
3582468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_SOCK_CREATE:
3583f5836749SStanislav Fomichev 	case BPF_CGROUP_INET_SOCK_RELEASE:
35844fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET4_BIND:
35854fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET6_BIND:
3586aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET4_POST_BIND:
3587aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET6_POST_BIND:
3588d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET4_CONNECT:
3589d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET6_CONNECT:
35901b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETPEERNAME:
35911b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETPEERNAME:
35921b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETSOCKNAME:
35931b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETSOCKNAME:
35941cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP4_SENDMSG:
35951cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP6_SENDMSG:
3596983695faSDaniel Borkmann 	case BPF_CGROUP_UDP4_RECVMSG:
3597983695faSDaniel Borkmann 	case BPF_CGROUP_UDP6_RECVMSG:
3598468e2f64SAlexei Starovoitov 	case BPF_CGROUP_SOCK_OPS:
3599ebc614f6SRoman Gushchin 	case BPF_CGROUP_DEVICE:
36007b146cebSAndrey Ignatov 	case BPF_CGROUP_SYSCTL:
36010d01da6aSStanislav Fomichev 	case BPF_CGROUP_GETSOCKOPT:
36020d01da6aSStanislav Fomichev 	case BPF_CGROUP_SETSOCKOPT:
3603b79c9fc9SStanislav Fomichev 	case BPF_LSM_CGROUP:
3604e28784e3SAndrii Nakryiko 		return cgroup_bpf_prog_query(attr, uattr);
3605f4364dcfSSean Young 	case BPF_LIRC_MODE2:
3606f4364dcfSSean Young 		return lirc_prog_query(attr, uattr);
3607118c8e9aSStanislav Fomichev 	case BPF_FLOW_DISSECTOR:
3608e9ddbb77SJakub Sitnicki 	case BPF_SK_LOOKUP:
3609a3fd7ceeSJakub Sitnicki 		return netns_bpf_prog_query(attr, uattr);
3610748cd572SDi Zhu 	case BPF_SK_SKB_STREAM_PARSER:
3611748cd572SDi Zhu 	case BPF_SK_SKB_STREAM_VERDICT:
3612748cd572SDi Zhu 	case BPF_SK_MSG_VERDICT:
3613748cd572SDi Zhu 	case BPF_SK_SKB_VERDICT:
3614748cd572SDi Zhu 		return sock_map_bpf_prog_query(attr, uattr);
3615468e2f64SAlexei Starovoitov 	default:
3616468e2f64SAlexei Starovoitov 		return -EINVAL;
3617468e2f64SAlexei Starovoitov 	}
3618468e2f64SAlexei Starovoitov }
3619f4324551SDaniel Mack 
3620b530e9e1SToke Høiland-Jørgensen #define BPF_PROG_TEST_RUN_LAST_FIELD test.batch_size
36211cf1cae9SAlexei Starovoitov 
36221cf1cae9SAlexei Starovoitov static int bpf_prog_test_run(const union bpf_attr *attr,
36231cf1cae9SAlexei Starovoitov 			     union bpf_attr __user *uattr)
36241cf1cae9SAlexei Starovoitov {
36251cf1cae9SAlexei Starovoitov 	struct bpf_prog *prog;
36261cf1cae9SAlexei Starovoitov 	int ret = -ENOTSUPP;
36271cf1cae9SAlexei Starovoitov 
36281cf1cae9SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_TEST_RUN))
36291cf1cae9SAlexei Starovoitov 		return -EINVAL;
36301cf1cae9SAlexei Starovoitov 
3631b0b9395dSStanislav Fomichev 	if ((attr->test.ctx_size_in && !attr->test.ctx_in) ||
3632b0b9395dSStanislav Fomichev 	    (!attr->test.ctx_size_in && attr->test.ctx_in))
3633b0b9395dSStanislav Fomichev 		return -EINVAL;
3634b0b9395dSStanislav Fomichev 
3635b0b9395dSStanislav Fomichev 	if ((attr->test.ctx_size_out && !attr->test.ctx_out) ||
3636b0b9395dSStanislav Fomichev 	    (!attr->test.ctx_size_out && attr->test.ctx_out))
3637b0b9395dSStanislav Fomichev 		return -EINVAL;
3638b0b9395dSStanislav Fomichev 
36391cf1cae9SAlexei Starovoitov 	prog = bpf_prog_get(attr->test.prog_fd);
36401cf1cae9SAlexei Starovoitov 	if (IS_ERR(prog))
36411cf1cae9SAlexei Starovoitov 		return PTR_ERR(prog);
36421cf1cae9SAlexei Starovoitov 
36431cf1cae9SAlexei Starovoitov 	if (prog->aux->ops->test_run)
36441cf1cae9SAlexei Starovoitov 		ret = prog->aux->ops->test_run(prog, attr, uattr);
36451cf1cae9SAlexei Starovoitov 
36461cf1cae9SAlexei Starovoitov 	bpf_prog_put(prog);
36471cf1cae9SAlexei Starovoitov 	return ret;
36481cf1cae9SAlexei Starovoitov }
36491cf1cae9SAlexei Starovoitov 
365034ad5580SMartin KaFai Lau #define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id
365134ad5580SMartin KaFai Lau 
365234ad5580SMartin KaFai Lau static int bpf_obj_get_next_id(const union bpf_attr *attr,
365334ad5580SMartin KaFai Lau 			       union bpf_attr __user *uattr,
365434ad5580SMartin KaFai Lau 			       struct idr *idr,
365534ad5580SMartin KaFai Lau 			       spinlock_t *lock)
365634ad5580SMartin KaFai Lau {
365734ad5580SMartin KaFai Lau 	u32 next_id = attr->start_id;
365834ad5580SMartin KaFai Lau 	int err = 0;
365934ad5580SMartin KaFai Lau 
366034ad5580SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX)
366134ad5580SMartin KaFai Lau 		return -EINVAL;
366234ad5580SMartin KaFai Lau 
366334ad5580SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
366434ad5580SMartin KaFai Lau 		return -EPERM;
366534ad5580SMartin KaFai Lau 
366634ad5580SMartin KaFai Lau 	next_id++;
366734ad5580SMartin KaFai Lau 	spin_lock_bh(lock);
366834ad5580SMartin KaFai Lau 	if (!idr_get_next(idr, &next_id))
366934ad5580SMartin KaFai Lau 		err = -ENOENT;
367034ad5580SMartin KaFai Lau 	spin_unlock_bh(lock);
367134ad5580SMartin KaFai Lau 
367234ad5580SMartin KaFai Lau 	if (!err)
367334ad5580SMartin KaFai Lau 		err = put_user(next_id, &uattr->next_id);
367434ad5580SMartin KaFai Lau 
367534ad5580SMartin KaFai Lau 	return err;
367634ad5580SMartin KaFai Lau }
367734ad5580SMartin KaFai Lau 
36786086d29dSYonghong Song struct bpf_map *bpf_map_get_curr_or_next(u32 *id)
36796086d29dSYonghong Song {
36806086d29dSYonghong Song 	struct bpf_map *map;
36816086d29dSYonghong Song 
36826086d29dSYonghong Song 	spin_lock_bh(&map_idr_lock);
36836086d29dSYonghong Song again:
36846086d29dSYonghong Song 	map = idr_get_next(&map_idr, id);
36856086d29dSYonghong Song 	if (map) {
36866086d29dSYonghong Song 		map = __bpf_map_inc_not_zero(map, false);
36876086d29dSYonghong Song 		if (IS_ERR(map)) {
36886086d29dSYonghong Song 			(*id)++;
36896086d29dSYonghong Song 			goto again;
36906086d29dSYonghong Song 		}
36916086d29dSYonghong Song 	}
36926086d29dSYonghong Song 	spin_unlock_bh(&map_idr_lock);
36936086d29dSYonghong Song 
36946086d29dSYonghong Song 	return map;
36956086d29dSYonghong Song }
36966086d29dSYonghong Song 
3697a228a64fSAlexei Starovoitov struct bpf_prog *bpf_prog_get_curr_or_next(u32 *id)
3698a228a64fSAlexei Starovoitov {
3699a228a64fSAlexei Starovoitov 	struct bpf_prog *prog;
3700a228a64fSAlexei Starovoitov 
3701a228a64fSAlexei Starovoitov 	spin_lock_bh(&prog_idr_lock);
3702a228a64fSAlexei Starovoitov again:
3703a228a64fSAlexei Starovoitov 	prog = idr_get_next(&prog_idr, id);
3704a228a64fSAlexei Starovoitov 	if (prog) {
3705a228a64fSAlexei Starovoitov 		prog = bpf_prog_inc_not_zero(prog);
3706a228a64fSAlexei Starovoitov 		if (IS_ERR(prog)) {
3707a228a64fSAlexei Starovoitov 			(*id)++;
3708a228a64fSAlexei Starovoitov 			goto again;
3709a228a64fSAlexei Starovoitov 		}
3710a228a64fSAlexei Starovoitov 	}
3711a228a64fSAlexei Starovoitov 	spin_unlock_bh(&prog_idr_lock);
3712a228a64fSAlexei Starovoitov 
3713a228a64fSAlexei Starovoitov 	return prog;
3714a228a64fSAlexei Starovoitov }
3715a228a64fSAlexei Starovoitov 
3716b16d9aa4SMartin KaFai Lau #define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id
3717b16d9aa4SMartin KaFai Lau 
37187e6897f9SBjörn Töpel struct bpf_prog *bpf_prog_by_id(u32 id)
37197e6897f9SBjörn Töpel {
37207e6897f9SBjörn Töpel 	struct bpf_prog *prog;
37217e6897f9SBjörn Töpel 
37227e6897f9SBjörn Töpel 	if (!id)
37237e6897f9SBjörn Töpel 		return ERR_PTR(-ENOENT);
37247e6897f9SBjörn Töpel 
37257e6897f9SBjörn Töpel 	spin_lock_bh(&prog_idr_lock);
37267e6897f9SBjörn Töpel 	prog = idr_find(&prog_idr, id);
37277e6897f9SBjörn Töpel 	if (prog)
37287e6897f9SBjörn Töpel 		prog = bpf_prog_inc_not_zero(prog);
37297e6897f9SBjörn Töpel 	else
37307e6897f9SBjörn Töpel 		prog = ERR_PTR(-ENOENT);
37317e6897f9SBjörn Töpel 	spin_unlock_bh(&prog_idr_lock);
37327e6897f9SBjörn Töpel 	return prog;
37337e6897f9SBjörn Töpel }
37347e6897f9SBjörn Töpel 
3735b16d9aa4SMartin KaFai Lau static int bpf_prog_get_fd_by_id(const union bpf_attr *attr)
3736b16d9aa4SMartin KaFai Lau {
3737b16d9aa4SMartin KaFai Lau 	struct bpf_prog *prog;
3738b16d9aa4SMartin KaFai Lau 	u32 id = attr->prog_id;
3739b16d9aa4SMartin KaFai Lau 	int fd;
3740b16d9aa4SMartin KaFai Lau 
3741b16d9aa4SMartin KaFai Lau 	if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID))
3742b16d9aa4SMartin KaFai Lau 		return -EINVAL;
3743b16d9aa4SMartin KaFai Lau 
3744b16d9aa4SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
3745b16d9aa4SMartin KaFai Lau 		return -EPERM;
3746b16d9aa4SMartin KaFai Lau 
37477e6897f9SBjörn Töpel 	prog = bpf_prog_by_id(id);
3748b16d9aa4SMartin KaFai Lau 	if (IS_ERR(prog))
3749b16d9aa4SMartin KaFai Lau 		return PTR_ERR(prog);
3750b16d9aa4SMartin KaFai Lau 
3751b16d9aa4SMartin KaFai Lau 	fd = bpf_prog_new_fd(prog);
3752b16d9aa4SMartin KaFai Lau 	if (fd < 0)
3753b16d9aa4SMartin KaFai Lau 		bpf_prog_put(prog);
3754b16d9aa4SMartin KaFai Lau 
3755b16d9aa4SMartin KaFai Lau 	return fd;
3756b16d9aa4SMartin KaFai Lau }
3757b16d9aa4SMartin KaFai Lau 
37586e71b04aSChenbo Feng #define BPF_MAP_GET_FD_BY_ID_LAST_FIELD open_flags
3759bd5f5f4eSMartin KaFai Lau 
3760bd5f5f4eSMartin KaFai Lau static int bpf_map_get_fd_by_id(const union bpf_attr *attr)
3761bd5f5f4eSMartin KaFai Lau {
3762bd5f5f4eSMartin KaFai Lau 	struct bpf_map *map;
3763bd5f5f4eSMartin KaFai Lau 	u32 id = attr->map_id;
37646e71b04aSChenbo Feng 	int f_flags;
3765bd5f5f4eSMartin KaFai Lau 	int fd;
3766bd5f5f4eSMartin KaFai Lau 
37676e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_MAP_GET_FD_BY_ID) ||
37686e71b04aSChenbo Feng 	    attr->open_flags & ~BPF_OBJ_FLAG_MASK)
3769bd5f5f4eSMartin KaFai Lau 		return -EINVAL;
3770bd5f5f4eSMartin KaFai Lau 
3771bd5f5f4eSMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
3772bd5f5f4eSMartin KaFai Lau 		return -EPERM;
3773bd5f5f4eSMartin KaFai Lau 
37746e71b04aSChenbo Feng 	f_flags = bpf_get_file_flag(attr->open_flags);
37756e71b04aSChenbo Feng 	if (f_flags < 0)
37766e71b04aSChenbo Feng 		return f_flags;
37776e71b04aSChenbo Feng 
3778bd5f5f4eSMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
3779bd5f5f4eSMartin KaFai Lau 	map = idr_find(&map_idr, id);
3780bd5f5f4eSMartin KaFai Lau 	if (map)
3781b0e4701cSStanislav Fomichev 		map = __bpf_map_inc_not_zero(map, true);
3782bd5f5f4eSMartin KaFai Lau 	else
3783bd5f5f4eSMartin KaFai Lau 		map = ERR_PTR(-ENOENT);
3784bd5f5f4eSMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
3785bd5f5f4eSMartin KaFai Lau 
3786bd5f5f4eSMartin KaFai Lau 	if (IS_ERR(map))
3787bd5f5f4eSMartin KaFai Lau 		return PTR_ERR(map);
3788bd5f5f4eSMartin KaFai Lau 
37896e71b04aSChenbo Feng 	fd = bpf_map_new_fd(map, f_flags);
3790bd5f5f4eSMartin KaFai Lau 	if (fd < 0)
3791781e6282SPeng Sun 		bpf_map_put_with_uref(map);
3792bd5f5f4eSMartin KaFai Lau 
3793bd5f5f4eSMartin KaFai Lau 	return fd;
3794bd5f5f4eSMartin KaFai Lau }
3795bd5f5f4eSMartin KaFai Lau 
37967105e828SDaniel Borkmann static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog,
3797d8eca5bbSDaniel Borkmann 					      unsigned long addr, u32 *off,
3798d8eca5bbSDaniel Borkmann 					      u32 *type)
37997105e828SDaniel Borkmann {
3800d8eca5bbSDaniel Borkmann 	const struct bpf_map *map;
38017105e828SDaniel Borkmann 	int i;
38027105e828SDaniel Borkmann 
3803984fe94fSYiFei Zhu 	mutex_lock(&prog->aux->used_maps_mutex);
3804d8eca5bbSDaniel Borkmann 	for (i = 0, *off = 0; i < prog->aux->used_map_cnt; i++) {
3805d8eca5bbSDaniel Borkmann 		map = prog->aux->used_maps[i];
3806d8eca5bbSDaniel Borkmann 		if (map == (void *)addr) {
3807d8eca5bbSDaniel Borkmann 			*type = BPF_PSEUDO_MAP_FD;
3808984fe94fSYiFei Zhu 			goto out;
3809d8eca5bbSDaniel Borkmann 		}
3810d8eca5bbSDaniel Borkmann 		if (!map->ops->map_direct_value_meta)
3811d8eca5bbSDaniel Borkmann 			continue;
3812d8eca5bbSDaniel Borkmann 		if (!map->ops->map_direct_value_meta(map, addr, off)) {
3813d8eca5bbSDaniel Borkmann 			*type = BPF_PSEUDO_MAP_VALUE;
3814984fe94fSYiFei Zhu 			goto out;
3815d8eca5bbSDaniel Borkmann 		}
3816d8eca5bbSDaniel Borkmann 	}
3817984fe94fSYiFei Zhu 	map = NULL;
3818d8eca5bbSDaniel Borkmann 
3819984fe94fSYiFei Zhu out:
3820984fe94fSYiFei Zhu 	mutex_unlock(&prog->aux->used_maps_mutex);
3821984fe94fSYiFei Zhu 	return map;
38227105e828SDaniel Borkmann }
38237105e828SDaniel Borkmann 
382463960260SKees Cook static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog,
382563960260SKees Cook 					      const struct cred *f_cred)
38267105e828SDaniel Borkmann {
38277105e828SDaniel Borkmann 	const struct bpf_map *map;
38287105e828SDaniel Borkmann 	struct bpf_insn *insns;
3829d8eca5bbSDaniel Borkmann 	u32 off, type;
38307105e828SDaniel Borkmann 	u64 imm;
383129fcb05bSAndrii Nakryiko 	u8 code;
38327105e828SDaniel Borkmann 	int i;
38337105e828SDaniel Borkmann 
38347105e828SDaniel Borkmann 	insns = kmemdup(prog->insnsi, bpf_prog_insn_size(prog),
38357105e828SDaniel Borkmann 			GFP_USER);
38367105e828SDaniel Borkmann 	if (!insns)
38377105e828SDaniel Borkmann 		return insns;
38387105e828SDaniel Borkmann 
38397105e828SDaniel Borkmann 	for (i = 0; i < prog->len; i++) {
384029fcb05bSAndrii Nakryiko 		code = insns[i].code;
384129fcb05bSAndrii Nakryiko 
384229fcb05bSAndrii Nakryiko 		if (code == (BPF_JMP | BPF_TAIL_CALL)) {
38437105e828SDaniel Borkmann 			insns[i].code = BPF_JMP | BPF_CALL;
38447105e828SDaniel Borkmann 			insns[i].imm = BPF_FUNC_tail_call;
38457105e828SDaniel Borkmann 			/* fall-through */
38467105e828SDaniel Borkmann 		}
384729fcb05bSAndrii Nakryiko 		if (code == (BPF_JMP | BPF_CALL) ||
384829fcb05bSAndrii Nakryiko 		    code == (BPF_JMP | BPF_CALL_ARGS)) {
384929fcb05bSAndrii Nakryiko 			if (code == (BPF_JMP | BPF_CALL_ARGS))
38507105e828SDaniel Borkmann 				insns[i].code = BPF_JMP | BPF_CALL;
385163960260SKees Cook 			if (!bpf_dump_raw_ok(f_cred))
38527105e828SDaniel Borkmann 				insns[i].imm = 0;
38537105e828SDaniel Borkmann 			continue;
38547105e828SDaniel Borkmann 		}
385529fcb05bSAndrii Nakryiko 		if (BPF_CLASS(code) == BPF_LDX && BPF_MODE(code) == BPF_PROBE_MEM) {
385629fcb05bSAndrii Nakryiko 			insns[i].code = BPF_LDX | BPF_SIZE(code) | BPF_MEM;
385729fcb05bSAndrii Nakryiko 			continue;
385829fcb05bSAndrii Nakryiko 		}
38597105e828SDaniel Borkmann 
386029fcb05bSAndrii Nakryiko 		if (code != (BPF_LD | BPF_IMM | BPF_DW))
38617105e828SDaniel Borkmann 			continue;
38627105e828SDaniel Borkmann 
38637105e828SDaniel Borkmann 		imm = ((u64)insns[i + 1].imm << 32) | (u32)insns[i].imm;
3864d8eca5bbSDaniel Borkmann 		map = bpf_map_from_imm(prog, imm, &off, &type);
38657105e828SDaniel Borkmann 		if (map) {
3866d8eca5bbSDaniel Borkmann 			insns[i].src_reg = type;
38677105e828SDaniel Borkmann 			insns[i].imm = map->id;
3868d8eca5bbSDaniel Borkmann 			insns[i + 1].imm = off;
38697105e828SDaniel Borkmann 			continue;
38707105e828SDaniel Borkmann 		}
38717105e828SDaniel Borkmann 	}
38727105e828SDaniel Borkmann 
38737105e828SDaniel Borkmann 	return insns;
38747105e828SDaniel Borkmann }
38757105e828SDaniel Borkmann 
3876c454a46bSMartin KaFai Lau static int set_info_rec_size(struct bpf_prog_info *info)
3877c454a46bSMartin KaFai Lau {
3878c454a46bSMartin KaFai Lau 	/*
3879c454a46bSMartin KaFai Lau 	 * Ensure info.*_rec_size is the same as kernel expected size
3880c454a46bSMartin KaFai Lau 	 *
3881c454a46bSMartin KaFai Lau 	 * or
3882c454a46bSMartin KaFai Lau 	 *
3883c454a46bSMartin KaFai Lau 	 * Only allow zero *_rec_size if both _rec_size and _cnt are
3884c454a46bSMartin KaFai Lau 	 * zero.  In this case, the kernel will set the expected
3885c454a46bSMartin KaFai Lau 	 * _rec_size back to the info.
3886c454a46bSMartin KaFai Lau 	 */
3887c454a46bSMartin KaFai Lau 
388811d8b82dSYonghong Song 	if ((info->nr_func_info || info->func_info_rec_size) &&
3889c454a46bSMartin KaFai Lau 	    info->func_info_rec_size != sizeof(struct bpf_func_info))
3890c454a46bSMartin KaFai Lau 		return -EINVAL;
3891c454a46bSMartin KaFai Lau 
389211d8b82dSYonghong Song 	if ((info->nr_line_info || info->line_info_rec_size) &&
3893c454a46bSMartin KaFai Lau 	    info->line_info_rec_size != sizeof(struct bpf_line_info))
3894c454a46bSMartin KaFai Lau 		return -EINVAL;
3895c454a46bSMartin KaFai Lau 
389611d8b82dSYonghong Song 	if ((info->nr_jited_line_info || info->jited_line_info_rec_size) &&
3897c454a46bSMartin KaFai Lau 	    info->jited_line_info_rec_size != sizeof(__u64))
3898c454a46bSMartin KaFai Lau 		return -EINVAL;
3899c454a46bSMartin KaFai Lau 
3900c454a46bSMartin KaFai Lau 	info->func_info_rec_size = sizeof(struct bpf_func_info);
3901c454a46bSMartin KaFai Lau 	info->line_info_rec_size = sizeof(struct bpf_line_info);
3902c454a46bSMartin KaFai Lau 	info->jited_line_info_rec_size = sizeof(__u64);
3903c454a46bSMartin KaFai Lau 
3904c454a46bSMartin KaFai Lau 	return 0;
3905c454a46bSMartin KaFai Lau }
3906c454a46bSMartin KaFai Lau 
390763960260SKees Cook static int bpf_prog_get_info_by_fd(struct file *file,
390863960260SKees Cook 				   struct bpf_prog *prog,
39091e270976SMartin KaFai Lau 				   const union bpf_attr *attr,
39101e270976SMartin KaFai Lau 				   union bpf_attr __user *uattr)
39111e270976SMartin KaFai Lau {
39121e270976SMartin KaFai Lau 	struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info);
39136644aabbSStanislav Fomichev 	struct btf *attach_btf = bpf_prog_get_target_btf(prog);
39145c6f2588SGreg Kroah-Hartman 	struct bpf_prog_info info;
39151e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
391661a0abaeSEric Dumazet 	struct bpf_prog_kstats stats;
39171e270976SMartin KaFai Lau 	char __user *uinsns;
39181e270976SMartin KaFai Lau 	u32 ulen;
39191e270976SMartin KaFai Lau 	int err;
39201e270976SMartin KaFai Lau 
3921af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len);
39221e270976SMartin KaFai Lau 	if (err)
39231e270976SMartin KaFai Lau 		return err;
39241e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
39251e270976SMartin KaFai Lau 
39265c6f2588SGreg Kroah-Hartman 	memset(&info, 0, sizeof(info));
39271e270976SMartin KaFai Lau 	if (copy_from_user(&info, uinfo, info_len))
392889b09689SDaniel Borkmann 		return -EFAULT;
39291e270976SMartin KaFai Lau 
39301e270976SMartin KaFai Lau 	info.type = prog->type;
39311e270976SMartin KaFai Lau 	info.id = prog->aux->id;
3932cb4d2b3fSMartin KaFai Lau 	info.load_time = prog->aux->load_time;
3933cb4d2b3fSMartin KaFai Lau 	info.created_by_uid = from_kuid_munged(current_user_ns(),
3934cb4d2b3fSMartin KaFai Lau 					       prog->aux->user->uid);
3935b85fab0eSJiri Olsa 	info.gpl_compatible = prog->gpl_compatible;
39361e270976SMartin KaFai Lau 
39371e270976SMartin KaFai Lau 	memcpy(info.tag, prog->tag, sizeof(prog->tag));
3938cb4d2b3fSMartin KaFai Lau 	memcpy(info.name, prog->aux->name, sizeof(prog->aux->name));
3939cb4d2b3fSMartin KaFai Lau 
3940984fe94fSYiFei Zhu 	mutex_lock(&prog->aux->used_maps_mutex);
3941cb4d2b3fSMartin KaFai Lau 	ulen = info.nr_map_ids;
3942cb4d2b3fSMartin KaFai Lau 	info.nr_map_ids = prog->aux->used_map_cnt;
3943cb4d2b3fSMartin KaFai Lau 	ulen = min_t(u32, info.nr_map_ids, ulen);
3944cb4d2b3fSMartin KaFai Lau 	if (ulen) {
3945721e08daSMartin KaFai Lau 		u32 __user *user_map_ids = u64_to_user_ptr(info.map_ids);
3946cb4d2b3fSMartin KaFai Lau 		u32 i;
3947cb4d2b3fSMartin KaFai Lau 
3948cb4d2b3fSMartin KaFai Lau 		for (i = 0; i < ulen; i++)
3949cb4d2b3fSMartin KaFai Lau 			if (put_user(prog->aux->used_maps[i]->id,
3950984fe94fSYiFei Zhu 				     &user_map_ids[i])) {
3951984fe94fSYiFei Zhu 				mutex_unlock(&prog->aux->used_maps_mutex);
3952cb4d2b3fSMartin KaFai Lau 				return -EFAULT;
3953cb4d2b3fSMartin KaFai Lau 			}
3954984fe94fSYiFei Zhu 	}
3955984fe94fSYiFei Zhu 	mutex_unlock(&prog->aux->used_maps_mutex);
39561e270976SMartin KaFai Lau 
3957c454a46bSMartin KaFai Lau 	err = set_info_rec_size(&info);
3958c454a46bSMartin KaFai Lau 	if (err)
3959c454a46bSMartin KaFai Lau 		return err;
39607337224fSMartin KaFai Lau 
39615f8f8b93SAlexei Starovoitov 	bpf_prog_get_stats(prog, &stats);
39625f8f8b93SAlexei Starovoitov 	info.run_time_ns = stats.nsecs;
39635f8f8b93SAlexei Starovoitov 	info.run_cnt = stats.cnt;
39649ed9e9baSAlexei Starovoitov 	info.recursion_misses = stats.misses;
39655f8f8b93SAlexei Starovoitov 
3966aba64c7dSDave Marchevsky 	info.verified_insns = prog->aux->verified_insns;
3967aba64c7dSDave Marchevsky 
39682c78ee89SAlexei Starovoitov 	if (!bpf_capable()) {
39691e270976SMartin KaFai Lau 		info.jited_prog_len = 0;
39701e270976SMartin KaFai Lau 		info.xlated_prog_len = 0;
3971dbecd738SSandipan Das 		info.nr_jited_ksyms = 0;
397228c2fae7SDaniel Borkmann 		info.nr_jited_func_lens = 0;
397311d8b82dSYonghong Song 		info.nr_func_info = 0;
397411d8b82dSYonghong Song 		info.nr_line_info = 0;
397511d8b82dSYonghong Song 		info.nr_jited_line_info = 0;
39761e270976SMartin KaFai Lau 		goto done;
39771e270976SMartin KaFai Lau 	}
39781e270976SMartin KaFai Lau 
39791e270976SMartin KaFai Lau 	ulen = info.xlated_prog_len;
39809975a54bSDaniel Borkmann 	info.xlated_prog_len = bpf_prog_insn_size(prog);
39811e270976SMartin KaFai Lau 	if (info.xlated_prog_len && ulen) {
39827105e828SDaniel Borkmann 		struct bpf_insn *insns_sanitized;
39837105e828SDaniel Borkmann 		bool fault;
39847105e828SDaniel Borkmann 
398563960260SKees Cook 		if (prog->blinded && !bpf_dump_raw_ok(file->f_cred)) {
39867105e828SDaniel Borkmann 			info.xlated_prog_insns = 0;
39877105e828SDaniel Borkmann 			goto done;
39887105e828SDaniel Borkmann 		}
398963960260SKees Cook 		insns_sanitized = bpf_insn_prepare_dump(prog, file->f_cred);
39907105e828SDaniel Borkmann 		if (!insns_sanitized)
39917105e828SDaniel Borkmann 			return -ENOMEM;
39921e270976SMartin KaFai Lau 		uinsns = u64_to_user_ptr(info.xlated_prog_insns);
39931e270976SMartin KaFai Lau 		ulen = min_t(u32, info.xlated_prog_len, ulen);
39947105e828SDaniel Borkmann 		fault = copy_to_user(uinsns, insns_sanitized, ulen);
39957105e828SDaniel Borkmann 		kfree(insns_sanitized);
39967105e828SDaniel Borkmann 		if (fault)
39971e270976SMartin KaFai Lau 			return -EFAULT;
39981e270976SMartin KaFai Lau 	}
39991e270976SMartin KaFai Lau 
4000675fc275SJakub Kicinski 	if (bpf_prog_is_dev_bound(prog->aux)) {
4001675fc275SJakub Kicinski 		err = bpf_prog_offload_info_fill(&info, prog);
4002675fc275SJakub Kicinski 		if (err)
4003675fc275SJakub Kicinski 			return err;
4004fcfb126dSJiong Wang 		goto done;
4005fcfb126dSJiong Wang 	}
4006fcfb126dSJiong Wang 
4007fcfb126dSJiong Wang 	/* NOTE: the following code is supposed to be skipped for offload.
4008fcfb126dSJiong Wang 	 * bpf_prog_offload_info_fill() is the place to fill similar fields
4009fcfb126dSJiong Wang 	 * for offload.
4010fcfb126dSJiong Wang 	 */
4011fcfb126dSJiong Wang 	ulen = info.jited_prog_len;
40124d56a76eSSandipan Das 	if (prog->aux->func_cnt) {
40134d56a76eSSandipan Das 		u32 i;
40144d56a76eSSandipan Das 
40154d56a76eSSandipan Das 		info.jited_prog_len = 0;
40164d56a76eSSandipan Das 		for (i = 0; i < prog->aux->func_cnt; i++)
40174d56a76eSSandipan Das 			info.jited_prog_len += prog->aux->func[i]->jited_len;
40184d56a76eSSandipan Das 	} else {
4019fcfb126dSJiong Wang 		info.jited_prog_len = prog->jited_len;
40204d56a76eSSandipan Das 	}
40214d56a76eSSandipan Das 
4022fcfb126dSJiong Wang 	if (info.jited_prog_len && ulen) {
402363960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
4024fcfb126dSJiong Wang 			uinsns = u64_to_user_ptr(info.jited_prog_insns);
4025fcfb126dSJiong Wang 			ulen = min_t(u32, info.jited_prog_len, ulen);
40264d56a76eSSandipan Das 
40274d56a76eSSandipan Das 			/* for multi-function programs, copy the JITed
40284d56a76eSSandipan Das 			 * instructions for all the functions
40294d56a76eSSandipan Das 			 */
40304d56a76eSSandipan Das 			if (prog->aux->func_cnt) {
40314d56a76eSSandipan Das 				u32 len, free, i;
40324d56a76eSSandipan Das 				u8 *img;
40334d56a76eSSandipan Das 
40344d56a76eSSandipan Das 				free = ulen;
40354d56a76eSSandipan Das 				for (i = 0; i < prog->aux->func_cnt; i++) {
40364d56a76eSSandipan Das 					len = prog->aux->func[i]->jited_len;
40374d56a76eSSandipan Das 					len = min_t(u32, len, free);
40384d56a76eSSandipan Das 					img = (u8 *) prog->aux->func[i]->bpf_func;
40394d56a76eSSandipan Das 					if (copy_to_user(uinsns, img, len))
40404d56a76eSSandipan Das 						return -EFAULT;
40414d56a76eSSandipan Das 					uinsns += len;
40424d56a76eSSandipan Das 					free -= len;
40434d56a76eSSandipan Das 					if (!free)
40444d56a76eSSandipan Das 						break;
40454d56a76eSSandipan Das 				}
40464d56a76eSSandipan Das 			} else {
4047fcfb126dSJiong Wang 				if (copy_to_user(uinsns, prog->bpf_func, ulen))
4048fcfb126dSJiong Wang 					return -EFAULT;
40494d56a76eSSandipan Das 			}
4050fcfb126dSJiong Wang 		} else {
4051fcfb126dSJiong Wang 			info.jited_prog_insns = 0;
4052fcfb126dSJiong Wang 		}
4053675fc275SJakub Kicinski 	}
4054675fc275SJakub Kicinski 
4055dbecd738SSandipan Das 	ulen = info.nr_jited_ksyms;
4056ff1889fcSSong Liu 	info.nr_jited_ksyms = prog->aux->func_cnt ? : 1;
40577a5725ddSSong Liu 	if (ulen) {
405863960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
4059ff1889fcSSong Liu 			unsigned long ksym_addr;
4060dbecd738SSandipan Das 			u64 __user *user_ksyms;
4061dbecd738SSandipan Das 			u32 i;
4062dbecd738SSandipan Das 
4063dbecd738SSandipan Das 			/* copy the address of the kernel symbol
4064dbecd738SSandipan Das 			 * corresponding to each function
4065dbecd738SSandipan Das 			 */
4066dbecd738SSandipan Das 			ulen = min_t(u32, info.nr_jited_ksyms, ulen);
4067dbecd738SSandipan Das 			user_ksyms = u64_to_user_ptr(info.jited_ksyms);
4068ff1889fcSSong Liu 			if (prog->aux->func_cnt) {
4069dbecd738SSandipan Das 				for (i = 0; i < ulen; i++) {
4070ff1889fcSSong Liu 					ksym_addr = (unsigned long)
4071ff1889fcSSong Liu 						prog->aux->func[i]->bpf_func;
4072ff1889fcSSong Liu 					if (put_user((u64) ksym_addr,
4073ff1889fcSSong Liu 						     &user_ksyms[i]))
4074ff1889fcSSong Liu 						return -EFAULT;
4075ff1889fcSSong Liu 				}
4076ff1889fcSSong Liu 			} else {
4077ff1889fcSSong Liu 				ksym_addr = (unsigned long) prog->bpf_func;
4078ff1889fcSSong Liu 				if (put_user((u64) ksym_addr, &user_ksyms[0]))
4079dbecd738SSandipan Das 					return -EFAULT;
4080dbecd738SSandipan Das 			}
4081dbecd738SSandipan Das 		} else {
4082dbecd738SSandipan Das 			info.jited_ksyms = 0;
4083dbecd738SSandipan Das 		}
4084dbecd738SSandipan Das 	}
4085dbecd738SSandipan Das 
4086815581c1SSandipan Das 	ulen = info.nr_jited_func_lens;
4087ff1889fcSSong Liu 	info.nr_jited_func_lens = prog->aux->func_cnt ? : 1;
40887a5725ddSSong Liu 	if (ulen) {
408963960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
4090815581c1SSandipan Das 			u32 __user *user_lens;
4091815581c1SSandipan Das 			u32 func_len, i;
4092815581c1SSandipan Das 
4093815581c1SSandipan Das 			/* copy the JITed image lengths for each function */
4094815581c1SSandipan Das 			ulen = min_t(u32, info.nr_jited_func_lens, ulen);
4095815581c1SSandipan Das 			user_lens = u64_to_user_ptr(info.jited_func_lens);
4096ff1889fcSSong Liu 			if (prog->aux->func_cnt) {
4097815581c1SSandipan Das 				for (i = 0; i < ulen; i++) {
4098ff1889fcSSong Liu 					func_len =
4099ff1889fcSSong Liu 						prog->aux->func[i]->jited_len;
4100815581c1SSandipan Das 					if (put_user(func_len, &user_lens[i]))
4101815581c1SSandipan Das 						return -EFAULT;
4102815581c1SSandipan Das 				}
4103815581c1SSandipan Das 			} else {
4104ff1889fcSSong Liu 				func_len = prog->jited_len;
4105ff1889fcSSong Liu 				if (put_user(func_len, &user_lens[0]))
4106ff1889fcSSong Liu 					return -EFAULT;
4107ff1889fcSSong Liu 			}
4108ff1889fcSSong Liu 		} else {
4109815581c1SSandipan Das 			info.jited_func_lens = 0;
4110815581c1SSandipan Das 		}
4111815581c1SSandipan Das 	}
4112815581c1SSandipan Das 
41137337224fSMartin KaFai Lau 	if (prog->aux->btf)
411422dc4a0fSAndrii Nakryiko 		info.btf_id = btf_obj_id(prog->aux->btf);
4115b79c9fc9SStanislav Fomichev 	info.attach_btf_id = prog->aux->attach_btf_id;
41166644aabbSStanislav Fomichev 	if (attach_btf)
41176644aabbSStanislav Fomichev 		info.attach_btf_obj_id = btf_obj_id(attach_btf);
4118838e9690SYonghong Song 
411911d8b82dSYonghong Song 	ulen = info.nr_func_info;
412011d8b82dSYonghong Song 	info.nr_func_info = prog->aux->func_info_cnt;
412111d8b82dSYonghong Song 	if (info.nr_func_info && ulen) {
4122838e9690SYonghong Song 		char __user *user_finfo;
4123838e9690SYonghong Song 
4124838e9690SYonghong Song 		user_finfo = u64_to_user_ptr(info.func_info);
412511d8b82dSYonghong Song 		ulen = min_t(u32, info.nr_func_info, ulen);
4126ba64e7d8SYonghong Song 		if (copy_to_user(user_finfo, prog->aux->func_info,
41277337224fSMartin KaFai Lau 				 info.func_info_rec_size * ulen))
4128838e9690SYonghong Song 			return -EFAULT;
4129838e9690SYonghong Song 	}
4130838e9690SYonghong Song 
413111d8b82dSYonghong Song 	ulen = info.nr_line_info;
413211d8b82dSYonghong Song 	info.nr_line_info = prog->aux->nr_linfo;
413311d8b82dSYonghong Song 	if (info.nr_line_info && ulen) {
4134c454a46bSMartin KaFai Lau 		__u8 __user *user_linfo;
4135c454a46bSMartin KaFai Lau 
4136c454a46bSMartin KaFai Lau 		user_linfo = u64_to_user_ptr(info.line_info);
413711d8b82dSYonghong Song 		ulen = min_t(u32, info.nr_line_info, ulen);
4138c454a46bSMartin KaFai Lau 		if (copy_to_user(user_linfo, prog->aux->linfo,
4139c454a46bSMartin KaFai Lau 				 info.line_info_rec_size * ulen))
4140c454a46bSMartin KaFai Lau 			return -EFAULT;
4141c454a46bSMartin KaFai Lau 	}
4142c454a46bSMartin KaFai Lau 
414311d8b82dSYonghong Song 	ulen = info.nr_jited_line_info;
4144c454a46bSMartin KaFai Lau 	if (prog->aux->jited_linfo)
414511d8b82dSYonghong Song 		info.nr_jited_line_info = prog->aux->nr_linfo;
4146c454a46bSMartin KaFai Lau 	else
414711d8b82dSYonghong Song 		info.nr_jited_line_info = 0;
414811d8b82dSYonghong Song 	if (info.nr_jited_line_info && ulen) {
414963960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
41502cd00852SPu Lehui 			unsigned long line_addr;
4151c454a46bSMartin KaFai Lau 			__u64 __user *user_linfo;
4152c454a46bSMartin KaFai Lau 			u32 i;
4153c454a46bSMartin KaFai Lau 
4154c454a46bSMartin KaFai Lau 			user_linfo = u64_to_user_ptr(info.jited_line_info);
415511d8b82dSYonghong Song 			ulen = min_t(u32, info.nr_jited_line_info, ulen);
4156c454a46bSMartin KaFai Lau 			for (i = 0; i < ulen; i++) {
41572cd00852SPu Lehui 				line_addr = (unsigned long)prog->aux->jited_linfo[i];
41582cd00852SPu Lehui 				if (put_user((__u64)line_addr, &user_linfo[i]))
4159c454a46bSMartin KaFai Lau 					return -EFAULT;
4160c454a46bSMartin KaFai Lau 			}
4161c454a46bSMartin KaFai Lau 		} else {
4162c454a46bSMartin KaFai Lau 			info.jited_line_info = 0;
4163c454a46bSMartin KaFai Lau 		}
4164c454a46bSMartin KaFai Lau 	}
4165c454a46bSMartin KaFai Lau 
4166c872bdb3SSong Liu 	ulen = info.nr_prog_tags;
4167c872bdb3SSong Liu 	info.nr_prog_tags = prog->aux->func_cnt ? : 1;
4168c872bdb3SSong Liu 	if (ulen) {
4169c872bdb3SSong Liu 		__u8 __user (*user_prog_tags)[BPF_TAG_SIZE];
4170c872bdb3SSong Liu 		u32 i;
4171c872bdb3SSong Liu 
4172c872bdb3SSong Liu 		user_prog_tags = u64_to_user_ptr(info.prog_tags);
4173c872bdb3SSong Liu 		ulen = min_t(u32, info.nr_prog_tags, ulen);
4174c872bdb3SSong Liu 		if (prog->aux->func_cnt) {
4175c872bdb3SSong Liu 			for (i = 0; i < ulen; i++) {
4176c872bdb3SSong Liu 				if (copy_to_user(user_prog_tags[i],
4177c872bdb3SSong Liu 						 prog->aux->func[i]->tag,
4178c872bdb3SSong Liu 						 BPF_TAG_SIZE))
4179c872bdb3SSong Liu 					return -EFAULT;
4180c872bdb3SSong Liu 			}
4181c872bdb3SSong Liu 		} else {
4182c872bdb3SSong Liu 			if (copy_to_user(user_prog_tags[0],
4183c872bdb3SSong Liu 					 prog->tag, BPF_TAG_SIZE))
4184c872bdb3SSong Liu 				return -EFAULT;
4185c872bdb3SSong Liu 		}
4186c872bdb3SSong Liu 	}
4187c872bdb3SSong Liu 
41881e270976SMartin KaFai Lau done:
41891e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
41901e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
41911e270976SMartin KaFai Lau 		return -EFAULT;
41921e270976SMartin KaFai Lau 
41931e270976SMartin KaFai Lau 	return 0;
41941e270976SMartin KaFai Lau }
41951e270976SMartin KaFai Lau 
419663960260SKees Cook static int bpf_map_get_info_by_fd(struct file *file,
419763960260SKees Cook 				  struct bpf_map *map,
41981e270976SMartin KaFai Lau 				  const union bpf_attr *attr,
41991e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
42001e270976SMartin KaFai Lau {
42011e270976SMartin KaFai Lau 	struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info);
42025c6f2588SGreg Kroah-Hartman 	struct bpf_map_info info;
42031e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
42041e270976SMartin KaFai Lau 	int err;
42051e270976SMartin KaFai Lau 
4206af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len);
42071e270976SMartin KaFai Lau 	if (err)
42081e270976SMartin KaFai Lau 		return err;
42091e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
42101e270976SMartin KaFai Lau 
42115c6f2588SGreg Kroah-Hartman 	memset(&info, 0, sizeof(info));
42121e270976SMartin KaFai Lau 	info.type = map->map_type;
42131e270976SMartin KaFai Lau 	info.id = map->id;
42141e270976SMartin KaFai Lau 	info.key_size = map->key_size;
42151e270976SMartin KaFai Lau 	info.value_size = map->value_size;
42161e270976SMartin KaFai Lau 	info.max_entries = map->max_entries;
42171e270976SMartin KaFai Lau 	info.map_flags = map->map_flags;
42189330986cSJoanne Koong 	info.map_extra = map->map_extra;
4219ad5b177bSMartin KaFai Lau 	memcpy(info.name, map->name, sizeof(map->name));
42201e270976SMartin KaFai Lau 
422178958fcaSMartin KaFai Lau 	if (map->btf) {
422222dc4a0fSAndrii Nakryiko 		info.btf_id = btf_obj_id(map->btf);
42239b2cf328SMartin KaFai Lau 		info.btf_key_type_id = map->btf_key_type_id;
42249b2cf328SMartin KaFai Lau 		info.btf_value_type_id = map->btf_value_type_id;
422578958fcaSMartin KaFai Lau 	}
422685d33df3SMartin KaFai Lau 	info.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id;
422778958fcaSMartin KaFai Lau 
422852775b33SJakub Kicinski 	if (bpf_map_is_dev_bound(map)) {
422952775b33SJakub Kicinski 		err = bpf_map_offload_info_fill(&info, map);
423052775b33SJakub Kicinski 		if (err)
423152775b33SJakub Kicinski 			return err;
423252775b33SJakub Kicinski 	}
423352775b33SJakub Kicinski 
42341e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
42351e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
42361e270976SMartin KaFai Lau 		return -EFAULT;
42371e270976SMartin KaFai Lau 
42381e270976SMartin KaFai Lau 	return 0;
42391e270976SMartin KaFai Lau }
42401e270976SMartin KaFai Lau 
424163960260SKees Cook static int bpf_btf_get_info_by_fd(struct file *file,
424263960260SKees Cook 				  struct btf *btf,
424362dab84cSMartin KaFai Lau 				  const union bpf_attr *attr,
424462dab84cSMartin KaFai Lau 				  union bpf_attr __user *uattr)
424562dab84cSMartin KaFai Lau {
424662dab84cSMartin KaFai Lau 	struct bpf_btf_info __user *uinfo = u64_to_user_ptr(attr->info.info);
424762dab84cSMartin KaFai Lau 	u32 info_len = attr->info.info_len;
424862dab84cSMartin KaFai Lau 	int err;
424962dab84cSMartin KaFai Lau 
4250af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(*uinfo), info_len);
425162dab84cSMartin KaFai Lau 	if (err)
425262dab84cSMartin KaFai Lau 		return err;
425362dab84cSMartin KaFai Lau 
425462dab84cSMartin KaFai Lau 	return btf_get_info_by_fd(btf, attr, uattr);
425562dab84cSMartin KaFai Lau }
425662dab84cSMartin KaFai Lau 
425763960260SKees Cook static int bpf_link_get_info_by_fd(struct file *file,
425863960260SKees Cook 				  struct bpf_link *link,
4259f2e10bffSAndrii Nakryiko 				  const union bpf_attr *attr,
4260f2e10bffSAndrii Nakryiko 				  union bpf_attr __user *uattr)
4261f2e10bffSAndrii Nakryiko {
4262f2e10bffSAndrii Nakryiko 	struct bpf_link_info __user *uinfo = u64_to_user_ptr(attr->info.info);
4263f2e10bffSAndrii Nakryiko 	struct bpf_link_info info;
4264f2e10bffSAndrii Nakryiko 	u32 info_len = attr->info.info_len;
4265f2e10bffSAndrii Nakryiko 	int err;
4266f2e10bffSAndrii Nakryiko 
4267af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len);
4268f2e10bffSAndrii Nakryiko 	if (err)
4269f2e10bffSAndrii Nakryiko 		return err;
4270f2e10bffSAndrii Nakryiko 	info_len = min_t(u32, sizeof(info), info_len);
4271f2e10bffSAndrii Nakryiko 
4272f2e10bffSAndrii Nakryiko 	memset(&info, 0, sizeof(info));
4273f2e10bffSAndrii Nakryiko 	if (copy_from_user(&info, uinfo, info_len))
4274f2e10bffSAndrii Nakryiko 		return -EFAULT;
4275f2e10bffSAndrii Nakryiko 
4276f2e10bffSAndrii Nakryiko 	info.type = link->type;
4277f2e10bffSAndrii Nakryiko 	info.id = link->id;
4278f2e10bffSAndrii Nakryiko 	info.prog_id = link->prog->aux->id;
4279f2e10bffSAndrii Nakryiko 
4280f2e10bffSAndrii Nakryiko 	if (link->ops->fill_link_info) {
4281f2e10bffSAndrii Nakryiko 		err = link->ops->fill_link_info(link, &info);
4282f2e10bffSAndrii Nakryiko 		if (err)
4283f2e10bffSAndrii Nakryiko 			return err;
4284f2e10bffSAndrii Nakryiko 	}
4285f2e10bffSAndrii Nakryiko 
4286f2e10bffSAndrii Nakryiko 	if (copy_to_user(uinfo, &info, info_len) ||
4287f2e10bffSAndrii Nakryiko 	    put_user(info_len, &uattr->info.info_len))
4288f2e10bffSAndrii Nakryiko 		return -EFAULT;
4289f2e10bffSAndrii Nakryiko 
4290f2e10bffSAndrii Nakryiko 	return 0;
4291f2e10bffSAndrii Nakryiko }
4292f2e10bffSAndrii Nakryiko 
4293f2e10bffSAndrii Nakryiko 
42941e270976SMartin KaFai Lau #define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info
42951e270976SMartin KaFai Lau 
42961e270976SMartin KaFai Lau static int bpf_obj_get_info_by_fd(const union bpf_attr *attr,
42971e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
42981e270976SMartin KaFai Lau {
42991e270976SMartin KaFai Lau 	int ufd = attr->info.bpf_fd;
43001e270976SMartin KaFai Lau 	struct fd f;
43011e270976SMartin KaFai Lau 	int err;
43021e270976SMartin KaFai Lau 
43031e270976SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD))
43041e270976SMartin KaFai Lau 		return -EINVAL;
43051e270976SMartin KaFai Lau 
43061e270976SMartin KaFai Lau 	f = fdget(ufd);
43071e270976SMartin KaFai Lau 	if (!f.file)
43081e270976SMartin KaFai Lau 		return -EBADFD;
43091e270976SMartin KaFai Lau 
43101e270976SMartin KaFai Lau 	if (f.file->f_op == &bpf_prog_fops)
431163960260SKees Cook 		err = bpf_prog_get_info_by_fd(f.file, f.file->private_data, attr,
43121e270976SMartin KaFai Lau 					      uattr);
43131e270976SMartin KaFai Lau 	else if (f.file->f_op == &bpf_map_fops)
431463960260SKees Cook 		err = bpf_map_get_info_by_fd(f.file, f.file->private_data, attr,
43151e270976SMartin KaFai Lau 					     uattr);
431660197cfbSMartin KaFai Lau 	else if (f.file->f_op == &btf_fops)
431763960260SKees Cook 		err = bpf_btf_get_info_by_fd(f.file, f.file->private_data, attr, uattr);
4318f2e10bffSAndrii Nakryiko 	else if (f.file->f_op == &bpf_link_fops)
431963960260SKees Cook 		err = bpf_link_get_info_by_fd(f.file, f.file->private_data,
4320f2e10bffSAndrii Nakryiko 					      attr, uattr);
43211e270976SMartin KaFai Lau 	else
43221e270976SMartin KaFai Lau 		err = -EINVAL;
43231e270976SMartin KaFai Lau 
43241e270976SMartin KaFai Lau 	fdput(f);
43251e270976SMartin KaFai Lau 	return err;
43261e270976SMartin KaFai Lau }
43271e270976SMartin KaFai Lau 
4328f56a653cSMartin KaFai Lau #define BPF_BTF_LOAD_LAST_FIELD btf_log_level
4329f56a653cSMartin KaFai Lau 
4330c571bd75SAlexei Starovoitov static int bpf_btf_load(const union bpf_attr *attr, bpfptr_t uattr)
4331f56a653cSMartin KaFai Lau {
4332f56a653cSMartin KaFai Lau 	if (CHECK_ATTR(BPF_BTF_LOAD))
4333f56a653cSMartin KaFai Lau 		return -EINVAL;
4334f56a653cSMartin KaFai Lau 
43352c78ee89SAlexei Starovoitov 	if (!bpf_capable())
4336f56a653cSMartin KaFai Lau 		return -EPERM;
4337f56a653cSMartin KaFai Lau 
4338c571bd75SAlexei Starovoitov 	return btf_new_fd(attr, uattr);
4339f56a653cSMartin KaFai Lau }
4340f56a653cSMartin KaFai Lau 
434178958fcaSMartin KaFai Lau #define BPF_BTF_GET_FD_BY_ID_LAST_FIELD btf_id
434278958fcaSMartin KaFai Lau 
434378958fcaSMartin KaFai Lau static int bpf_btf_get_fd_by_id(const union bpf_attr *attr)
434478958fcaSMartin KaFai Lau {
434578958fcaSMartin KaFai Lau 	if (CHECK_ATTR(BPF_BTF_GET_FD_BY_ID))
434678958fcaSMartin KaFai Lau 		return -EINVAL;
434778958fcaSMartin KaFai Lau 
434878958fcaSMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
434978958fcaSMartin KaFai Lau 		return -EPERM;
435078958fcaSMartin KaFai Lau 
435178958fcaSMartin KaFai Lau 	return btf_get_fd_by_id(attr->btf_id);
435278958fcaSMartin KaFai Lau }
435378958fcaSMartin KaFai Lau 
435441bdc4b4SYonghong Song static int bpf_task_fd_query_copy(const union bpf_attr *attr,
435541bdc4b4SYonghong Song 				    union bpf_attr __user *uattr,
435641bdc4b4SYonghong Song 				    u32 prog_id, u32 fd_type,
435741bdc4b4SYonghong Song 				    const char *buf, u64 probe_offset,
435841bdc4b4SYonghong Song 				    u64 probe_addr)
435941bdc4b4SYonghong Song {
436041bdc4b4SYonghong Song 	char __user *ubuf = u64_to_user_ptr(attr->task_fd_query.buf);
436141bdc4b4SYonghong Song 	u32 len = buf ? strlen(buf) : 0, input_len;
436241bdc4b4SYonghong Song 	int err = 0;
436341bdc4b4SYonghong Song 
436441bdc4b4SYonghong Song 	if (put_user(len, &uattr->task_fd_query.buf_len))
436541bdc4b4SYonghong Song 		return -EFAULT;
436641bdc4b4SYonghong Song 	input_len = attr->task_fd_query.buf_len;
436741bdc4b4SYonghong Song 	if (input_len && ubuf) {
436841bdc4b4SYonghong Song 		if (!len) {
436941bdc4b4SYonghong Song 			/* nothing to copy, just make ubuf NULL terminated */
437041bdc4b4SYonghong Song 			char zero = '\0';
437141bdc4b4SYonghong Song 
437241bdc4b4SYonghong Song 			if (put_user(zero, ubuf))
437341bdc4b4SYonghong Song 				return -EFAULT;
437441bdc4b4SYonghong Song 		} else if (input_len >= len + 1) {
437541bdc4b4SYonghong Song 			/* ubuf can hold the string with NULL terminator */
437641bdc4b4SYonghong Song 			if (copy_to_user(ubuf, buf, len + 1))
437741bdc4b4SYonghong Song 				return -EFAULT;
437841bdc4b4SYonghong Song 		} else {
437941bdc4b4SYonghong Song 			/* ubuf cannot hold the string with NULL terminator,
438041bdc4b4SYonghong Song 			 * do a partial copy with NULL terminator.
438141bdc4b4SYonghong Song 			 */
438241bdc4b4SYonghong Song 			char zero = '\0';
438341bdc4b4SYonghong Song 
438441bdc4b4SYonghong Song 			err = -ENOSPC;
438541bdc4b4SYonghong Song 			if (copy_to_user(ubuf, buf, input_len - 1))
438641bdc4b4SYonghong Song 				return -EFAULT;
438741bdc4b4SYonghong Song 			if (put_user(zero, ubuf + input_len - 1))
438841bdc4b4SYonghong Song 				return -EFAULT;
438941bdc4b4SYonghong Song 		}
439041bdc4b4SYonghong Song 	}
439141bdc4b4SYonghong Song 
439241bdc4b4SYonghong Song 	if (put_user(prog_id, &uattr->task_fd_query.prog_id) ||
439341bdc4b4SYonghong Song 	    put_user(fd_type, &uattr->task_fd_query.fd_type) ||
439441bdc4b4SYonghong Song 	    put_user(probe_offset, &uattr->task_fd_query.probe_offset) ||
439541bdc4b4SYonghong Song 	    put_user(probe_addr, &uattr->task_fd_query.probe_addr))
439641bdc4b4SYonghong Song 		return -EFAULT;
439741bdc4b4SYonghong Song 
439841bdc4b4SYonghong Song 	return err;
439941bdc4b4SYonghong Song }
440041bdc4b4SYonghong Song 
440141bdc4b4SYonghong Song #define BPF_TASK_FD_QUERY_LAST_FIELD task_fd_query.probe_addr
440241bdc4b4SYonghong Song 
440341bdc4b4SYonghong Song static int bpf_task_fd_query(const union bpf_attr *attr,
440441bdc4b4SYonghong Song 			     union bpf_attr __user *uattr)
440541bdc4b4SYonghong Song {
440641bdc4b4SYonghong Song 	pid_t pid = attr->task_fd_query.pid;
440741bdc4b4SYonghong Song 	u32 fd = attr->task_fd_query.fd;
440841bdc4b4SYonghong Song 	const struct perf_event *event;
440941bdc4b4SYonghong Song 	struct task_struct *task;
441041bdc4b4SYonghong Song 	struct file *file;
441141bdc4b4SYonghong Song 	int err;
441241bdc4b4SYonghong Song 
441341bdc4b4SYonghong Song 	if (CHECK_ATTR(BPF_TASK_FD_QUERY))
441441bdc4b4SYonghong Song 		return -EINVAL;
441541bdc4b4SYonghong Song 
441641bdc4b4SYonghong Song 	if (!capable(CAP_SYS_ADMIN))
441741bdc4b4SYonghong Song 		return -EPERM;
441841bdc4b4SYonghong Song 
441941bdc4b4SYonghong Song 	if (attr->task_fd_query.flags != 0)
442041bdc4b4SYonghong Song 		return -EINVAL;
442141bdc4b4SYonghong Song 
442283c10cc3SLee Jones 	rcu_read_lock();
442341bdc4b4SYonghong Song 	task = get_pid_task(find_vpid(pid), PIDTYPE_PID);
442483c10cc3SLee Jones 	rcu_read_unlock();
442541bdc4b4SYonghong Song 	if (!task)
442641bdc4b4SYonghong Song 		return -ENOENT;
442741bdc4b4SYonghong Song 
442841bdc4b4SYonghong Song 	err = 0;
4429b48845afSEric W. Biederman 	file = fget_task(task, fd);
4430b48845afSEric W. Biederman 	put_task_struct(task);
443141bdc4b4SYonghong Song 	if (!file)
4432b48845afSEric W. Biederman 		return -EBADF;
443341bdc4b4SYonghong Song 
443470ed506cSAndrii Nakryiko 	if (file->f_op == &bpf_link_fops) {
443570ed506cSAndrii Nakryiko 		struct bpf_link *link = file->private_data;
443670ed506cSAndrii Nakryiko 
4437a3b80e10SAndrii Nakryiko 		if (link->ops == &bpf_raw_tp_link_lops) {
443870ed506cSAndrii Nakryiko 			struct bpf_raw_tp_link *raw_tp =
443970ed506cSAndrii Nakryiko 				container_of(link, struct bpf_raw_tp_link, link);
444041bdc4b4SYonghong Song 			struct bpf_raw_event_map *btp = raw_tp->btp;
444141bdc4b4SYonghong Song 
444241bdc4b4SYonghong Song 			err = bpf_task_fd_query_copy(attr, uattr,
444370ed506cSAndrii Nakryiko 						     raw_tp->link.prog->aux->id,
444441bdc4b4SYonghong Song 						     BPF_FD_TYPE_RAW_TRACEPOINT,
444541bdc4b4SYonghong Song 						     btp->tp->name, 0, 0);
444641bdc4b4SYonghong Song 			goto put_file;
444741bdc4b4SYonghong Song 		}
444870ed506cSAndrii Nakryiko 		goto out_not_supp;
444970ed506cSAndrii Nakryiko 	}
445041bdc4b4SYonghong Song 
445141bdc4b4SYonghong Song 	event = perf_get_event(file);
445241bdc4b4SYonghong Song 	if (!IS_ERR(event)) {
445341bdc4b4SYonghong Song 		u64 probe_offset, probe_addr;
445441bdc4b4SYonghong Song 		u32 prog_id, fd_type;
445541bdc4b4SYonghong Song 		const char *buf;
445641bdc4b4SYonghong Song 
445741bdc4b4SYonghong Song 		err = bpf_get_perf_event_info(event, &prog_id, &fd_type,
445841bdc4b4SYonghong Song 					      &buf, &probe_offset,
445941bdc4b4SYonghong Song 					      &probe_addr);
446041bdc4b4SYonghong Song 		if (!err)
446141bdc4b4SYonghong Song 			err = bpf_task_fd_query_copy(attr, uattr, prog_id,
446241bdc4b4SYonghong Song 						     fd_type, buf,
446341bdc4b4SYonghong Song 						     probe_offset,
446441bdc4b4SYonghong Song 						     probe_addr);
446541bdc4b4SYonghong Song 		goto put_file;
446641bdc4b4SYonghong Song 	}
446741bdc4b4SYonghong Song 
446870ed506cSAndrii Nakryiko out_not_supp:
446941bdc4b4SYonghong Song 	err = -ENOTSUPP;
447041bdc4b4SYonghong Song put_file:
447141bdc4b4SYonghong Song 	fput(file);
447241bdc4b4SYonghong Song 	return err;
447341bdc4b4SYonghong Song }
447441bdc4b4SYonghong Song 
4475cb4d03abSBrian Vazquez #define BPF_MAP_BATCH_LAST_FIELD batch.flags
4476cb4d03abSBrian Vazquez 
44773af43ba4SHou Tao #define BPF_DO_BATCH(fn, ...)			\
4478cb4d03abSBrian Vazquez 	do {					\
4479cb4d03abSBrian Vazquez 		if (!fn) {			\
4480cb4d03abSBrian Vazquez 			err = -ENOTSUPP;	\
4481cb4d03abSBrian Vazquez 			goto err_put;		\
4482cb4d03abSBrian Vazquez 		}				\
44833af43ba4SHou Tao 		err = fn(__VA_ARGS__);		\
4484cb4d03abSBrian Vazquez 	} while (0)
4485cb4d03abSBrian Vazquez 
4486cb4d03abSBrian Vazquez static int bpf_map_do_batch(const union bpf_attr *attr,
4487cb4d03abSBrian Vazquez 			    union bpf_attr __user *uattr,
4488cb4d03abSBrian Vazquez 			    int cmd)
4489cb4d03abSBrian Vazquez {
4490353050beSDaniel Borkmann 	bool has_read  = cmd == BPF_MAP_LOOKUP_BATCH ||
4491353050beSDaniel Borkmann 			 cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH;
4492353050beSDaniel Borkmann 	bool has_write = cmd != BPF_MAP_LOOKUP_BATCH;
4493cb4d03abSBrian Vazquez 	struct bpf_map *map;
4494cb4d03abSBrian Vazquez 	int err, ufd;
4495cb4d03abSBrian Vazquez 	struct fd f;
4496cb4d03abSBrian Vazquez 
4497cb4d03abSBrian Vazquez 	if (CHECK_ATTR(BPF_MAP_BATCH))
4498cb4d03abSBrian Vazquez 		return -EINVAL;
4499cb4d03abSBrian Vazquez 
4500cb4d03abSBrian Vazquez 	ufd = attr->batch.map_fd;
4501cb4d03abSBrian Vazquez 	f = fdget(ufd);
4502cb4d03abSBrian Vazquez 	map = __bpf_map_get(f);
4503cb4d03abSBrian Vazquez 	if (IS_ERR(map))
4504cb4d03abSBrian Vazquez 		return PTR_ERR(map);
4505353050beSDaniel Borkmann 	if (has_write)
4506353050beSDaniel Borkmann 		bpf_map_write_active_inc(map);
4507353050beSDaniel Borkmann 	if (has_read && !(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
4508cb4d03abSBrian Vazquez 		err = -EPERM;
4509cb4d03abSBrian Vazquez 		goto err_put;
4510cb4d03abSBrian Vazquez 	}
4511353050beSDaniel Borkmann 	if (has_write && !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
4512cb4d03abSBrian Vazquez 		err = -EPERM;
4513cb4d03abSBrian Vazquez 		goto err_put;
4514cb4d03abSBrian Vazquez 	}
4515cb4d03abSBrian Vazquez 
4516cb4d03abSBrian Vazquez 	if (cmd == BPF_MAP_LOOKUP_BATCH)
45173af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_lookup_batch, map, attr, uattr);
451805799638SYonghong Song 	else if (cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH)
45193af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_lookup_and_delete_batch, map, attr, uattr);
4520aa2e93b8SBrian Vazquez 	else if (cmd == BPF_MAP_UPDATE_BATCH)
45213af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_update_batch, map, f.file, attr, uattr);
4522aa2e93b8SBrian Vazquez 	else
45233af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_delete_batch, map, attr, uattr);
4524cb4d03abSBrian Vazquez err_put:
4525353050beSDaniel Borkmann 	if (has_write)
4526353050beSDaniel Borkmann 		bpf_map_write_active_dec(map);
4527cb4d03abSBrian Vazquez 	fdput(f);
4528cb4d03abSBrian Vazquez 	return err;
4529cb4d03abSBrian Vazquez }
4530cb4d03abSBrian Vazquez 
4531ca74823cSJiri Olsa #define BPF_LINK_CREATE_LAST_FIELD link_create.kprobe_multi.cookies
4532af2ac3e1SAlexei Starovoitov static int link_create(union bpf_attr *attr, bpfptr_t uattr)
4533af6eea57SAndrii Nakryiko {
4534af6eea57SAndrii Nakryiko 	enum bpf_prog_type ptype;
4535af6eea57SAndrii Nakryiko 	struct bpf_prog *prog;
4536af6eea57SAndrii Nakryiko 	int ret;
4537af6eea57SAndrii Nakryiko 
4538af6eea57SAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_CREATE))
4539af6eea57SAndrii Nakryiko 		return -EINVAL;
4540af6eea57SAndrii Nakryiko 
45414a1e7c0cSToke Høiland-Jørgensen 	prog = bpf_prog_get(attr->link_create.prog_fd);
4542af6eea57SAndrii Nakryiko 	if (IS_ERR(prog))
4543af6eea57SAndrii Nakryiko 		return PTR_ERR(prog);
4544af6eea57SAndrii Nakryiko 
4545af6eea57SAndrii Nakryiko 	ret = bpf_prog_attach_check_attach_type(prog,
4546af6eea57SAndrii Nakryiko 						attr->link_create.attach_type);
4547af6eea57SAndrii Nakryiko 	if (ret)
45484a1e7c0cSToke Høiland-Jørgensen 		goto out;
45494a1e7c0cSToke Høiland-Jørgensen 
4550b89fbfbbSAndrii Nakryiko 	switch (prog->type) {
4551b89fbfbbSAndrii Nakryiko 	case BPF_PROG_TYPE_EXT:
4552df86ca0dSAndrii Nakryiko 		break;
4553b89fbfbbSAndrii Nakryiko 	case BPF_PROG_TYPE_PERF_EVENT:
4554b89fbfbbSAndrii Nakryiko 	case BPF_PROG_TYPE_TRACEPOINT:
4555b89fbfbbSAndrii Nakryiko 		if (attr->link_create.attach_type != BPF_PERF_EVENT) {
4556b89fbfbbSAndrii Nakryiko 			ret = -EINVAL;
4557b89fbfbbSAndrii Nakryiko 			goto out;
45584a1e7c0cSToke Høiland-Jørgensen 		}
4559b89fbfbbSAndrii Nakryiko 		break;
45600dcac272SJiri Olsa 	case BPF_PROG_TYPE_KPROBE:
45610dcac272SJiri Olsa 		if (attr->link_create.attach_type != BPF_PERF_EVENT &&
45620dcac272SJiri Olsa 		    attr->link_create.attach_type != BPF_TRACE_KPROBE_MULTI) {
45630dcac272SJiri Olsa 			ret = -EINVAL;
45640dcac272SJiri Olsa 			goto out;
45650dcac272SJiri Olsa 		}
45660dcac272SJiri Olsa 		break;
4567b89fbfbbSAndrii Nakryiko 	default:
45684a1e7c0cSToke Høiland-Jørgensen 		ptype = attach_type_to_prog_type(attr->link_create.attach_type);
45694a1e7c0cSToke Høiland-Jørgensen 		if (ptype == BPF_PROG_TYPE_UNSPEC || ptype != prog->type) {
45704a1e7c0cSToke Høiland-Jørgensen 			ret = -EINVAL;
45714a1e7c0cSToke Høiland-Jørgensen 			goto out;
45724a1e7c0cSToke Høiland-Jørgensen 		}
4573b89fbfbbSAndrii Nakryiko 		break;
4574b89fbfbbSAndrii Nakryiko 	}
4575af6eea57SAndrii Nakryiko 
4576df86ca0dSAndrii Nakryiko 	switch (prog->type) {
4577af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SKB:
4578af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK:
4579af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
4580af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_SOCK_OPS:
4581af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_DEVICE:
4582af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
4583af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
4584af6eea57SAndrii Nakryiko 		ret = cgroup_bpf_link_attach(attr, prog);
4585af6eea57SAndrii Nakryiko 		break;
4586df86ca0dSAndrii Nakryiko 	case BPF_PROG_TYPE_EXT:
4587df86ca0dSAndrii Nakryiko 		ret = bpf_tracing_prog_attach(prog,
4588df86ca0dSAndrii Nakryiko 					      attr->link_create.target_fd,
45892fcc8241SKui-Feng Lee 					      attr->link_create.target_btf_id,
45902fcc8241SKui-Feng Lee 					      attr->link_create.tracing.cookie);
4591df86ca0dSAndrii Nakryiko 		break;
4592df86ca0dSAndrii Nakryiko 	case BPF_PROG_TYPE_LSM:
4593de4e05caSYonghong Song 	case BPF_PROG_TYPE_TRACING:
4594df86ca0dSAndrii Nakryiko 		if (attr->link_create.attach_type != prog->expected_attach_type) {
4595df86ca0dSAndrii Nakryiko 			ret = -EINVAL;
4596df86ca0dSAndrii Nakryiko 			goto out;
4597df86ca0dSAndrii Nakryiko 		}
4598df86ca0dSAndrii Nakryiko 		if (prog->expected_attach_type == BPF_TRACE_RAW_TP)
4599df86ca0dSAndrii Nakryiko 			ret = bpf_raw_tp_link_attach(prog, NULL);
4600df86ca0dSAndrii Nakryiko 		else if (prog->expected_attach_type == BPF_TRACE_ITER)
4601df86ca0dSAndrii Nakryiko 			ret = bpf_iter_link_attach(attr, uattr, prog);
460269fd337aSStanislav Fomichev 		else if (prog->expected_attach_type == BPF_LSM_CGROUP)
460369fd337aSStanislav Fomichev 			ret = cgroup_bpf_link_attach(attr, prog);
4604df86ca0dSAndrii Nakryiko 		else
4605df86ca0dSAndrii Nakryiko 			ret = bpf_tracing_prog_attach(prog,
4606df86ca0dSAndrii Nakryiko 						      attr->link_create.target_fd,
46072fcc8241SKui-Feng Lee 						      attr->link_create.target_btf_id,
46082fcc8241SKui-Feng Lee 						      attr->link_create.tracing.cookie);
4609de4e05caSYonghong Song 		break;
46107f045a49SJakub Sitnicki 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
4611e9ddbb77SJakub Sitnicki 	case BPF_PROG_TYPE_SK_LOOKUP:
46127f045a49SJakub Sitnicki 		ret = netns_bpf_link_create(attr, prog);
46137f045a49SJakub Sitnicki 		break;
4614310ad797SAndrii Nakryiko #ifdef CONFIG_NET
4615aa8d3a71SAndrii Nakryiko 	case BPF_PROG_TYPE_XDP:
4616aa8d3a71SAndrii Nakryiko 		ret = bpf_xdp_link_attach(attr, prog);
4617aa8d3a71SAndrii Nakryiko 		break;
4618310ad797SAndrii Nakryiko #endif
4619b89fbfbbSAndrii Nakryiko 	case BPF_PROG_TYPE_PERF_EVENT:
4620b89fbfbbSAndrii Nakryiko 	case BPF_PROG_TYPE_TRACEPOINT:
4621b89fbfbbSAndrii Nakryiko 		ret = bpf_perf_link_attach(attr, prog);
4622b89fbfbbSAndrii Nakryiko 		break;
46230dcac272SJiri Olsa 	case BPF_PROG_TYPE_KPROBE:
46240dcac272SJiri Olsa 		if (attr->link_create.attach_type == BPF_PERF_EVENT)
46250dcac272SJiri Olsa 			ret = bpf_perf_link_attach(attr, prog);
46260dcac272SJiri Olsa 		else
46270dcac272SJiri Olsa 			ret = bpf_kprobe_multi_link_attach(attr, prog);
46280dcac272SJiri Olsa 		break;
4629af6eea57SAndrii Nakryiko 	default:
4630af6eea57SAndrii Nakryiko 		ret = -EINVAL;
4631af6eea57SAndrii Nakryiko 	}
4632af6eea57SAndrii Nakryiko 
46334a1e7c0cSToke Høiland-Jørgensen out:
4634af6eea57SAndrii Nakryiko 	if (ret < 0)
4635af6eea57SAndrii Nakryiko 		bpf_prog_put(prog);
4636af6eea57SAndrii Nakryiko 	return ret;
4637af6eea57SAndrii Nakryiko }
4638af6eea57SAndrii Nakryiko 
46390c991ebcSAndrii Nakryiko #define BPF_LINK_UPDATE_LAST_FIELD link_update.old_prog_fd
46400c991ebcSAndrii Nakryiko 
46410c991ebcSAndrii Nakryiko static int link_update(union bpf_attr *attr)
46420c991ebcSAndrii Nakryiko {
46430c991ebcSAndrii Nakryiko 	struct bpf_prog *old_prog = NULL, *new_prog;
46440c991ebcSAndrii Nakryiko 	struct bpf_link *link;
46450c991ebcSAndrii Nakryiko 	u32 flags;
46460c991ebcSAndrii Nakryiko 	int ret;
46470c991ebcSAndrii Nakryiko 
46480c991ebcSAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_UPDATE))
46490c991ebcSAndrii Nakryiko 		return -EINVAL;
46500c991ebcSAndrii Nakryiko 
46510c991ebcSAndrii Nakryiko 	flags = attr->link_update.flags;
46520c991ebcSAndrii Nakryiko 	if (flags & ~BPF_F_REPLACE)
46530c991ebcSAndrii Nakryiko 		return -EINVAL;
46540c991ebcSAndrii Nakryiko 
46550c991ebcSAndrii Nakryiko 	link = bpf_link_get_from_fd(attr->link_update.link_fd);
46560c991ebcSAndrii Nakryiko 	if (IS_ERR(link))
46570c991ebcSAndrii Nakryiko 		return PTR_ERR(link);
46580c991ebcSAndrii Nakryiko 
46590c991ebcSAndrii Nakryiko 	new_prog = bpf_prog_get(attr->link_update.new_prog_fd);
46604adb7a4aSAndrii Nakryiko 	if (IS_ERR(new_prog)) {
46614adb7a4aSAndrii Nakryiko 		ret = PTR_ERR(new_prog);
46624adb7a4aSAndrii Nakryiko 		goto out_put_link;
46634adb7a4aSAndrii Nakryiko 	}
46640c991ebcSAndrii Nakryiko 
46650c991ebcSAndrii Nakryiko 	if (flags & BPF_F_REPLACE) {
46660c991ebcSAndrii Nakryiko 		old_prog = bpf_prog_get(attr->link_update.old_prog_fd);
46670c991ebcSAndrii Nakryiko 		if (IS_ERR(old_prog)) {
46680c991ebcSAndrii Nakryiko 			ret = PTR_ERR(old_prog);
46690c991ebcSAndrii Nakryiko 			old_prog = NULL;
46700c991ebcSAndrii Nakryiko 			goto out_put_progs;
46710c991ebcSAndrii Nakryiko 		}
46724adb7a4aSAndrii Nakryiko 	} else if (attr->link_update.old_prog_fd) {
46734adb7a4aSAndrii Nakryiko 		ret = -EINVAL;
46744adb7a4aSAndrii Nakryiko 		goto out_put_progs;
46750c991ebcSAndrii Nakryiko 	}
46760c991ebcSAndrii Nakryiko 
4677f9d04127SAndrii Nakryiko 	if (link->ops->update_prog)
4678f9d04127SAndrii Nakryiko 		ret = link->ops->update_prog(link, new_prog, old_prog);
4679f9d04127SAndrii Nakryiko 	else
46800c991ebcSAndrii Nakryiko 		ret = -EINVAL;
46810c991ebcSAndrii Nakryiko 
46820c991ebcSAndrii Nakryiko out_put_progs:
46830c991ebcSAndrii Nakryiko 	if (old_prog)
46840c991ebcSAndrii Nakryiko 		bpf_prog_put(old_prog);
46850c991ebcSAndrii Nakryiko 	if (ret)
46860c991ebcSAndrii Nakryiko 		bpf_prog_put(new_prog);
46874adb7a4aSAndrii Nakryiko out_put_link:
46884adb7a4aSAndrii Nakryiko 	bpf_link_put(link);
46890c991ebcSAndrii Nakryiko 	return ret;
46900c991ebcSAndrii Nakryiko }
46910c991ebcSAndrii Nakryiko 
469273b11c2aSAndrii Nakryiko #define BPF_LINK_DETACH_LAST_FIELD link_detach.link_fd
469373b11c2aSAndrii Nakryiko 
469473b11c2aSAndrii Nakryiko static int link_detach(union bpf_attr *attr)
469573b11c2aSAndrii Nakryiko {
469673b11c2aSAndrii Nakryiko 	struct bpf_link *link;
469773b11c2aSAndrii Nakryiko 	int ret;
469873b11c2aSAndrii Nakryiko 
469973b11c2aSAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_DETACH))
470073b11c2aSAndrii Nakryiko 		return -EINVAL;
470173b11c2aSAndrii Nakryiko 
470273b11c2aSAndrii Nakryiko 	link = bpf_link_get_from_fd(attr->link_detach.link_fd);
470373b11c2aSAndrii Nakryiko 	if (IS_ERR(link))
470473b11c2aSAndrii Nakryiko 		return PTR_ERR(link);
470573b11c2aSAndrii Nakryiko 
470673b11c2aSAndrii Nakryiko 	if (link->ops->detach)
470773b11c2aSAndrii Nakryiko 		ret = link->ops->detach(link);
470873b11c2aSAndrii Nakryiko 	else
470973b11c2aSAndrii Nakryiko 		ret = -EOPNOTSUPP;
471073b11c2aSAndrii Nakryiko 
471173b11c2aSAndrii Nakryiko 	bpf_link_put(link);
471273b11c2aSAndrii Nakryiko 	return ret;
471373b11c2aSAndrii Nakryiko }
471473b11c2aSAndrii Nakryiko 
4715005142b8SAlexei Starovoitov static struct bpf_link *bpf_link_inc_not_zero(struct bpf_link *link)
47162d602c8cSAndrii Nakryiko {
4717005142b8SAlexei Starovoitov 	return atomic64_fetch_add_unless(&link->refcnt, 1, 0) ? link : ERR_PTR(-ENOENT);
4718005142b8SAlexei Starovoitov }
4719005142b8SAlexei Starovoitov 
4720005142b8SAlexei Starovoitov struct bpf_link *bpf_link_by_id(u32 id)
4721005142b8SAlexei Starovoitov {
4722005142b8SAlexei Starovoitov 	struct bpf_link *link;
4723005142b8SAlexei Starovoitov 
4724005142b8SAlexei Starovoitov 	if (!id)
4725005142b8SAlexei Starovoitov 		return ERR_PTR(-ENOENT);
4726005142b8SAlexei Starovoitov 
4727005142b8SAlexei Starovoitov 	spin_lock_bh(&link_idr_lock);
4728005142b8SAlexei Starovoitov 	/* before link is "settled", ID is 0, pretend it doesn't exist yet */
4729005142b8SAlexei Starovoitov 	link = idr_find(&link_idr, id);
4730005142b8SAlexei Starovoitov 	if (link) {
4731005142b8SAlexei Starovoitov 		if (link->id)
4732005142b8SAlexei Starovoitov 			link = bpf_link_inc_not_zero(link);
4733005142b8SAlexei Starovoitov 		else
4734005142b8SAlexei Starovoitov 			link = ERR_PTR(-EAGAIN);
4735005142b8SAlexei Starovoitov 	} else {
4736005142b8SAlexei Starovoitov 		link = ERR_PTR(-ENOENT);
4737005142b8SAlexei Starovoitov 	}
4738005142b8SAlexei Starovoitov 	spin_unlock_bh(&link_idr_lock);
4739005142b8SAlexei Starovoitov 	return link;
47402d602c8cSAndrii Nakryiko }
47412d602c8cSAndrii Nakryiko 
47429f883612SDmitrii Dolgov struct bpf_link *bpf_link_get_curr_or_next(u32 *id)
47439f883612SDmitrii Dolgov {
47449f883612SDmitrii Dolgov 	struct bpf_link *link;
47459f883612SDmitrii Dolgov 
47469f883612SDmitrii Dolgov 	spin_lock_bh(&link_idr_lock);
47479f883612SDmitrii Dolgov again:
47489f883612SDmitrii Dolgov 	link = idr_get_next(&link_idr, id);
47499f883612SDmitrii Dolgov 	if (link) {
47509f883612SDmitrii Dolgov 		link = bpf_link_inc_not_zero(link);
47519f883612SDmitrii Dolgov 		if (IS_ERR(link)) {
47529f883612SDmitrii Dolgov 			(*id)++;
47539f883612SDmitrii Dolgov 			goto again;
47549f883612SDmitrii Dolgov 		}
47559f883612SDmitrii Dolgov 	}
47569f883612SDmitrii Dolgov 	spin_unlock_bh(&link_idr_lock);
47579f883612SDmitrii Dolgov 
47589f883612SDmitrii Dolgov 	return link;
47599f883612SDmitrii Dolgov }
47609f883612SDmitrii Dolgov 
47612d602c8cSAndrii Nakryiko #define BPF_LINK_GET_FD_BY_ID_LAST_FIELD link_id
47622d602c8cSAndrii Nakryiko 
47632d602c8cSAndrii Nakryiko static int bpf_link_get_fd_by_id(const union bpf_attr *attr)
47642d602c8cSAndrii Nakryiko {
47652d602c8cSAndrii Nakryiko 	struct bpf_link *link;
47662d602c8cSAndrii Nakryiko 	u32 id = attr->link_id;
4767005142b8SAlexei Starovoitov 	int fd;
47682d602c8cSAndrii Nakryiko 
47692d602c8cSAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_GET_FD_BY_ID))
47702d602c8cSAndrii Nakryiko 		return -EINVAL;
47712d602c8cSAndrii Nakryiko 
47722d602c8cSAndrii Nakryiko 	if (!capable(CAP_SYS_ADMIN))
47732d602c8cSAndrii Nakryiko 		return -EPERM;
47742d602c8cSAndrii Nakryiko 
4775005142b8SAlexei Starovoitov 	link = bpf_link_by_id(id);
4776005142b8SAlexei Starovoitov 	if (IS_ERR(link))
4777005142b8SAlexei Starovoitov 		return PTR_ERR(link);
47782d602c8cSAndrii Nakryiko 
47792d602c8cSAndrii Nakryiko 	fd = bpf_link_new_fd(link);
47802d602c8cSAndrii Nakryiko 	if (fd < 0)
47812d602c8cSAndrii Nakryiko 		bpf_link_put(link);
47822d602c8cSAndrii Nakryiko 
47832d602c8cSAndrii Nakryiko 	return fd;
47842d602c8cSAndrii Nakryiko }
47852d602c8cSAndrii Nakryiko 
4786d46edd67SSong Liu DEFINE_MUTEX(bpf_stats_enabled_mutex);
4787d46edd67SSong Liu 
4788d46edd67SSong Liu static int bpf_stats_release(struct inode *inode, struct file *file)
4789d46edd67SSong Liu {
4790d46edd67SSong Liu 	mutex_lock(&bpf_stats_enabled_mutex);
4791d46edd67SSong Liu 	static_key_slow_dec(&bpf_stats_enabled_key.key);
4792d46edd67SSong Liu 	mutex_unlock(&bpf_stats_enabled_mutex);
4793d46edd67SSong Liu 	return 0;
4794d46edd67SSong Liu }
4795d46edd67SSong Liu 
4796d46edd67SSong Liu static const struct file_operations bpf_stats_fops = {
4797d46edd67SSong Liu 	.release = bpf_stats_release,
4798d46edd67SSong Liu };
4799d46edd67SSong Liu 
4800d46edd67SSong Liu static int bpf_enable_runtime_stats(void)
4801d46edd67SSong Liu {
4802d46edd67SSong Liu 	int fd;
4803d46edd67SSong Liu 
4804d46edd67SSong Liu 	mutex_lock(&bpf_stats_enabled_mutex);
4805d46edd67SSong Liu 
4806d46edd67SSong Liu 	/* Set a very high limit to avoid overflow */
4807d46edd67SSong Liu 	if (static_key_count(&bpf_stats_enabled_key.key) > INT_MAX / 2) {
4808d46edd67SSong Liu 		mutex_unlock(&bpf_stats_enabled_mutex);
4809d46edd67SSong Liu 		return -EBUSY;
4810d46edd67SSong Liu 	}
4811d46edd67SSong Liu 
4812d46edd67SSong Liu 	fd = anon_inode_getfd("bpf-stats", &bpf_stats_fops, NULL, O_CLOEXEC);
4813d46edd67SSong Liu 	if (fd >= 0)
4814d46edd67SSong Liu 		static_key_slow_inc(&bpf_stats_enabled_key.key);
4815d46edd67SSong Liu 
4816d46edd67SSong Liu 	mutex_unlock(&bpf_stats_enabled_mutex);
4817d46edd67SSong Liu 	return fd;
4818d46edd67SSong Liu }
4819d46edd67SSong Liu 
4820d46edd67SSong Liu #define BPF_ENABLE_STATS_LAST_FIELD enable_stats.type
4821d46edd67SSong Liu 
4822d46edd67SSong Liu static int bpf_enable_stats(union bpf_attr *attr)
4823d46edd67SSong Liu {
4824d46edd67SSong Liu 
4825d46edd67SSong Liu 	if (CHECK_ATTR(BPF_ENABLE_STATS))
4826d46edd67SSong Liu 		return -EINVAL;
4827d46edd67SSong Liu 
4828d46edd67SSong Liu 	if (!capable(CAP_SYS_ADMIN))
4829d46edd67SSong Liu 		return -EPERM;
4830d46edd67SSong Liu 
4831d46edd67SSong Liu 	switch (attr->enable_stats.type) {
4832d46edd67SSong Liu 	case BPF_STATS_RUN_TIME:
4833d46edd67SSong Liu 		return bpf_enable_runtime_stats();
4834d46edd67SSong Liu 	default:
4835d46edd67SSong Liu 		break;
4836d46edd67SSong Liu 	}
4837d46edd67SSong Liu 	return -EINVAL;
4838d46edd67SSong Liu }
4839d46edd67SSong Liu 
4840ac51d99bSYonghong Song #define BPF_ITER_CREATE_LAST_FIELD iter_create.flags
4841ac51d99bSYonghong Song 
4842ac51d99bSYonghong Song static int bpf_iter_create(union bpf_attr *attr)
4843ac51d99bSYonghong Song {
4844ac51d99bSYonghong Song 	struct bpf_link *link;
4845ac51d99bSYonghong Song 	int err;
4846ac51d99bSYonghong Song 
4847ac51d99bSYonghong Song 	if (CHECK_ATTR(BPF_ITER_CREATE))
4848ac51d99bSYonghong Song 		return -EINVAL;
4849ac51d99bSYonghong Song 
4850ac51d99bSYonghong Song 	if (attr->iter_create.flags)
4851ac51d99bSYonghong Song 		return -EINVAL;
4852ac51d99bSYonghong Song 
4853ac51d99bSYonghong Song 	link = bpf_link_get_from_fd(attr->iter_create.link_fd);
4854ac51d99bSYonghong Song 	if (IS_ERR(link))
4855ac51d99bSYonghong Song 		return PTR_ERR(link);
4856ac51d99bSYonghong Song 
4857ac51d99bSYonghong Song 	err = bpf_iter_new_fd(link);
4858ac51d99bSYonghong Song 	bpf_link_put(link);
4859ac51d99bSYonghong Song 
4860ac51d99bSYonghong Song 	return err;
4861ac51d99bSYonghong Song }
4862ac51d99bSYonghong Song 
4863ef15314aSYiFei Zhu #define BPF_PROG_BIND_MAP_LAST_FIELD prog_bind_map.flags
4864ef15314aSYiFei Zhu 
4865ef15314aSYiFei Zhu static int bpf_prog_bind_map(union bpf_attr *attr)
4866ef15314aSYiFei Zhu {
4867ef15314aSYiFei Zhu 	struct bpf_prog *prog;
4868ef15314aSYiFei Zhu 	struct bpf_map *map;
4869ef15314aSYiFei Zhu 	struct bpf_map **used_maps_old, **used_maps_new;
4870ef15314aSYiFei Zhu 	int i, ret = 0;
4871ef15314aSYiFei Zhu 
4872ef15314aSYiFei Zhu 	if (CHECK_ATTR(BPF_PROG_BIND_MAP))
4873ef15314aSYiFei Zhu 		return -EINVAL;
4874ef15314aSYiFei Zhu 
4875ef15314aSYiFei Zhu 	if (attr->prog_bind_map.flags)
4876ef15314aSYiFei Zhu 		return -EINVAL;
4877ef15314aSYiFei Zhu 
4878ef15314aSYiFei Zhu 	prog = bpf_prog_get(attr->prog_bind_map.prog_fd);
4879ef15314aSYiFei Zhu 	if (IS_ERR(prog))
4880ef15314aSYiFei Zhu 		return PTR_ERR(prog);
4881ef15314aSYiFei Zhu 
4882ef15314aSYiFei Zhu 	map = bpf_map_get(attr->prog_bind_map.map_fd);
4883ef15314aSYiFei Zhu 	if (IS_ERR(map)) {
4884ef15314aSYiFei Zhu 		ret = PTR_ERR(map);
4885ef15314aSYiFei Zhu 		goto out_prog_put;
4886ef15314aSYiFei Zhu 	}
4887ef15314aSYiFei Zhu 
4888ef15314aSYiFei Zhu 	mutex_lock(&prog->aux->used_maps_mutex);
4889ef15314aSYiFei Zhu 
4890ef15314aSYiFei Zhu 	used_maps_old = prog->aux->used_maps;
4891ef15314aSYiFei Zhu 
4892ef15314aSYiFei Zhu 	for (i = 0; i < prog->aux->used_map_cnt; i++)
48931028ae40SStanislav Fomichev 		if (used_maps_old[i] == map) {
48941028ae40SStanislav Fomichev 			bpf_map_put(map);
4895ef15314aSYiFei Zhu 			goto out_unlock;
48961028ae40SStanislav Fomichev 		}
4897ef15314aSYiFei Zhu 
4898ef15314aSYiFei Zhu 	used_maps_new = kmalloc_array(prog->aux->used_map_cnt + 1,
4899ef15314aSYiFei Zhu 				      sizeof(used_maps_new[0]),
4900ef15314aSYiFei Zhu 				      GFP_KERNEL);
4901ef15314aSYiFei Zhu 	if (!used_maps_new) {
4902ef15314aSYiFei Zhu 		ret = -ENOMEM;
4903ef15314aSYiFei Zhu 		goto out_unlock;
4904ef15314aSYiFei Zhu 	}
4905ef15314aSYiFei Zhu 
4906ef15314aSYiFei Zhu 	memcpy(used_maps_new, used_maps_old,
4907ef15314aSYiFei Zhu 	       sizeof(used_maps_old[0]) * prog->aux->used_map_cnt);
4908ef15314aSYiFei Zhu 	used_maps_new[prog->aux->used_map_cnt] = map;
4909ef15314aSYiFei Zhu 
4910ef15314aSYiFei Zhu 	prog->aux->used_map_cnt++;
4911ef15314aSYiFei Zhu 	prog->aux->used_maps = used_maps_new;
4912ef15314aSYiFei Zhu 
4913ef15314aSYiFei Zhu 	kfree(used_maps_old);
4914ef15314aSYiFei Zhu 
4915ef15314aSYiFei Zhu out_unlock:
4916ef15314aSYiFei Zhu 	mutex_unlock(&prog->aux->used_maps_mutex);
4917ef15314aSYiFei Zhu 
4918ef15314aSYiFei Zhu 	if (ret)
4919ef15314aSYiFei Zhu 		bpf_map_put(map);
4920ef15314aSYiFei Zhu out_prog_put:
4921ef15314aSYiFei Zhu 	bpf_prog_put(prog);
4922ef15314aSYiFei Zhu 	return ret;
4923ef15314aSYiFei Zhu }
4924ef15314aSYiFei Zhu 
4925af2ac3e1SAlexei Starovoitov static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size)
492699c55f7dSAlexei Starovoitov {
49278096f229SGreg Kroah-Hartman 	union bpf_attr attr;
4928c8644cd0SAlan Maguire 	bool capable;
492999c55f7dSAlexei Starovoitov 	int err;
493099c55f7dSAlexei Starovoitov 
4931c8644cd0SAlan Maguire 	capable = bpf_capable() || !sysctl_unprivileged_bpf_disabled;
4932c8644cd0SAlan Maguire 
4933c8644cd0SAlan Maguire 	/* Intent here is for unprivileged_bpf_disabled to block key object
4934c8644cd0SAlan Maguire 	 * creation commands for unprivileged users; other actions depend
4935c8644cd0SAlan Maguire 	 * of fd availability and access to bpffs, so are dependent on
4936c8644cd0SAlan Maguire 	 * object creation success.  Capabilities are later verified for
4937c8644cd0SAlan Maguire 	 * operations such as load and map create, so even with unprivileged
4938c8644cd0SAlan Maguire 	 * BPF disabled, capability checks are still carried out for these
4939c8644cd0SAlan Maguire 	 * and other operations.
4940c8644cd0SAlan Maguire 	 */
4941c8644cd0SAlan Maguire 	if (!capable &&
4942c8644cd0SAlan Maguire 	    (cmd == BPF_MAP_CREATE || cmd == BPF_PROG_LOAD))
494399c55f7dSAlexei Starovoitov 		return -EPERM;
494499c55f7dSAlexei Starovoitov 
4945dcab51f1SMartin KaFai Lau 	err = bpf_check_uarg_tail_zero(uattr, sizeof(attr), size);
494699c55f7dSAlexei Starovoitov 	if (err)
494799c55f7dSAlexei Starovoitov 		return err;
49481e270976SMartin KaFai Lau 	size = min_t(u32, size, sizeof(attr));
494999c55f7dSAlexei Starovoitov 
495099c55f7dSAlexei Starovoitov 	/* copy attributes from user space, may be less than sizeof(bpf_attr) */
49518096f229SGreg Kroah-Hartman 	memset(&attr, 0, sizeof(attr));
4952af2ac3e1SAlexei Starovoitov 	if (copy_from_bpfptr(&attr, uattr, size) != 0)
495399c55f7dSAlexei Starovoitov 		return -EFAULT;
495499c55f7dSAlexei Starovoitov 
4955afdb09c7SChenbo Feng 	err = security_bpf(cmd, &attr, size);
4956afdb09c7SChenbo Feng 	if (err < 0)
4957afdb09c7SChenbo Feng 		return err;
4958afdb09c7SChenbo Feng 
495999c55f7dSAlexei Starovoitov 	switch (cmd) {
496099c55f7dSAlexei Starovoitov 	case BPF_MAP_CREATE:
496199c55f7dSAlexei Starovoitov 		err = map_create(&attr);
496299c55f7dSAlexei Starovoitov 		break;
4963db20fd2bSAlexei Starovoitov 	case BPF_MAP_LOOKUP_ELEM:
4964db20fd2bSAlexei Starovoitov 		err = map_lookup_elem(&attr);
4965db20fd2bSAlexei Starovoitov 		break;
4966db20fd2bSAlexei Starovoitov 	case BPF_MAP_UPDATE_ELEM:
4967af2ac3e1SAlexei Starovoitov 		err = map_update_elem(&attr, uattr);
4968db20fd2bSAlexei Starovoitov 		break;
4969db20fd2bSAlexei Starovoitov 	case BPF_MAP_DELETE_ELEM:
4970b88df697SBenjamin Tissoires 		err = map_delete_elem(&attr, uattr);
4971db20fd2bSAlexei Starovoitov 		break;
4972db20fd2bSAlexei Starovoitov 	case BPF_MAP_GET_NEXT_KEY:
4973db20fd2bSAlexei Starovoitov 		err = map_get_next_key(&attr);
4974db20fd2bSAlexei Starovoitov 		break;
497587df15deSDaniel Borkmann 	case BPF_MAP_FREEZE:
497687df15deSDaniel Borkmann 		err = map_freeze(&attr);
497787df15deSDaniel Borkmann 		break;
497809756af4SAlexei Starovoitov 	case BPF_PROG_LOAD:
4979838e9690SYonghong Song 		err = bpf_prog_load(&attr, uattr);
498009756af4SAlexei Starovoitov 		break;
4981b2197755SDaniel Borkmann 	case BPF_OBJ_PIN:
4982b2197755SDaniel Borkmann 		err = bpf_obj_pin(&attr);
4983b2197755SDaniel Borkmann 		break;
4984b2197755SDaniel Borkmann 	case BPF_OBJ_GET:
4985b2197755SDaniel Borkmann 		err = bpf_obj_get(&attr);
4986b2197755SDaniel Borkmann 		break;
4987f4324551SDaniel Mack 	case BPF_PROG_ATTACH:
4988f4324551SDaniel Mack 		err = bpf_prog_attach(&attr);
4989f4324551SDaniel Mack 		break;
4990f4324551SDaniel Mack 	case BPF_PROG_DETACH:
4991f4324551SDaniel Mack 		err = bpf_prog_detach(&attr);
4992f4324551SDaniel Mack 		break;
4993468e2f64SAlexei Starovoitov 	case BPF_PROG_QUERY:
4994af2ac3e1SAlexei Starovoitov 		err = bpf_prog_query(&attr, uattr.user);
4995468e2f64SAlexei Starovoitov 		break;
49961cf1cae9SAlexei Starovoitov 	case BPF_PROG_TEST_RUN:
4997af2ac3e1SAlexei Starovoitov 		err = bpf_prog_test_run(&attr, uattr.user);
49981cf1cae9SAlexei Starovoitov 		break;
499934ad5580SMartin KaFai Lau 	case BPF_PROG_GET_NEXT_ID:
5000af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
500134ad5580SMartin KaFai Lau 					  &prog_idr, &prog_idr_lock);
500234ad5580SMartin KaFai Lau 		break;
500334ad5580SMartin KaFai Lau 	case BPF_MAP_GET_NEXT_ID:
5004af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
500534ad5580SMartin KaFai Lau 					  &map_idr, &map_idr_lock);
500634ad5580SMartin KaFai Lau 		break;
50071b9ed84eSQuentin Monnet 	case BPF_BTF_GET_NEXT_ID:
5008af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
50091b9ed84eSQuentin Monnet 					  &btf_idr, &btf_idr_lock);
50101b9ed84eSQuentin Monnet 		break;
5011b16d9aa4SMartin KaFai Lau 	case BPF_PROG_GET_FD_BY_ID:
5012b16d9aa4SMartin KaFai Lau 		err = bpf_prog_get_fd_by_id(&attr);
5013b16d9aa4SMartin KaFai Lau 		break;
5014bd5f5f4eSMartin KaFai Lau 	case BPF_MAP_GET_FD_BY_ID:
5015bd5f5f4eSMartin KaFai Lau 		err = bpf_map_get_fd_by_id(&attr);
5016bd5f5f4eSMartin KaFai Lau 		break;
50171e270976SMartin KaFai Lau 	case BPF_OBJ_GET_INFO_BY_FD:
5018af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_info_by_fd(&attr, uattr.user);
50191e270976SMartin KaFai Lau 		break;
5020c4f6699dSAlexei Starovoitov 	case BPF_RAW_TRACEPOINT_OPEN:
5021c4f6699dSAlexei Starovoitov 		err = bpf_raw_tracepoint_open(&attr);
5022c4f6699dSAlexei Starovoitov 		break;
5023f56a653cSMartin KaFai Lau 	case BPF_BTF_LOAD:
5024c571bd75SAlexei Starovoitov 		err = bpf_btf_load(&attr, uattr);
5025f56a653cSMartin KaFai Lau 		break;
502678958fcaSMartin KaFai Lau 	case BPF_BTF_GET_FD_BY_ID:
502778958fcaSMartin KaFai Lau 		err = bpf_btf_get_fd_by_id(&attr);
502878958fcaSMartin KaFai Lau 		break;
502941bdc4b4SYonghong Song 	case BPF_TASK_FD_QUERY:
5030af2ac3e1SAlexei Starovoitov 		err = bpf_task_fd_query(&attr, uattr.user);
503141bdc4b4SYonghong Song 		break;
5032bd513cd0SMauricio Vasquez B 	case BPF_MAP_LOOKUP_AND_DELETE_ELEM:
5033bd513cd0SMauricio Vasquez B 		err = map_lookup_and_delete_elem(&attr);
5034bd513cd0SMauricio Vasquez B 		break;
5035cb4d03abSBrian Vazquez 	case BPF_MAP_LOOKUP_BATCH:
5036af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_LOOKUP_BATCH);
5037cb4d03abSBrian Vazquez 		break;
503805799638SYonghong Song 	case BPF_MAP_LOOKUP_AND_DELETE_BATCH:
5039af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user,
504005799638SYonghong Song 				       BPF_MAP_LOOKUP_AND_DELETE_BATCH);
504105799638SYonghong Song 		break;
5042aa2e93b8SBrian Vazquez 	case BPF_MAP_UPDATE_BATCH:
5043af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_UPDATE_BATCH);
5044aa2e93b8SBrian Vazquez 		break;
5045aa2e93b8SBrian Vazquez 	case BPF_MAP_DELETE_BATCH:
5046af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_DELETE_BATCH);
5047aa2e93b8SBrian Vazquez 		break;
5048af6eea57SAndrii Nakryiko 	case BPF_LINK_CREATE:
5049af2ac3e1SAlexei Starovoitov 		err = link_create(&attr, uattr);
5050af6eea57SAndrii Nakryiko 		break;
50510c991ebcSAndrii Nakryiko 	case BPF_LINK_UPDATE:
50520c991ebcSAndrii Nakryiko 		err = link_update(&attr);
50530c991ebcSAndrii Nakryiko 		break;
50542d602c8cSAndrii Nakryiko 	case BPF_LINK_GET_FD_BY_ID:
50552d602c8cSAndrii Nakryiko 		err = bpf_link_get_fd_by_id(&attr);
50562d602c8cSAndrii Nakryiko 		break;
50572d602c8cSAndrii Nakryiko 	case BPF_LINK_GET_NEXT_ID:
5058af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
50592d602c8cSAndrii Nakryiko 					  &link_idr, &link_idr_lock);
50602d602c8cSAndrii Nakryiko 		break;
5061d46edd67SSong Liu 	case BPF_ENABLE_STATS:
5062d46edd67SSong Liu 		err = bpf_enable_stats(&attr);
5063d46edd67SSong Liu 		break;
5064ac51d99bSYonghong Song 	case BPF_ITER_CREATE:
5065ac51d99bSYonghong Song 		err = bpf_iter_create(&attr);
5066ac51d99bSYonghong Song 		break;
506773b11c2aSAndrii Nakryiko 	case BPF_LINK_DETACH:
506873b11c2aSAndrii Nakryiko 		err = link_detach(&attr);
506973b11c2aSAndrii Nakryiko 		break;
5070ef15314aSYiFei Zhu 	case BPF_PROG_BIND_MAP:
5071ef15314aSYiFei Zhu 		err = bpf_prog_bind_map(&attr);
5072ef15314aSYiFei Zhu 		break;
507399c55f7dSAlexei Starovoitov 	default:
507499c55f7dSAlexei Starovoitov 		err = -EINVAL;
507599c55f7dSAlexei Starovoitov 		break;
507699c55f7dSAlexei Starovoitov 	}
507799c55f7dSAlexei Starovoitov 
507899c55f7dSAlexei Starovoitov 	return err;
507999c55f7dSAlexei Starovoitov }
508079a7f8bdSAlexei Starovoitov 
5081af2ac3e1SAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
5082af2ac3e1SAlexei Starovoitov {
5083af2ac3e1SAlexei Starovoitov 	return __sys_bpf(cmd, USER_BPFPTR(uattr), size);
5084af2ac3e1SAlexei Starovoitov }
5085af2ac3e1SAlexei Starovoitov 
508679a7f8bdSAlexei Starovoitov static bool syscall_prog_is_valid_access(int off, int size,
508779a7f8bdSAlexei Starovoitov 					 enum bpf_access_type type,
508879a7f8bdSAlexei Starovoitov 					 const struct bpf_prog *prog,
508979a7f8bdSAlexei Starovoitov 					 struct bpf_insn_access_aux *info)
509079a7f8bdSAlexei Starovoitov {
509179a7f8bdSAlexei Starovoitov 	if (off < 0 || off >= U16_MAX)
509279a7f8bdSAlexei Starovoitov 		return false;
509379a7f8bdSAlexei Starovoitov 	if (off % size != 0)
509479a7f8bdSAlexei Starovoitov 		return false;
509579a7f8bdSAlexei Starovoitov 	return true;
509679a7f8bdSAlexei Starovoitov }
509779a7f8bdSAlexei Starovoitov 
5098b1d18a75SAlexei Starovoitov BPF_CALL_3(bpf_sys_bpf, int, cmd, union bpf_attr *, attr, u32, attr_size)
509979a7f8bdSAlexei Starovoitov {
5100af2ac3e1SAlexei Starovoitov 	switch (cmd) {
5101af2ac3e1SAlexei Starovoitov 	case BPF_MAP_CREATE:
5102b88df697SBenjamin Tissoires 	case BPF_MAP_DELETE_ELEM:
5103af2ac3e1SAlexei Starovoitov 	case BPF_MAP_UPDATE_ELEM:
5104af2ac3e1SAlexei Starovoitov 	case BPF_MAP_FREEZE:
5105b88df697SBenjamin Tissoires 	case BPF_MAP_GET_FD_BY_ID:
5106af2ac3e1SAlexei Starovoitov 	case BPF_PROG_LOAD:
5107c571bd75SAlexei Starovoitov 	case BPF_BTF_LOAD:
5108b1d18a75SAlexei Starovoitov 	case BPF_LINK_CREATE:
5109b1d18a75SAlexei Starovoitov 	case BPF_RAW_TRACEPOINT_OPEN:
5110af2ac3e1SAlexei Starovoitov 		break;
511186f44fceSAlexei Starovoitov 	default:
511286f44fceSAlexei Starovoitov 		return -EINVAL;
511386f44fceSAlexei Starovoitov 	}
511486f44fceSAlexei Starovoitov 	return __sys_bpf(cmd, KERNEL_BPFPTR(attr), attr_size);
511586f44fceSAlexei Starovoitov }
511686f44fceSAlexei Starovoitov 
51174e4588f1SAlexei Starovoitov 
51184e4588f1SAlexei Starovoitov /* To shut up -Wmissing-prototypes.
51194e4588f1SAlexei Starovoitov  * This function is used by the kernel light skeleton
51204e4588f1SAlexei Starovoitov  * to load bpf programs when modules are loaded or during kernel boot.
51214e4588f1SAlexei Starovoitov  * See tools/lib/bpf/skel_internal.h
51224e4588f1SAlexei Starovoitov  */
51234e4588f1SAlexei Starovoitov int kern_sys_bpf(int cmd, union bpf_attr *attr, unsigned int size);
51244e4588f1SAlexei Starovoitov 
512586f44fceSAlexei Starovoitov int kern_sys_bpf(int cmd, union bpf_attr *attr, unsigned int size)
512686f44fceSAlexei Starovoitov {
512786f44fceSAlexei Starovoitov 	struct bpf_prog * __maybe_unused prog;
512886f44fceSAlexei Starovoitov 	struct bpf_tramp_run_ctx __maybe_unused run_ctx;
512986f44fceSAlexei Starovoitov 
513086f44fceSAlexei Starovoitov 	switch (cmd) {
5131b1d18a75SAlexei Starovoitov #ifdef CONFIG_BPF_JIT /* __bpf_prog_enter_sleepable used by trampoline and JIT */
5132b1d18a75SAlexei Starovoitov 	case BPF_PROG_TEST_RUN:
5133b1d18a75SAlexei Starovoitov 		if (attr->test.data_in || attr->test.data_out ||
5134b1d18a75SAlexei Starovoitov 		    attr->test.ctx_out || attr->test.duration ||
5135b1d18a75SAlexei Starovoitov 		    attr->test.repeat || attr->test.flags)
5136b1d18a75SAlexei Starovoitov 			return -EINVAL;
5137b1d18a75SAlexei Starovoitov 
5138b1d18a75SAlexei Starovoitov 		prog = bpf_prog_get_type(attr->test.prog_fd, BPF_PROG_TYPE_SYSCALL);
5139b1d18a75SAlexei Starovoitov 		if (IS_ERR(prog))
5140b1d18a75SAlexei Starovoitov 			return PTR_ERR(prog);
5141b1d18a75SAlexei Starovoitov 
5142b1d18a75SAlexei Starovoitov 		if (attr->test.ctx_size_in < prog->aux->max_ctx_offset ||
5143b1d18a75SAlexei Starovoitov 		    attr->test.ctx_size_in > U16_MAX) {
5144b1d18a75SAlexei Starovoitov 			bpf_prog_put(prog);
5145b1d18a75SAlexei Starovoitov 			return -EINVAL;
5146b1d18a75SAlexei Starovoitov 		}
5147b1d18a75SAlexei Starovoitov 
5148e384c7b7SKui-Feng Lee 		run_ctx.bpf_cookie = 0;
5149e384c7b7SKui-Feng Lee 		run_ctx.saved_run_ctx = NULL;
5150271de525SMartin KaFai Lau 		if (!__bpf_prog_enter_sleepable_recur(prog, &run_ctx)) {
5151b1d18a75SAlexei Starovoitov 			/* recursion detected */
5152b1d18a75SAlexei Starovoitov 			bpf_prog_put(prog);
5153b1d18a75SAlexei Starovoitov 			return -EBUSY;
5154b1d18a75SAlexei Starovoitov 		}
5155b1d18a75SAlexei Starovoitov 		attr->test.retval = bpf_prog_run(prog, (void *) (long) attr->test.ctx_in);
5156271de525SMartin KaFai Lau 		__bpf_prog_exit_sleepable_recur(prog, 0 /* bpf_prog_run does runtime stats */,
5157271de525SMartin KaFai Lau 						&run_ctx);
5158b1d18a75SAlexei Starovoitov 		bpf_prog_put(prog);
5159b1d18a75SAlexei Starovoitov 		return 0;
5160b1d18a75SAlexei Starovoitov #endif
5161af2ac3e1SAlexei Starovoitov 	default:
516286f44fceSAlexei Starovoitov 		return ____bpf_sys_bpf(cmd, attr, size);
516379a7f8bdSAlexei Starovoitov 	}
5164af2ac3e1SAlexei Starovoitov }
516586f44fceSAlexei Starovoitov EXPORT_SYMBOL(kern_sys_bpf);
516679a7f8bdSAlexei Starovoitov 
51673a2daa72SPu Lehui static const struct bpf_func_proto bpf_sys_bpf_proto = {
516879a7f8bdSAlexei Starovoitov 	.func		= bpf_sys_bpf,
516979a7f8bdSAlexei Starovoitov 	.gpl_only	= false,
517079a7f8bdSAlexei Starovoitov 	.ret_type	= RET_INTEGER,
517179a7f8bdSAlexei Starovoitov 	.arg1_type	= ARG_ANYTHING,
5172216e3cd2SHao Luo 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
517379a7f8bdSAlexei Starovoitov 	.arg3_type	= ARG_CONST_SIZE,
517479a7f8bdSAlexei Starovoitov };
517579a7f8bdSAlexei Starovoitov 
517679a7f8bdSAlexei Starovoitov const struct bpf_func_proto * __weak
517779a7f8bdSAlexei Starovoitov tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
517879a7f8bdSAlexei Starovoitov {
517979a7f8bdSAlexei Starovoitov 	return bpf_base_func_proto(func_id);
518079a7f8bdSAlexei Starovoitov }
518179a7f8bdSAlexei Starovoitov 
51823abea089SAlexei Starovoitov BPF_CALL_1(bpf_sys_close, u32, fd)
51833abea089SAlexei Starovoitov {
51843abea089SAlexei Starovoitov 	/* When bpf program calls this helper there should not be
51853abea089SAlexei Starovoitov 	 * an fdget() without matching completed fdput().
51863abea089SAlexei Starovoitov 	 * This helper is allowed in the following callchain only:
51873abea089SAlexei Starovoitov 	 * sys_bpf->prog_test_run->bpf_prog->bpf_sys_close
51883abea089SAlexei Starovoitov 	 */
51893abea089SAlexei Starovoitov 	return close_fd(fd);
51903abea089SAlexei Starovoitov }
51913abea089SAlexei Starovoitov 
51923a2daa72SPu Lehui static const struct bpf_func_proto bpf_sys_close_proto = {
51933abea089SAlexei Starovoitov 	.func		= bpf_sys_close,
51943abea089SAlexei Starovoitov 	.gpl_only	= false,
51953abea089SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
51963abea089SAlexei Starovoitov 	.arg1_type	= ARG_ANYTHING,
51973abea089SAlexei Starovoitov };
51983abea089SAlexei Starovoitov 
5199d6aef08aSKumar Kartikeya Dwivedi BPF_CALL_4(bpf_kallsyms_lookup_name, const char *, name, int, name_sz, int, flags, u64 *, res)
5200d6aef08aSKumar Kartikeya Dwivedi {
5201d6aef08aSKumar Kartikeya Dwivedi 	if (flags)
5202d6aef08aSKumar Kartikeya Dwivedi 		return -EINVAL;
5203d6aef08aSKumar Kartikeya Dwivedi 
5204d6aef08aSKumar Kartikeya Dwivedi 	if (name_sz <= 1 || name[name_sz - 1])
5205d6aef08aSKumar Kartikeya Dwivedi 		return -EINVAL;
5206d6aef08aSKumar Kartikeya Dwivedi 
5207d6aef08aSKumar Kartikeya Dwivedi 	if (!bpf_dump_raw_ok(current_cred()))
5208d6aef08aSKumar Kartikeya Dwivedi 		return -EPERM;
5209d6aef08aSKumar Kartikeya Dwivedi 
5210d6aef08aSKumar Kartikeya Dwivedi 	*res = kallsyms_lookup_name(name);
5211d6aef08aSKumar Kartikeya Dwivedi 	return *res ? 0 : -ENOENT;
5212d6aef08aSKumar Kartikeya Dwivedi }
5213d6aef08aSKumar Kartikeya Dwivedi 
5214dc368e1cSJoanne Koong static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
5215d6aef08aSKumar Kartikeya Dwivedi 	.func		= bpf_kallsyms_lookup_name,
5216d6aef08aSKumar Kartikeya Dwivedi 	.gpl_only	= false,
5217d6aef08aSKumar Kartikeya Dwivedi 	.ret_type	= RET_INTEGER,
5218d6aef08aSKumar Kartikeya Dwivedi 	.arg1_type	= ARG_PTR_TO_MEM,
5219d4efb170SKumar Kartikeya Dwivedi 	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
5220d6aef08aSKumar Kartikeya Dwivedi 	.arg3_type	= ARG_ANYTHING,
5221d6aef08aSKumar Kartikeya Dwivedi 	.arg4_type	= ARG_PTR_TO_LONG,
5222d6aef08aSKumar Kartikeya Dwivedi };
5223d6aef08aSKumar Kartikeya Dwivedi 
522479a7f8bdSAlexei Starovoitov static const struct bpf_func_proto *
522579a7f8bdSAlexei Starovoitov syscall_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
522679a7f8bdSAlexei Starovoitov {
522779a7f8bdSAlexei Starovoitov 	switch (func_id) {
522879a7f8bdSAlexei Starovoitov 	case BPF_FUNC_sys_bpf:
522914b20b78SYiFei Zhu 		return !perfmon_capable() ? NULL : &bpf_sys_bpf_proto;
52303d78417bSAlexei Starovoitov 	case BPF_FUNC_btf_find_by_name_kind:
52313d78417bSAlexei Starovoitov 		return &bpf_btf_find_by_name_kind_proto;
52323abea089SAlexei Starovoitov 	case BPF_FUNC_sys_close:
52333abea089SAlexei Starovoitov 		return &bpf_sys_close_proto;
5234d6aef08aSKumar Kartikeya Dwivedi 	case BPF_FUNC_kallsyms_lookup_name:
5235d6aef08aSKumar Kartikeya Dwivedi 		return &bpf_kallsyms_lookup_name_proto;
523679a7f8bdSAlexei Starovoitov 	default:
523779a7f8bdSAlexei Starovoitov 		return tracing_prog_func_proto(func_id, prog);
523879a7f8bdSAlexei Starovoitov 	}
523979a7f8bdSAlexei Starovoitov }
524079a7f8bdSAlexei Starovoitov 
524179a7f8bdSAlexei Starovoitov const struct bpf_verifier_ops bpf_syscall_verifier_ops = {
524279a7f8bdSAlexei Starovoitov 	.get_func_proto  = syscall_prog_func_proto,
524379a7f8bdSAlexei Starovoitov 	.is_valid_access = syscall_prog_is_valid_access,
524479a7f8bdSAlexei Starovoitov };
524579a7f8bdSAlexei Starovoitov 
524679a7f8bdSAlexei Starovoitov const struct bpf_prog_ops bpf_syscall_prog_ops = {
524779a7f8bdSAlexei Starovoitov 	.test_run = bpf_prog_test_run_syscall,
524879a7f8bdSAlexei Starovoitov };
52492900005eSYan Zhu 
52502900005eSYan Zhu #ifdef CONFIG_SYSCTL
52512900005eSYan Zhu static int bpf_stats_handler(struct ctl_table *table, int write,
52522900005eSYan Zhu 			     void *buffer, size_t *lenp, loff_t *ppos)
52532900005eSYan Zhu {
52542900005eSYan Zhu 	struct static_key *key = (struct static_key *)table->data;
52552900005eSYan Zhu 	static int saved_val;
52562900005eSYan Zhu 	int val, ret;
52572900005eSYan Zhu 	struct ctl_table tmp = {
52582900005eSYan Zhu 		.data   = &val,
52592900005eSYan Zhu 		.maxlen = sizeof(val),
52602900005eSYan Zhu 		.mode   = table->mode,
52612900005eSYan Zhu 		.extra1 = SYSCTL_ZERO,
52622900005eSYan Zhu 		.extra2 = SYSCTL_ONE,
52632900005eSYan Zhu 	};
52642900005eSYan Zhu 
52652900005eSYan Zhu 	if (write && !capable(CAP_SYS_ADMIN))
52662900005eSYan Zhu 		return -EPERM;
52672900005eSYan Zhu 
52682900005eSYan Zhu 	mutex_lock(&bpf_stats_enabled_mutex);
52692900005eSYan Zhu 	val = saved_val;
52702900005eSYan Zhu 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
52712900005eSYan Zhu 	if (write && !ret && val != saved_val) {
52722900005eSYan Zhu 		if (val)
52732900005eSYan Zhu 			static_key_slow_inc(key);
52742900005eSYan Zhu 		else
52752900005eSYan Zhu 			static_key_slow_dec(key);
52762900005eSYan Zhu 		saved_val = val;
52772900005eSYan Zhu 	}
52782900005eSYan Zhu 	mutex_unlock(&bpf_stats_enabled_mutex);
52792900005eSYan Zhu 	return ret;
52802900005eSYan Zhu }
52812900005eSYan Zhu 
52822900005eSYan Zhu void __weak unpriv_ebpf_notify(int new_state)
52832900005eSYan Zhu {
52842900005eSYan Zhu }
52852900005eSYan Zhu 
52862900005eSYan Zhu static int bpf_unpriv_handler(struct ctl_table *table, int write,
52872900005eSYan Zhu 			      void *buffer, size_t *lenp, loff_t *ppos)
52882900005eSYan Zhu {
52892900005eSYan Zhu 	int ret, unpriv_enable = *(int *)table->data;
52902900005eSYan Zhu 	bool locked_state = unpriv_enable == 1;
52912900005eSYan Zhu 	struct ctl_table tmp = *table;
52922900005eSYan Zhu 
52932900005eSYan Zhu 	if (write && !capable(CAP_SYS_ADMIN))
52942900005eSYan Zhu 		return -EPERM;
52952900005eSYan Zhu 
52962900005eSYan Zhu 	tmp.data = &unpriv_enable;
52972900005eSYan Zhu 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
52982900005eSYan Zhu 	if (write && !ret) {
52992900005eSYan Zhu 		if (locked_state && unpriv_enable != 1)
53002900005eSYan Zhu 			return -EPERM;
53012900005eSYan Zhu 		*(int *)table->data = unpriv_enable;
53022900005eSYan Zhu 	}
53032900005eSYan Zhu 
53042900005eSYan Zhu 	unpriv_ebpf_notify(unpriv_enable);
53052900005eSYan Zhu 
53062900005eSYan Zhu 	return ret;
53072900005eSYan Zhu }
53082900005eSYan Zhu 
53092900005eSYan Zhu static struct ctl_table bpf_syscall_table[] = {
53102900005eSYan Zhu 	{
53112900005eSYan Zhu 		.procname	= "unprivileged_bpf_disabled",
53122900005eSYan Zhu 		.data		= &sysctl_unprivileged_bpf_disabled,
53132900005eSYan Zhu 		.maxlen		= sizeof(sysctl_unprivileged_bpf_disabled),
53142900005eSYan Zhu 		.mode		= 0644,
53152900005eSYan Zhu 		.proc_handler	= bpf_unpriv_handler,
53162900005eSYan Zhu 		.extra1		= SYSCTL_ZERO,
53172900005eSYan Zhu 		.extra2		= SYSCTL_TWO,
53182900005eSYan Zhu 	},
53192900005eSYan Zhu 	{
53202900005eSYan Zhu 		.procname	= "bpf_stats_enabled",
53212900005eSYan Zhu 		.data		= &bpf_stats_enabled_key.key,
53222900005eSYan Zhu 		.maxlen		= sizeof(bpf_stats_enabled_key),
53232900005eSYan Zhu 		.mode		= 0644,
53242900005eSYan Zhu 		.proc_handler	= bpf_stats_handler,
53252900005eSYan Zhu 	},
53262900005eSYan Zhu 	{ }
53272900005eSYan Zhu };
53282900005eSYan Zhu 
53292900005eSYan Zhu static int __init bpf_syscall_sysctl_init(void)
53302900005eSYan Zhu {
53312900005eSYan Zhu 	register_sysctl_init("kernel", bpf_syscall_table);
53322900005eSYan Zhu 	return 0;
53332900005eSYan Zhu }
53342900005eSYan Zhu late_initcall(bpf_syscall_sysctl_init);
53352900005eSYan Zhu #endif /* CONFIG_SYSCTL */
5336