xref: /linux/kernel/bpf/syscall.c (revision 2884dc7d08d98a89d8d65121524bb7533183a63a)
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 
3935dfaad7SDaniel Borkmann #include <net/netfilter/nf_bpf_link.h>
4035dfaad7SDaniel Borkmann #include <net/netkit.h>
41e420bed0SDaniel Borkmann #include <net/tcx.h>
42e420bed0SDaniel Borkmann 
43da765a2fSDaniel Borkmann #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \
4414dc6f04SMartin KaFai Lau 			  (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \
4514dc6f04SMartin KaFai Lau 			  (map)->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS)
46da765a2fSDaniel Borkmann #define IS_FD_PROG_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY)
4714dc6f04SMartin KaFai Lau #define IS_FD_HASH(map) ((map)->map_type == BPF_MAP_TYPE_HASH_OF_MAPS)
48da765a2fSDaniel Borkmann #define IS_FD_MAP(map) (IS_FD_ARRAY(map) || IS_FD_PROG_ARRAY(map) || \
49da765a2fSDaniel Borkmann 			IS_FD_HASH(map))
5014dc6f04SMartin KaFai Lau 
516e71b04aSChenbo Feng #define BPF_OBJ_FLAG_MASK   (BPF_F_RDONLY | BPF_F_WRONLY)
526e71b04aSChenbo Feng 
53b121d1e7SAlexei Starovoitov DEFINE_PER_CPU(int, bpf_prog_active);
54dc4bb0e2SMartin KaFai Lau static DEFINE_IDR(prog_idr);
55dc4bb0e2SMartin KaFai Lau static DEFINE_SPINLOCK(prog_idr_lock);
56f3f1c054SMartin KaFai Lau static DEFINE_IDR(map_idr);
57f3f1c054SMartin KaFai Lau static DEFINE_SPINLOCK(map_idr_lock);
58a3b80e10SAndrii Nakryiko static DEFINE_IDR(link_idr);
59a3b80e10SAndrii Nakryiko static DEFINE_SPINLOCK(link_idr_lock);
60b121d1e7SAlexei Starovoitov 
6108389d88SDaniel Borkmann int sysctl_unprivileged_bpf_disabled __read_mostly =
6208389d88SDaniel Borkmann 	IS_BUILTIN(CONFIG_BPF_UNPRIV_DEFAULT_OFF) ? 2 : 0;
631be7f75dSAlexei Starovoitov 
6440077e0cSJohannes Berg static const struct bpf_map_ops * const bpf_map_types[] = {
6591cc1a99SAlexei Starovoitov #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type)
6640077e0cSJohannes Berg #define BPF_MAP_TYPE(_id, _ops) \
6740077e0cSJohannes Berg 	[_id] = &_ops,
68f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name)
6940077e0cSJohannes Berg #include <linux/bpf_types.h>
7040077e0cSJohannes Berg #undef BPF_PROG_TYPE
7140077e0cSJohannes Berg #undef BPF_MAP_TYPE
72f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE
7340077e0cSJohannes Berg };
7499c55f7dSAlexei Starovoitov 
75752ba56fSMickaël Salaün /*
76752ba56fSMickaël Salaün  * If we're handed a bigger struct than we know of, ensure all the unknown bits
77752ba56fSMickaël Salaün  * are 0 - i.e. new user-space does not rely on any kernel feature extensions
78752ba56fSMickaël Salaün  * we don't know about yet.
79752ba56fSMickaël Salaün  *
80752ba56fSMickaël Salaün  * There is a ToCToU between this function call and the following
81752ba56fSMickaël Salaün  * copy_from_user() call. However, this is not a concern since this function is
82752ba56fSMickaël Salaün  * meant to be a future-proofing of bits.
83752ba56fSMickaël Salaün  */
84af2ac3e1SAlexei Starovoitov int bpf_check_uarg_tail_zero(bpfptr_t uaddr,
8558291a74SMickaël Salaün 			     size_t expected_size,
8658291a74SMickaël Salaün 			     size_t actual_size)
8758291a74SMickaël Salaün {
88b7e4b65fSAl Viro 	int res;
8958291a74SMickaël Salaün 
90752ba56fSMickaël Salaün 	if (unlikely(actual_size > PAGE_SIZE))	/* silly large */
91752ba56fSMickaël Salaün 		return -E2BIG;
92752ba56fSMickaël Salaün 
9358291a74SMickaël Salaün 	if (actual_size <= expected_size)
9458291a74SMickaël Salaün 		return 0;
9558291a74SMickaël Salaün 
96af2ac3e1SAlexei Starovoitov 	if (uaddr.is_kernel)
97af2ac3e1SAlexei Starovoitov 		res = memchr_inv(uaddr.kernel + expected_size, 0,
98af2ac3e1SAlexei Starovoitov 				 actual_size - expected_size) == NULL;
99af2ac3e1SAlexei Starovoitov 	else
100af2ac3e1SAlexei Starovoitov 		res = check_zeroed_user(uaddr.user + expected_size,
101af2ac3e1SAlexei Starovoitov 					actual_size - expected_size);
102b7e4b65fSAl Viro 	if (res < 0)
103b7e4b65fSAl Viro 		return res;
104b7e4b65fSAl Viro 	return res ? 0 : -E2BIG;
10558291a74SMickaël Salaün }
10658291a74SMickaël Salaün 
107a3884572SJakub Kicinski const struct bpf_map_ops bpf_map_offload_ops = {
108f4d05259SMartin KaFai Lau 	.map_meta_equal = bpf_map_meta_equal,
109a3884572SJakub Kicinski 	.map_alloc = bpf_map_offload_map_alloc,
110a3884572SJakub Kicinski 	.map_free = bpf_map_offload_map_free,
111e8d2bec0SDaniel Borkmann 	.map_check_btf = map_check_no_btf,
1129629363cSYafang Shao 	.map_mem_usage = bpf_map_offload_map_mem_usage,
113a3884572SJakub Kicinski };
114a3884572SJakub Kicinski 
115353050beSDaniel Borkmann static void bpf_map_write_active_inc(struct bpf_map *map)
116353050beSDaniel Borkmann {
117353050beSDaniel Borkmann 	atomic64_inc(&map->writecnt);
118353050beSDaniel Borkmann }
119353050beSDaniel Borkmann 
120353050beSDaniel Borkmann static void bpf_map_write_active_dec(struct bpf_map *map)
121353050beSDaniel Borkmann {
122353050beSDaniel Borkmann 	atomic64_dec(&map->writecnt);
123353050beSDaniel Borkmann }
124353050beSDaniel Borkmann 
125353050beSDaniel Borkmann bool bpf_map_write_active(const struct bpf_map *map)
126353050beSDaniel Borkmann {
127353050beSDaniel Borkmann 	return atomic64_read(&map->writecnt) != 0;
128353050beSDaniel Borkmann }
129353050beSDaniel Borkmann 
13080ee81e0SRoman Gushchin static u32 bpf_map_value_size(const struct bpf_map *map)
13115c14a3dSBrian Vazquez {
13215c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
13315c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
13415c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY ||
13515c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE)
13615c14a3dSBrian Vazquez 		return round_up(map->value_size, 8) * num_possible_cpus();
13715c14a3dSBrian Vazquez 	else if (IS_FD_MAP(map))
13815c14a3dSBrian Vazquez 		return sizeof(u32);
13915c14a3dSBrian Vazquez 	else
14015c14a3dSBrian Vazquez 		return  map->value_size;
14115c14a3dSBrian Vazquez }
14215c14a3dSBrian Vazquez 
14315c14a3dSBrian Vazquez static void maybe_wait_bpf_programs(struct bpf_map *map)
14415c14a3dSBrian Vazquez {
1452a0c6b41SHou Tao 	/* Wait for any running non-sleepable BPF programs to complete so that
1462a0c6b41SHou Tao 	 * userspace, when we return to it, knows that all non-sleepable
1472a0c6b41SHou Tao 	 * programs that could be running use the new map value. For sleepable
1482a0c6b41SHou Tao 	 * BPF programs, synchronize_rcu_tasks_trace() should be used to wait
1492a0c6b41SHou Tao 	 * for the completions of these programs, but considering the waiting
1502a0c6b41SHou Tao 	 * time can be very long and userspace may think it will hang forever,
1512a0c6b41SHou Tao 	 * so don't handle sleepable BPF programs now.
15215c14a3dSBrian Vazquez 	 */
15315c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS ||
15415c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS)
15515c14a3dSBrian Vazquez 		synchronize_rcu();
15615c14a3dSBrian Vazquez }
15715c14a3dSBrian Vazquez 
1583af43ba4SHou Tao static int bpf_map_update_value(struct bpf_map *map, struct file *map_file,
1593af43ba4SHou Tao 				void *key, void *value, __u64 flags)
16015c14a3dSBrian Vazquez {
16115c14a3dSBrian Vazquez 	int err;
16215c14a3dSBrian Vazquez 
16315c14a3dSBrian Vazquez 	/* Need to create a kthread, thus must support schedule */
1649d03ebc7SStanislav Fomichev 	if (bpf_map_is_offloaded(map)) {
16515c14a3dSBrian Vazquez 		return bpf_map_offload_update_elem(map, key, value, flags);
16615c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_CPUMAP ||
16731746031SAlexei Starovoitov 		   map->map_type == BPF_MAP_TYPE_ARENA ||
16815c14a3dSBrian Vazquez 		   map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
16915c14a3dSBrian Vazquez 		return map->ops->map_update_elem(map, key, value, flags);
17013b79d3fSLorenz Bauer 	} else if (map->map_type == BPF_MAP_TYPE_SOCKHASH ||
17113b79d3fSLorenz Bauer 		   map->map_type == BPF_MAP_TYPE_SOCKMAP) {
17213b79d3fSLorenz Bauer 		return sock_map_update_elem_sys(map, key, value, flags);
17315c14a3dSBrian Vazquez 	} else if (IS_FD_PROG_ARRAY(map)) {
1743af43ba4SHou Tao 		return bpf_fd_array_map_update_elem(map, map_file, key, value,
17515c14a3dSBrian Vazquez 						    flags);
17615c14a3dSBrian Vazquez 	}
17715c14a3dSBrian Vazquez 
178b6e5dae1SThomas Gleixner 	bpf_disable_instrumentation();
17915c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
18015c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
18115c14a3dSBrian Vazquez 		err = bpf_percpu_hash_update(map, key, value, flags);
18215c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
18315c14a3dSBrian Vazquez 		err = bpf_percpu_array_update(map, key, value, flags);
18415c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
18515c14a3dSBrian Vazquez 		err = bpf_percpu_cgroup_storage_update(map, key, value,
18615c14a3dSBrian Vazquez 						       flags);
18715c14a3dSBrian Vazquez 	} else if (IS_FD_ARRAY(map)) {
1883af43ba4SHou Tao 		err = bpf_fd_array_map_update_elem(map, map_file, key, value,
18915c14a3dSBrian Vazquez 						   flags);
19015c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) {
1913af43ba4SHou Tao 		err = bpf_fd_htab_map_update_elem(map, map_file, key, value,
19215c14a3dSBrian Vazquez 						  flags);
19315c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
19415c14a3dSBrian Vazquez 		/* rcu_read_lock() is not needed */
19515c14a3dSBrian Vazquez 		err = bpf_fd_reuseport_array_update_elem(map, key, value,
19615c14a3dSBrian Vazquez 							 flags);
19715c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
1989330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_STACK ||
1999330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) {
20015c14a3dSBrian Vazquez 		err = map->ops->map_push_elem(map, value, flags);
20115c14a3dSBrian Vazquez 	} else {
20215c14a3dSBrian Vazquez 		rcu_read_lock();
20315c14a3dSBrian Vazquez 		err = map->ops->map_update_elem(map, key, value, flags);
20415c14a3dSBrian Vazquez 		rcu_read_unlock();
20515c14a3dSBrian Vazquez 	}
206b6e5dae1SThomas Gleixner 	bpf_enable_instrumentation();
20715c14a3dSBrian Vazquez 
20815c14a3dSBrian Vazquez 	return err;
20915c14a3dSBrian Vazquez }
21015c14a3dSBrian Vazquez 
21115c14a3dSBrian Vazquez static int bpf_map_copy_value(struct bpf_map *map, void *key, void *value,
21215c14a3dSBrian Vazquez 			      __u64 flags)
21315c14a3dSBrian Vazquez {
21415c14a3dSBrian Vazquez 	void *ptr;
21515c14a3dSBrian Vazquez 	int err;
21615c14a3dSBrian Vazquez 
2179d03ebc7SStanislav Fomichev 	if (bpf_map_is_offloaded(map))
218cb4d03abSBrian Vazquez 		return bpf_map_offload_lookup_elem(map, key, value);
21915c14a3dSBrian Vazquez 
220b6e5dae1SThomas Gleixner 	bpf_disable_instrumentation();
22115c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
22215c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
22315c14a3dSBrian Vazquez 		err = bpf_percpu_hash_copy(map, key, value);
22415c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
22515c14a3dSBrian Vazquez 		err = bpf_percpu_array_copy(map, key, value);
22615c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
22715c14a3dSBrian Vazquez 		err = bpf_percpu_cgroup_storage_copy(map, key, value);
22815c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) {
22915c14a3dSBrian Vazquez 		err = bpf_stackmap_copy(map, key, value);
23015c14a3dSBrian Vazquez 	} else if (IS_FD_ARRAY(map) || IS_FD_PROG_ARRAY(map)) {
23115c14a3dSBrian Vazquez 		err = bpf_fd_array_map_lookup_elem(map, key, value);
23215c14a3dSBrian Vazquez 	} else if (IS_FD_HASH(map)) {
23315c14a3dSBrian Vazquez 		err = bpf_fd_htab_map_lookup_elem(map, key, value);
23415c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
23515c14a3dSBrian Vazquez 		err = bpf_fd_reuseport_array_lookup_elem(map, key, value);
23615c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
2379330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_STACK ||
2389330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) {
23915c14a3dSBrian Vazquez 		err = map->ops->map_peek_elem(map, value);
24015c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
24115c14a3dSBrian Vazquez 		/* struct_ops map requires directly updating "value" */
24215c14a3dSBrian Vazquez 		err = bpf_struct_ops_map_sys_lookup_elem(map, key, value);
24315c14a3dSBrian Vazquez 	} else {
24415c14a3dSBrian Vazquez 		rcu_read_lock();
24515c14a3dSBrian Vazquez 		if (map->ops->map_lookup_elem_sys_only)
24615c14a3dSBrian Vazquez 			ptr = map->ops->map_lookup_elem_sys_only(map, key);
24715c14a3dSBrian Vazquez 		else
24815c14a3dSBrian Vazquez 			ptr = map->ops->map_lookup_elem(map, key);
24915c14a3dSBrian Vazquez 		if (IS_ERR(ptr)) {
25015c14a3dSBrian Vazquez 			err = PTR_ERR(ptr);
25115c14a3dSBrian Vazquez 		} else if (!ptr) {
25215c14a3dSBrian Vazquez 			err = -ENOENT;
25315c14a3dSBrian Vazquez 		} else {
25415c14a3dSBrian Vazquez 			err = 0;
25515c14a3dSBrian Vazquez 			if (flags & BPF_F_LOCK)
25615c14a3dSBrian Vazquez 				/* lock 'ptr' and copy everything but lock */
25715c14a3dSBrian Vazquez 				copy_map_value_locked(map, value, ptr, true);
25815c14a3dSBrian Vazquez 			else
25915c14a3dSBrian Vazquez 				copy_map_value(map, value, ptr);
26068134668SAlexei Starovoitov 			/* mask lock and timer, since value wasn't zero inited */
26168134668SAlexei Starovoitov 			check_and_init_map_value(map, value);
26215c14a3dSBrian Vazquez 		}
26315c14a3dSBrian Vazquez 		rcu_read_unlock();
26415c14a3dSBrian Vazquez 	}
26515c14a3dSBrian Vazquez 
266b6e5dae1SThomas Gleixner 	bpf_enable_instrumentation();
26715c14a3dSBrian Vazquez 
26815c14a3dSBrian Vazquez 	return err;
26915c14a3dSBrian Vazquez }
27015c14a3dSBrian Vazquez 
271d5299b67SRoman Gushchin /* Please, do not use this function outside from the map creation path
272d5299b67SRoman Gushchin  * (e.g. in map update path) without taking care of setting the active
273d5299b67SRoman Gushchin  * memory cgroup (see at bpf_map_kmalloc_node() for example).
274d5299b67SRoman Gushchin  */
275196e8ca7SDaniel Borkmann static void *__bpf_map_area_alloc(u64 size, int numa_node, bool mmapable)
276d407bd25SDaniel Borkmann {
277f01a7dbeSMartynas Pumputis 	/* We really just want to fail instead of triggering OOM killer
278f01a7dbeSMartynas Pumputis 	 * under memory pressure, therefore we set __GFP_NORETRY to kmalloc,
279f01a7dbeSMartynas Pumputis 	 * which is used for lower order allocation requests.
280f01a7dbeSMartynas Pumputis 	 *
281f01a7dbeSMartynas Pumputis 	 * It has been observed that higher order allocation requests done by
282f01a7dbeSMartynas Pumputis 	 * vmalloc with __GFP_NORETRY being set might fail due to not trying
283f01a7dbeSMartynas Pumputis 	 * to reclaim memory from the page cache, thus we set
284f01a7dbeSMartynas Pumputis 	 * __GFP_RETRY_MAYFAIL to avoid such situations.
285d407bd25SDaniel Borkmann 	 */
286f01a7dbeSMartynas Pumputis 
287ee53cbfbSYafang Shao 	gfp_t gfp = bpf_memcg_flags(__GFP_NOWARN | __GFP_ZERO);
288041de93fSChristoph Hellwig 	unsigned int flags = 0;
289041de93fSChristoph Hellwig 	unsigned long align = 1;
290d407bd25SDaniel Borkmann 	void *area;
291d407bd25SDaniel Borkmann 
292196e8ca7SDaniel Borkmann 	if (size >= SIZE_MAX)
293196e8ca7SDaniel Borkmann 		return NULL;
294196e8ca7SDaniel Borkmann 
295fc970227SAndrii Nakryiko 	/* kmalloc()'ed memory can't be mmap()'ed */
296041de93fSChristoph Hellwig 	if (mmapable) {
297041de93fSChristoph Hellwig 		BUG_ON(!PAGE_ALIGNED(size));
298041de93fSChristoph Hellwig 		align = SHMLBA;
299041de93fSChristoph Hellwig 		flags = VM_USERMAP;
300041de93fSChristoph Hellwig 	} else if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
301041de93fSChristoph Hellwig 		area = kmalloc_node(size, gfp | GFP_USER | __GFP_NORETRY,
302f01a7dbeSMartynas Pumputis 				    numa_node);
303d407bd25SDaniel Borkmann 		if (area != NULL)
304d407bd25SDaniel Borkmann 			return area;
305d407bd25SDaniel Borkmann 	}
306041de93fSChristoph Hellwig 
307041de93fSChristoph Hellwig 	return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END,
308041de93fSChristoph Hellwig 			gfp | GFP_KERNEL | __GFP_RETRY_MAYFAIL, PAGE_KERNEL,
309041de93fSChristoph Hellwig 			flags, numa_node, __builtin_return_address(0));
310d407bd25SDaniel Borkmann }
311d407bd25SDaniel Borkmann 
312196e8ca7SDaniel Borkmann void *bpf_map_area_alloc(u64 size, int numa_node)
313fc970227SAndrii Nakryiko {
314fc970227SAndrii Nakryiko 	return __bpf_map_area_alloc(size, numa_node, false);
315fc970227SAndrii Nakryiko }
316fc970227SAndrii Nakryiko 
317196e8ca7SDaniel Borkmann void *bpf_map_area_mmapable_alloc(u64 size, int numa_node)
318fc970227SAndrii Nakryiko {
319fc970227SAndrii Nakryiko 	return __bpf_map_area_alloc(size, numa_node, true);
320fc970227SAndrii Nakryiko }
321fc970227SAndrii Nakryiko 
322d407bd25SDaniel Borkmann void bpf_map_area_free(void *area)
323d407bd25SDaniel Borkmann {
324d407bd25SDaniel Borkmann 	kvfree(area);
325d407bd25SDaniel Borkmann }
326d407bd25SDaniel Borkmann 
327be70bcd5SDaniel Borkmann static u32 bpf_map_flags_retain_permanent(u32 flags)
328be70bcd5SDaniel Borkmann {
329be70bcd5SDaniel Borkmann 	/* Some map creation flags are not tied to the map object but
330be70bcd5SDaniel Borkmann 	 * rather to the map fd instead, so they have no meaning upon
331be70bcd5SDaniel Borkmann 	 * map object inspection since multiple file descriptors with
332be70bcd5SDaniel Borkmann 	 * different (access) properties can exist here. Thus, given
333be70bcd5SDaniel Borkmann 	 * this has zero meaning for the map itself, lets clear these
334be70bcd5SDaniel Borkmann 	 * from here.
335be70bcd5SDaniel Borkmann 	 */
336be70bcd5SDaniel Borkmann 	return flags & ~(BPF_F_RDONLY | BPF_F_WRONLY);
337be70bcd5SDaniel Borkmann }
338be70bcd5SDaniel Borkmann 
339bd475643SJakub Kicinski void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr)
340bd475643SJakub Kicinski {
341bd475643SJakub Kicinski 	map->map_type = attr->map_type;
342bd475643SJakub Kicinski 	map->key_size = attr->key_size;
343bd475643SJakub Kicinski 	map->value_size = attr->value_size;
344bd475643SJakub Kicinski 	map->max_entries = attr->max_entries;
345be70bcd5SDaniel Borkmann 	map->map_flags = bpf_map_flags_retain_permanent(attr->map_flags);
346bd475643SJakub Kicinski 	map->numa_node = bpf_map_attr_numa_node(attr);
3479330986cSJoanne Koong 	map->map_extra = attr->map_extra;
348bd475643SJakub Kicinski }
349bd475643SJakub Kicinski 
350f3f1c054SMartin KaFai Lau static int bpf_map_alloc_id(struct bpf_map *map)
351f3f1c054SMartin KaFai Lau {
352f3f1c054SMartin KaFai Lau 	int id;
353f3f1c054SMartin KaFai Lau 
354b76354cdSShaohua Li 	idr_preload(GFP_KERNEL);
355f3f1c054SMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
356f3f1c054SMartin KaFai Lau 	id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC);
357f3f1c054SMartin KaFai Lau 	if (id > 0)
358f3f1c054SMartin KaFai Lau 		map->id = id;
359f3f1c054SMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
360b76354cdSShaohua Li 	idr_preload_end();
361f3f1c054SMartin KaFai Lau 
362f3f1c054SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
363f3f1c054SMartin KaFai Lau 		return -ENOSPC;
364f3f1c054SMartin KaFai Lau 
365f3f1c054SMartin KaFai Lau 	return id > 0 ? 0 : id;
366f3f1c054SMartin KaFai Lau }
367f3f1c054SMartin KaFai Lau 
368158e5e9eSTobias Klauser void bpf_map_free_id(struct bpf_map *map)
369f3f1c054SMartin KaFai Lau {
370930651a7SEric Dumazet 	unsigned long flags;
371930651a7SEric Dumazet 
372a3884572SJakub Kicinski 	/* Offloaded maps are removed from the IDR store when their device
373a3884572SJakub Kicinski 	 * disappears - even if someone holds an fd to them they are unusable,
374a3884572SJakub Kicinski 	 * the memory is gone, all ops will fail; they are simply waiting for
375a3884572SJakub Kicinski 	 * refcnt to drop to be freed.
376a3884572SJakub Kicinski 	 */
377a3884572SJakub Kicinski 	if (!map->id)
378a3884572SJakub Kicinski 		return;
379a3884572SJakub Kicinski 
380930651a7SEric Dumazet 	spin_lock_irqsave(&map_idr_lock, flags);
381bd5f5f4eSMartin KaFai Lau 
382f3f1c054SMartin KaFai Lau 	idr_remove(&map_idr, map->id);
383a3884572SJakub Kicinski 	map->id = 0;
384bd5f5f4eSMartin KaFai Lau 
385930651a7SEric Dumazet 	spin_unlock_irqrestore(&map_idr_lock, flags);
386f3f1c054SMartin KaFai Lau }
387f3f1c054SMartin KaFai Lau 
38848edc1f7SRoman Gushchin #ifdef CONFIG_MEMCG_KMEM
38948edc1f7SRoman Gushchin static void bpf_map_save_memcg(struct bpf_map *map)
39048edc1f7SRoman Gushchin {
3914201d9abSRoman Gushchin 	/* Currently if a map is created by a process belonging to the root
3924201d9abSRoman Gushchin 	 * memory cgroup, get_obj_cgroup_from_current() will return NULL.
3934201d9abSRoman Gushchin 	 * So we have to check map->objcg for being NULL each time it's
3944201d9abSRoman Gushchin 	 * being used.
3954201d9abSRoman Gushchin 	 */
396ee53cbfbSYafang Shao 	if (memcg_bpf_enabled())
3974201d9abSRoman Gushchin 		map->objcg = get_obj_cgroup_from_current();
39848edc1f7SRoman Gushchin }
39948edc1f7SRoman Gushchin 
40048edc1f7SRoman Gushchin static void bpf_map_release_memcg(struct bpf_map *map)
40148edc1f7SRoman Gushchin {
4024201d9abSRoman Gushchin 	if (map->objcg)
4034201d9abSRoman Gushchin 		obj_cgroup_put(map->objcg);
4044201d9abSRoman Gushchin }
4054201d9abSRoman Gushchin 
4064201d9abSRoman Gushchin static struct mem_cgroup *bpf_map_get_memcg(const struct bpf_map *map)
4074201d9abSRoman Gushchin {
4084201d9abSRoman Gushchin 	if (map->objcg)
4094201d9abSRoman Gushchin 		return get_mem_cgroup_from_objcg(map->objcg);
4104201d9abSRoman Gushchin 
4114201d9abSRoman Gushchin 	return root_mem_cgroup;
41248edc1f7SRoman Gushchin }
41348edc1f7SRoman Gushchin 
41448edc1f7SRoman Gushchin void *bpf_map_kmalloc_node(const struct bpf_map *map, size_t size, gfp_t flags,
41548edc1f7SRoman Gushchin 			   int node)
41648edc1f7SRoman Gushchin {
4174201d9abSRoman Gushchin 	struct mem_cgroup *memcg, *old_memcg;
41848edc1f7SRoman Gushchin 	void *ptr;
41948edc1f7SRoman Gushchin 
4204201d9abSRoman Gushchin 	memcg = bpf_map_get_memcg(map);
4214201d9abSRoman Gushchin 	old_memcg = set_active_memcg(memcg);
42248edc1f7SRoman Gushchin 	ptr = kmalloc_node(size, flags | __GFP_ACCOUNT, node);
42348edc1f7SRoman Gushchin 	set_active_memcg(old_memcg);
4244201d9abSRoman Gushchin 	mem_cgroup_put(memcg);
42548edc1f7SRoman Gushchin 
42648edc1f7SRoman Gushchin 	return ptr;
42748edc1f7SRoman Gushchin }
42848edc1f7SRoman Gushchin 
42948edc1f7SRoman Gushchin void *bpf_map_kzalloc(const struct bpf_map *map, size_t size, gfp_t flags)
43048edc1f7SRoman Gushchin {
4314201d9abSRoman Gushchin 	struct mem_cgroup *memcg, *old_memcg;
43248edc1f7SRoman Gushchin 	void *ptr;
43348edc1f7SRoman Gushchin 
4344201d9abSRoman Gushchin 	memcg = bpf_map_get_memcg(map);
4354201d9abSRoman Gushchin 	old_memcg = set_active_memcg(memcg);
43648edc1f7SRoman Gushchin 	ptr = kzalloc(size, flags | __GFP_ACCOUNT);
43748edc1f7SRoman Gushchin 	set_active_memcg(old_memcg);
4384201d9abSRoman Gushchin 	mem_cgroup_put(memcg);
43948edc1f7SRoman Gushchin 
44048edc1f7SRoman Gushchin 	return ptr;
44148edc1f7SRoman Gushchin }
44248edc1f7SRoman Gushchin 
443ddef81b5SYafang Shao void *bpf_map_kvcalloc(struct bpf_map *map, size_t n, size_t size,
444ddef81b5SYafang Shao 		       gfp_t flags)
445ddef81b5SYafang Shao {
446ddef81b5SYafang Shao 	struct mem_cgroup *memcg, *old_memcg;
447ddef81b5SYafang Shao 	void *ptr;
448ddef81b5SYafang Shao 
449ddef81b5SYafang Shao 	memcg = bpf_map_get_memcg(map);
450ddef81b5SYafang Shao 	old_memcg = set_active_memcg(memcg);
451ddef81b5SYafang Shao 	ptr = kvcalloc(n, size, flags | __GFP_ACCOUNT);
452ddef81b5SYafang Shao 	set_active_memcg(old_memcg);
453ddef81b5SYafang Shao 	mem_cgroup_put(memcg);
454ddef81b5SYafang Shao 
455ddef81b5SYafang Shao 	return ptr;
456ddef81b5SYafang Shao }
457ddef81b5SYafang Shao 
45848edc1f7SRoman Gushchin void __percpu *bpf_map_alloc_percpu(const struct bpf_map *map, size_t size,
45948edc1f7SRoman Gushchin 				    size_t align, gfp_t flags)
46048edc1f7SRoman Gushchin {
4614201d9abSRoman Gushchin 	struct mem_cgroup *memcg, *old_memcg;
46248edc1f7SRoman Gushchin 	void __percpu *ptr;
46348edc1f7SRoman Gushchin 
4644201d9abSRoman Gushchin 	memcg = bpf_map_get_memcg(map);
4654201d9abSRoman Gushchin 	old_memcg = set_active_memcg(memcg);
46648edc1f7SRoman Gushchin 	ptr = __alloc_percpu_gfp(size, align, 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 #else
47448edc1f7SRoman Gushchin static void bpf_map_save_memcg(struct bpf_map *map)
47548edc1f7SRoman Gushchin {
47648edc1f7SRoman Gushchin }
47748edc1f7SRoman Gushchin 
47848edc1f7SRoman Gushchin static void bpf_map_release_memcg(struct bpf_map *map)
47948edc1f7SRoman Gushchin {
48048edc1f7SRoman Gushchin }
48148edc1f7SRoman Gushchin #endif
48248edc1f7SRoman Gushchin 
48331746031SAlexei Starovoitov int bpf_map_alloc_pages(const struct bpf_map *map, gfp_t gfp, int nid,
48431746031SAlexei Starovoitov 			unsigned long nr_pages, struct page **pages)
48531746031SAlexei Starovoitov {
48631746031SAlexei Starovoitov 	unsigned long i, j;
48731746031SAlexei Starovoitov 	struct page *pg;
48831746031SAlexei Starovoitov 	int ret = 0;
48931746031SAlexei Starovoitov #ifdef CONFIG_MEMCG_KMEM
49031746031SAlexei Starovoitov 	struct mem_cgroup *memcg, *old_memcg;
49131746031SAlexei Starovoitov 
49231746031SAlexei Starovoitov 	memcg = bpf_map_get_memcg(map);
49331746031SAlexei Starovoitov 	old_memcg = set_active_memcg(memcg);
49431746031SAlexei Starovoitov #endif
49531746031SAlexei Starovoitov 	for (i = 0; i < nr_pages; i++) {
49631746031SAlexei Starovoitov 		pg = alloc_pages_node(nid, gfp | __GFP_ACCOUNT, 0);
49731746031SAlexei Starovoitov 
49831746031SAlexei Starovoitov 		if (pg) {
49931746031SAlexei Starovoitov 			pages[i] = pg;
50031746031SAlexei Starovoitov 			continue;
50131746031SAlexei Starovoitov 		}
50231746031SAlexei Starovoitov 		for (j = 0; j < i; j++)
50331746031SAlexei Starovoitov 			__free_page(pages[j]);
50431746031SAlexei Starovoitov 		ret = -ENOMEM;
50531746031SAlexei Starovoitov 		break;
50631746031SAlexei Starovoitov 	}
50731746031SAlexei Starovoitov 
50831746031SAlexei Starovoitov #ifdef CONFIG_MEMCG_KMEM
50931746031SAlexei Starovoitov 	set_active_memcg(old_memcg);
51031746031SAlexei Starovoitov 	mem_cgroup_put(memcg);
51131746031SAlexei Starovoitov #endif
51231746031SAlexei Starovoitov 	return ret;
51331746031SAlexei Starovoitov }
51431746031SAlexei Starovoitov 
51531746031SAlexei Starovoitov 
516aa3496acSKumar Kartikeya Dwivedi static int btf_field_cmp(const void *a, const void *b)
51761df10c7SKumar Kartikeya Dwivedi {
518aa3496acSKumar Kartikeya Dwivedi 	const struct btf_field *f1 = a, *f2 = b;
51961df10c7SKumar Kartikeya Dwivedi 
520aa3496acSKumar Kartikeya Dwivedi 	if (f1->offset < f2->offset)
52161df10c7SKumar Kartikeya Dwivedi 		return -1;
522aa3496acSKumar Kartikeya Dwivedi 	else if (f1->offset > f2->offset)
52361df10c7SKumar Kartikeya Dwivedi 		return 1;
52461df10c7SKumar Kartikeya Dwivedi 	return 0;
52561df10c7SKumar Kartikeya Dwivedi }
52661df10c7SKumar Kartikeya Dwivedi 
527aa3496acSKumar Kartikeya Dwivedi struct btf_field *btf_record_find(const struct btf_record *rec, u32 offset,
52874843b57SDave Marchevsky 				  u32 field_mask)
52961df10c7SKumar Kartikeya Dwivedi {
530aa3496acSKumar Kartikeya Dwivedi 	struct btf_field *field;
53161df10c7SKumar Kartikeya Dwivedi 
53274843b57SDave Marchevsky 	if (IS_ERR_OR_NULL(rec) || !(rec->field_mask & field_mask))
53361df10c7SKumar Kartikeya Dwivedi 		return NULL;
534aa3496acSKumar Kartikeya Dwivedi 	field = bsearch(&offset, rec->fields, rec->cnt, sizeof(rec->fields[0]), btf_field_cmp);
53574843b57SDave Marchevsky 	if (!field || !(field->type & field_mask))
536aa3496acSKumar Kartikeya Dwivedi 		return NULL;
537aa3496acSKumar Kartikeya Dwivedi 	return field;
53861df10c7SKumar Kartikeya Dwivedi }
53961df10c7SKumar Kartikeya Dwivedi 
540aa3496acSKumar Kartikeya Dwivedi void btf_record_free(struct btf_record *rec)
54161df10c7SKumar Kartikeya Dwivedi {
54261df10c7SKumar Kartikeya Dwivedi 	int i;
54361df10c7SKumar Kartikeya Dwivedi 
544aa3496acSKumar Kartikeya Dwivedi 	if (IS_ERR_OR_NULL(rec))
54561df10c7SKumar Kartikeya Dwivedi 		return;
546aa3496acSKumar Kartikeya Dwivedi 	for (i = 0; i < rec->cnt; i++) {
547aa3496acSKumar Kartikeya Dwivedi 		switch (rec->fields[i].type) {
548aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_UNREF:
549aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_REF:
55055db92f4SYonghong Song 		case BPF_KPTR_PERCPU:
551aa3496acSKumar Kartikeya Dwivedi 			if (rec->fields[i].kptr.module)
552aa3496acSKumar Kartikeya Dwivedi 				module_put(rec->fields[i].kptr.module);
553aa3496acSKumar Kartikeya Dwivedi 			btf_put(rec->fields[i].kptr.btf);
554aa3496acSKumar Kartikeya Dwivedi 			break;
555f0c5941fSKumar Kartikeya Dwivedi 		case BPF_LIST_HEAD:
5568ffa5cc1SKumar Kartikeya Dwivedi 		case BPF_LIST_NODE:
5579c395c1bSDave Marchevsky 		case BPF_RB_ROOT:
5589c395c1bSDave Marchevsky 		case BPF_RB_NODE:
5599c395c1bSDave Marchevsky 		case BPF_SPIN_LOCK:
5609c395c1bSDave Marchevsky 		case BPF_TIMER:
561d54730b5SDave Marchevsky 		case BPF_REFCOUNT:
562d56b63cfSBenjamin Tissoires 		case BPF_WORKQUEUE:
5639c395c1bSDave Marchevsky 			/* Nothing to release */
564f0c5941fSKumar Kartikeya Dwivedi 			break;
565aa3496acSKumar Kartikeya Dwivedi 		default:
566aa3496acSKumar Kartikeya Dwivedi 			WARN_ON_ONCE(1);
56714a324f6SKumar Kartikeya Dwivedi 			continue;
56814a324f6SKumar Kartikeya Dwivedi 		}
569aa3496acSKumar Kartikeya Dwivedi 	}
570aa3496acSKumar Kartikeya Dwivedi 	kfree(rec);
571aa3496acSKumar Kartikeya Dwivedi }
572aa3496acSKumar Kartikeya Dwivedi 
573aa3496acSKumar Kartikeya Dwivedi void bpf_map_free_record(struct bpf_map *map)
574aa3496acSKumar Kartikeya Dwivedi {
575aa3496acSKumar Kartikeya Dwivedi 	btf_record_free(map->record);
576aa3496acSKumar Kartikeya Dwivedi 	map->record = NULL;
577aa3496acSKumar Kartikeya Dwivedi }
578aa3496acSKumar Kartikeya Dwivedi 
579aa3496acSKumar Kartikeya Dwivedi struct btf_record *btf_record_dup(const struct btf_record *rec)
580aa3496acSKumar Kartikeya Dwivedi {
581aa3496acSKumar Kartikeya Dwivedi 	const struct btf_field *fields;
582aa3496acSKumar Kartikeya Dwivedi 	struct btf_record *new_rec;
583aa3496acSKumar Kartikeya Dwivedi 	int ret, size, i;
584aa3496acSKumar Kartikeya Dwivedi 
585aa3496acSKumar Kartikeya Dwivedi 	if (IS_ERR_OR_NULL(rec))
586aa3496acSKumar Kartikeya Dwivedi 		return NULL;
587aa3496acSKumar Kartikeya Dwivedi 	size = offsetof(struct btf_record, fields[rec->cnt]);
588aa3496acSKumar Kartikeya Dwivedi 	new_rec = kmemdup(rec, size, GFP_KERNEL | __GFP_NOWARN);
589aa3496acSKumar Kartikeya Dwivedi 	if (!new_rec)
590aa3496acSKumar Kartikeya Dwivedi 		return ERR_PTR(-ENOMEM);
591aa3496acSKumar Kartikeya Dwivedi 	/* Do a deep copy of the btf_record */
592aa3496acSKumar Kartikeya Dwivedi 	fields = rec->fields;
593aa3496acSKumar Kartikeya Dwivedi 	new_rec->cnt = 0;
594aa3496acSKumar Kartikeya Dwivedi 	for (i = 0; i < rec->cnt; i++) {
595aa3496acSKumar Kartikeya Dwivedi 		switch (fields[i].type) {
596aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_UNREF:
597aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_REF:
59855db92f4SYonghong Song 		case BPF_KPTR_PERCPU:
599aa3496acSKumar Kartikeya Dwivedi 			btf_get(fields[i].kptr.btf);
600aa3496acSKumar Kartikeya Dwivedi 			if (fields[i].kptr.module && !try_module_get(fields[i].kptr.module)) {
601aa3496acSKumar Kartikeya Dwivedi 				ret = -ENXIO;
602aa3496acSKumar Kartikeya Dwivedi 				goto free;
603aa3496acSKumar Kartikeya Dwivedi 			}
604aa3496acSKumar Kartikeya Dwivedi 			break;
605f0c5941fSKumar Kartikeya Dwivedi 		case BPF_LIST_HEAD:
6068ffa5cc1SKumar Kartikeya Dwivedi 		case BPF_LIST_NODE:
6079c395c1bSDave Marchevsky 		case BPF_RB_ROOT:
6089c395c1bSDave Marchevsky 		case BPF_RB_NODE:
6099c395c1bSDave Marchevsky 		case BPF_SPIN_LOCK:
6109c395c1bSDave Marchevsky 		case BPF_TIMER:
611d54730b5SDave Marchevsky 		case BPF_REFCOUNT:
612d56b63cfSBenjamin Tissoires 		case BPF_WORKQUEUE:
6139c395c1bSDave Marchevsky 			/* Nothing to acquire */
614f0c5941fSKumar Kartikeya Dwivedi 			break;
615aa3496acSKumar Kartikeya Dwivedi 		default:
616aa3496acSKumar Kartikeya Dwivedi 			ret = -EFAULT;
617aa3496acSKumar Kartikeya Dwivedi 			WARN_ON_ONCE(1);
618aa3496acSKumar Kartikeya Dwivedi 			goto free;
619aa3496acSKumar Kartikeya Dwivedi 		}
620aa3496acSKumar Kartikeya Dwivedi 		new_rec->cnt++;
621aa3496acSKumar Kartikeya Dwivedi 	}
622aa3496acSKumar Kartikeya Dwivedi 	return new_rec;
623aa3496acSKumar Kartikeya Dwivedi free:
624aa3496acSKumar Kartikeya Dwivedi 	btf_record_free(new_rec);
625aa3496acSKumar Kartikeya Dwivedi 	return ERR_PTR(ret);
626aa3496acSKumar Kartikeya Dwivedi }
627aa3496acSKumar Kartikeya Dwivedi 
628aa3496acSKumar Kartikeya Dwivedi bool btf_record_equal(const struct btf_record *rec_a, const struct btf_record *rec_b)
629aa3496acSKumar Kartikeya Dwivedi {
630aa3496acSKumar Kartikeya Dwivedi 	bool a_has_fields = !IS_ERR_OR_NULL(rec_a), b_has_fields = !IS_ERR_OR_NULL(rec_b);
631aa3496acSKumar Kartikeya Dwivedi 	int size;
632aa3496acSKumar Kartikeya Dwivedi 
633aa3496acSKumar Kartikeya Dwivedi 	if (!a_has_fields && !b_has_fields)
634aa3496acSKumar Kartikeya Dwivedi 		return true;
635aa3496acSKumar Kartikeya Dwivedi 	if (a_has_fields != b_has_fields)
636aa3496acSKumar Kartikeya Dwivedi 		return false;
637aa3496acSKumar Kartikeya Dwivedi 	if (rec_a->cnt != rec_b->cnt)
638aa3496acSKumar Kartikeya Dwivedi 		return false;
639aa3496acSKumar Kartikeya Dwivedi 	size = offsetof(struct btf_record, fields[rec_a->cnt]);
640c22dfdd2SKumar Kartikeya Dwivedi 	/* btf_parse_fields uses kzalloc to allocate a btf_record, so unused
641c22dfdd2SKumar Kartikeya Dwivedi 	 * members are zeroed out. So memcmp is safe to do without worrying
642c22dfdd2SKumar Kartikeya Dwivedi 	 * about padding/unused fields.
643c22dfdd2SKumar Kartikeya Dwivedi 	 *
644c22dfdd2SKumar Kartikeya Dwivedi 	 * While spin_lock, timer, and kptr have no relation to map BTF,
645c22dfdd2SKumar Kartikeya Dwivedi 	 * list_head metadata is specific to map BTF, the btf and value_rec
646c22dfdd2SKumar Kartikeya Dwivedi 	 * members in particular. btf is the map BTF, while value_rec points to
647c22dfdd2SKumar Kartikeya Dwivedi 	 * btf_record in that map BTF.
648c22dfdd2SKumar Kartikeya Dwivedi 	 *
649c22dfdd2SKumar Kartikeya Dwivedi 	 * So while by default, we don't rely on the map BTF (which the records
650c22dfdd2SKumar Kartikeya Dwivedi 	 * were parsed from) matching for both records, which is not backwards
651c22dfdd2SKumar Kartikeya Dwivedi 	 * compatible, in case list_head is part of it, we implicitly rely on
652c22dfdd2SKumar Kartikeya Dwivedi 	 * that by way of depending on memcmp succeeding for it.
653c22dfdd2SKumar Kartikeya Dwivedi 	 */
654aa3496acSKumar Kartikeya Dwivedi 	return !memcmp(rec_a, rec_b, size);
655aa3496acSKumar Kartikeya Dwivedi }
656aa3496acSKumar Kartikeya Dwivedi 
657db559117SKumar Kartikeya Dwivedi void bpf_obj_free_timer(const struct btf_record *rec, void *obj)
658db559117SKumar Kartikeya Dwivedi {
659db559117SKumar Kartikeya Dwivedi 	if (WARN_ON_ONCE(!btf_record_has_field(rec, BPF_TIMER)))
660db559117SKumar Kartikeya Dwivedi 		return;
661db559117SKumar Kartikeya Dwivedi 	bpf_timer_cancel_and_free(obj + rec->timer_off);
662db559117SKumar Kartikeya Dwivedi }
663db559117SKumar Kartikeya Dwivedi 
664246331e3SBenjamin Tissoires void bpf_obj_free_workqueue(const struct btf_record *rec, void *obj)
665246331e3SBenjamin Tissoires {
666246331e3SBenjamin Tissoires 	if (WARN_ON_ONCE(!btf_record_has_field(rec, BPF_WORKQUEUE)))
667246331e3SBenjamin Tissoires 		return;
668246331e3SBenjamin Tissoires 	bpf_wq_cancel_and_free(obj + rec->wq_off);
669246331e3SBenjamin Tissoires }
670246331e3SBenjamin Tissoires 
671aa3496acSKumar Kartikeya Dwivedi void bpf_obj_free_fields(const struct btf_record *rec, void *obj)
672aa3496acSKumar Kartikeya Dwivedi {
673aa3496acSKumar Kartikeya Dwivedi 	const struct btf_field *fields;
674aa3496acSKumar Kartikeya Dwivedi 	int i;
675aa3496acSKumar Kartikeya Dwivedi 
676aa3496acSKumar Kartikeya Dwivedi 	if (IS_ERR_OR_NULL(rec))
677aa3496acSKumar Kartikeya Dwivedi 		return;
678aa3496acSKumar Kartikeya Dwivedi 	fields = rec->fields;
679aa3496acSKumar Kartikeya Dwivedi 	for (i = 0; i < rec->cnt; i++) {
680c8e18754SDave Marchevsky 		struct btf_struct_meta *pointee_struct_meta;
681aa3496acSKumar Kartikeya Dwivedi 		const struct btf_field *field = &fields[i];
682aa3496acSKumar Kartikeya Dwivedi 		void *field_ptr = obj + field->offset;
683c8e18754SDave Marchevsky 		void *xchgd_field;
684aa3496acSKumar Kartikeya Dwivedi 
685aa3496acSKumar Kartikeya Dwivedi 		switch (fields[i].type) {
686db559117SKumar Kartikeya Dwivedi 		case BPF_SPIN_LOCK:
687db559117SKumar Kartikeya Dwivedi 			break;
688db559117SKumar Kartikeya Dwivedi 		case BPF_TIMER:
689db559117SKumar Kartikeya Dwivedi 			bpf_timer_cancel_and_free(field_ptr);
690db559117SKumar Kartikeya Dwivedi 			break;
691d56b63cfSBenjamin Tissoires 		case BPF_WORKQUEUE:
692246331e3SBenjamin Tissoires 			bpf_wq_cancel_and_free(field_ptr);
693d56b63cfSBenjamin Tissoires 			break;
694aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_UNREF:
695aa3496acSKumar Kartikeya Dwivedi 			WRITE_ONCE(*(u64 *)field_ptr, 0);
696aa3496acSKumar Kartikeya Dwivedi 			break;
697aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_REF:
69855db92f4SYonghong Song 		case BPF_KPTR_PERCPU:
699c8e18754SDave Marchevsky 			xchgd_field = (void *)xchg((unsigned long *)field_ptr, 0);
7001431d0b5SDavid Vernet 			if (!xchgd_field)
7011431d0b5SDavid Vernet 				break;
7021431d0b5SDavid Vernet 
703c8e18754SDave Marchevsky 			if (!btf_is_kernel(field->kptr.btf)) {
704c8e18754SDave Marchevsky 				pointee_struct_meta = btf_find_struct_meta(field->kptr.btf,
705c8e18754SDave Marchevsky 									   field->kptr.btf_id);
7069e36a204SDave Marchevsky 				migrate_disable();
7079e36a204SDave Marchevsky 				__bpf_obj_drop_impl(xchgd_field, pointee_struct_meta ?
708e383a459SHou Tao 								 pointee_struct_meta->record : NULL,
709e383a459SHou Tao 								 fields[i].type == BPF_KPTR_PERCPU);
7109e36a204SDave Marchevsky 				migrate_enable();
711c8e18754SDave Marchevsky 			} else {
712c8e18754SDave Marchevsky 				field->kptr.dtor(xchgd_field);
713c8e18754SDave Marchevsky 			}
714aa3496acSKumar Kartikeya Dwivedi 			break;
715f0c5941fSKumar Kartikeya Dwivedi 		case BPF_LIST_HEAD:
716f0c5941fSKumar Kartikeya Dwivedi 			if (WARN_ON_ONCE(rec->spin_lock_off < 0))
717f0c5941fSKumar Kartikeya Dwivedi 				continue;
718f0c5941fSKumar Kartikeya Dwivedi 			bpf_list_head_free(field, field_ptr, obj + rec->spin_lock_off);
719f0c5941fSKumar Kartikeya Dwivedi 			break;
7209c395c1bSDave Marchevsky 		case BPF_RB_ROOT:
7219c395c1bSDave Marchevsky 			if (WARN_ON_ONCE(rec->spin_lock_off < 0))
7229c395c1bSDave Marchevsky 				continue;
7239c395c1bSDave Marchevsky 			bpf_rb_root_free(field, field_ptr, obj + rec->spin_lock_off);
7249c395c1bSDave Marchevsky 			break;
7258ffa5cc1SKumar Kartikeya Dwivedi 		case BPF_LIST_NODE:
7269c395c1bSDave Marchevsky 		case BPF_RB_NODE:
727d54730b5SDave Marchevsky 		case BPF_REFCOUNT:
7288ffa5cc1SKumar Kartikeya Dwivedi 			break;
729aa3496acSKumar Kartikeya Dwivedi 		default:
730aa3496acSKumar Kartikeya Dwivedi 			WARN_ON_ONCE(1);
731aa3496acSKumar Kartikeya Dwivedi 			continue;
732aa3496acSKumar Kartikeya Dwivedi 		}
73314a324f6SKumar Kartikeya Dwivedi 	}
73414a324f6SKumar Kartikeya Dwivedi }
73514a324f6SKumar Kartikeya Dwivedi 
73699c55f7dSAlexei Starovoitov /* called from workqueue */
73799c55f7dSAlexei Starovoitov static void bpf_map_free_deferred(struct work_struct *work)
73899c55f7dSAlexei Starovoitov {
73999c55f7dSAlexei Starovoitov 	struct bpf_map *map = container_of(work, struct bpf_map, work);
740d7f5ef65SKumar Kartikeya Dwivedi 	struct btf_record *rec = map->record;
74159e5791fSYonghong Song 	struct btf *btf = map->btf;
74299c55f7dSAlexei Starovoitov 
743afdb09c7SChenbo Feng 	security_bpf_map_free(map);
74448edc1f7SRoman Gushchin 	bpf_map_release_memcg(map);
745d7f5ef65SKumar Kartikeya Dwivedi 	/* implementation dependent freeing */
74699c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
747cd2a8079SDave Marchevsky 	/* Delay freeing of btf_record for maps, as map_free
748d7f5ef65SKumar Kartikeya Dwivedi 	 * callback usually needs access to them. It is better to do it here
749d7f5ef65SKumar Kartikeya Dwivedi 	 * than require each callback to do the free itself manually.
750d7f5ef65SKumar Kartikeya Dwivedi 	 *
751d7f5ef65SKumar Kartikeya Dwivedi 	 * Note that the btf_record stashed in map->inner_map_meta->record was
752d7f5ef65SKumar Kartikeya Dwivedi 	 * already freed using the map_free callback for map in map case which
753d7f5ef65SKumar Kartikeya Dwivedi 	 * eventually calls bpf_map_free_meta, since inner_map_meta is only a
754d7f5ef65SKumar Kartikeya Dwivedi 	 * template bpf_map struct used during verification.
755d7f5ef65SKumar Kartikeya Dwivedi 	 */
756d7f5ef65SKumar Kartikeya Dwivedi 	btf_record_free(rec);
75759e5791fSYonghong Song 	/* Delay freeing of btf for maps, as map_free callback may need
75859e5791fSYonghong Song 	 * struct_meta info which will be freed with btf_put().
75959e5791fSYonghong Song 	 */
76059e5791fSYonghong Song 	btf_put(btf);
76199c55f7dSAlexei Starovoitov }
76299c55f7dSAlexei Starovoitov 
763c9da161cSDaniel Borkmann static void bpf_map_put_uref(struct bpf_map *map)
764c9da161cSDaniel Borkmann {
7651e0bd5a0SAndrii Nakryiko 	if (atomic64_dec_and_test(&map->usercnt)) {
766ba6b8de4SJohn Fastabend 		if (map->ops->map_release_uref)
767ba6b8de4SJohn Fastabend 			map->ops->map_release_uref(map);
768c9da161cSDaniel Borkmann 	}
769c9da161cSDaniel Borkmann }
770c9da161cSDaniel Borkmann 
77187667336SHou Tao static void bpf_map_free_in_work(struct bpf_map *map)
77287667336SHou Tao {
77387667336SHou Tao 	INIT_WORK(&map->work, bpf_map_free_deferred);
77487667336SHou Tao 	/* Avoid spawning kworkers, since they all might contend
77587667336SHou Tao 	 * for the same mutex like slab_mutex.
77687667336SHou Tao 	 */
77787667336SHou Tao 	queue_work(system_unbound_wq, &map->work);
77887667336SHou Tao }
77987667336SHou Tao 
78087667336SHou Tao static void bpf_map_free_rcu_gp(struct rcu_head *rcu)
78187667336SHou Tao {
78287667336SHou Tao 	bpf_map_free_in_work(container_of(rcu, struct bpf_map, rcu));
78387667336SHou Tao }
78487667336SHou Tao 
78587667336SHou Tao static void bpf_map_free_mult_rcu_gp(struct rcu_head *rcu)
78687667336SHou Tao {
78787667336SHou Tao 	if (rcu_trace_implies_rcu_gp())
78887667336SHou Tao 		bpf_map_free_rcu_gp(rcu);
78987667336SHou Tao 	else
79087667336SHou Tao 		call_rcu(rcu, bpf_map_free_rcu_gp);
79187667336SHou Tao }
79287667336SHou Tao 
79399c55f7dSAlexei Starovoitov /* decrement map refcnt and schedule it for freeing via workqueue
794158e5e9eSTobias Klauser  * (underlying map implementation ops->map_free() might sleep)
79599c55f7dSAlexei Starovoitov  */
796158e5e9eSTobias Klauser void bpf_map_put(struct bpf_map *map)
79799c55f7dSAlexei Starovoitov {
7981e0bd5a0SAndrii Nakryiko 	if (atomic64_dec_and_test(&map->refcnt)) {
79934ad5580SMartin KaFai Lau 		/* bpf_map_free_id() must be called first */
800158e5e9eSTobias Klauser 		bpf_map_free_id(map);
80187667336SHou Tao 
802af66bfd3SHou Tao 		WARN_ON_ONCE(atomic64_read(&map->sleepable_refcnt));
80387667336SHou Tao 		if (READ_ONCE(map->free_after_mult_rcu_gp))
80487667336SHou Tao 			call_rcu_tasks_trace(&map->rcu, bpf_map_free_mult_rcu_gp);
805af66bfd3SHou Tao 		else if (READ_ONCE(map->free_after_rcu_gp))
806af66bfd3SHou Tao 			call_rcu(&map->rcu, bpf_map_free_rcu_gp);
80787667336SHou Tao 		else
80887667336SHou Tao 			bpf_map_free_in_work(map);
80999c55f7dSAlexei Starovoitov 	}
81099c55f7dSAlexei Starovoitov }
811630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_put);
812bd5f5f4eSMartin KaFai Lau 
813c9da161cSDaniel Borkmann void bpf_map_put_with_uref(struct bpf_map *map)
814c9da161cSDaniel Borkmann {
815c9da161cSDaniel Borkmann 	bpf_map_put_uref(map);
816c9da161cSDaniel Borkmann 	bpf_map_put(map);
817c9da161cSDaniel Borkmann }
818c9da161cSDaniel Borkmann 
81999c55f7dSAlexei Starovoitov static int bpf_map_release(struct inode *inode, struct file *filp)
82099c55f7dSAlexei Starovoitov {
82161d1b6a4SDaniel Borkmann 	struct bpf_map *map = filp->private_data;
82261d1b6a4SDaniel Borkmann 
82361d1b6a4SDaniel Borkmann 	if (map->ops->map_release)
82461d1b6a4SDaniel Borkmann 		map->ops->map_release(map, filp);
82561d1b6a4SDaniel Borkmann 
82661d1b6a4SDaniel Borkmann 	bpf_map_put_with_uref(map);
82799c55f7dSAlexei Starovoitov 	return 0;
82899c55f7dSAlexei Starovoitov }
82999c55f7dSAlexei Starovoitov 
83087df15deSDaniel Borkmann static fmode_t map_get_sys_perms(struct bpf_map *map, struct fd f)
83187df15deSDaniel Borkmann {
83287df15deSDaniel Borkmann 	fmode_t mode = f.file->f_mode;
83387df15deSDaniel Borkmann 
83487df15deSDaniel Borkmann 	/* Our file permissions may have been overridden by global
83587df15deSDaniel Borkmann 	 * map permissions facing syscall side.
83687df15deSDaniel Borkmann 	 */
83787df15deSDaniel Borkmann 	if (READ_ONCE(map->frozen))
83887df15deSDaniel Borkmann 		mode &= ~FMODE_CAN_WRITE;
83987df15deSDaniel Borkmann 	return mode;
84087df15deSDaniel Borkmann }
84187df15deSDaniel Borkmann 
842f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
84390a5527dSYafang Shao /* Show the memory usage of a bpf map */
84490a5527dSYafang Shao static u64 bpf_map_memory_usage(const struct bpf_map *map)
84580ee81e0SRoman Gushchin {
84690a5527dSYafang Shao 	return map->ops->map_mem_usage(map);
84780ee81e0SRoman Gushchin }
84880ee81e0SRoman Gushchin 
849f99bf205SDaniel Borkmann static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)
850f99bf205SDaniel Borkmann {
851f45d5b6cSToke Hoiland-Jorgensen 	struct bpf_map *map = filp->private_data;
8522beee5f5SDaniel Borkmann 	u32 type = 0, jited = 0;
85321116b70SDaniel Borkmann 
854f45d5b6cSToke Hoiland-Jorgensen 	if (map_type_contains_progs(map)) {
855f45d5b6cSToke Hoiland-Jorgensen 		spin_lock(&map->owner.lock);
856f45d5b6cSToke Hoiland-Jorgensen 		type  = map->owner.type;
857f45d5b6cSToke Hoiland-Jorgensen 		jited = map->owner.jited;
858f45d5b6cSToke Hoiland-Jorgensen 		spin_unlock(&map->owner.lock);
85921116b70SDaniel Borkmann 	}
860f99bf205SDaniel Borkmann 
861f99bf205SDaniel Borkmann 	seq_printf(m,
862f99bf205SDaniel Borkmann 		   "map_type:\t%u\n"
863f99bf205SDaniel Borkmann 		   "key_size:\t%u\n"
864f99bf205SDaniel Borkmann 		   "value_size:\t%u\n"
865322cea2fSDaniel Borkmann 		   "max_entries:\t%u\n"
86621116b70SDaniel Borkmann 		   "map_flags:\t%#x\n"
8679330986cSJoanne Koong 		   "map_extra:\t%#llx\n"
86890a5527dSYafang Shao 		   "memlock:\t%llu\n"
86987df15deSDaniel Borkmann 		   "map_id:\t%u\n"
87087df15deSDaniel Borkmann 		   "frozen:\t%u\n",
871f99bf205SDaniel Borkmann 		   map->map_type,
872f99bf205SDaniel Borkmann 		   map->key_size,
873f99bf205SDaniel Borkmann 		   map->value_size,
874322cea2fSDaniel Borkmann 		   map->max_entries,
87521116b70SDaniel Borkmann 		   map->map_flags,
8769330986cSJoanne Koong 		   (unsigned long long)map->map_extra,
87790a5527dSYafang Shao 		   bpf_map_memory_usage(map),
87887df15deSDaniel Borkmann 		   map->id,
87987df15deSDaniel Borkmann 		   READ_ONCE(map->frozen));
8802beee5f5SDaniel Borkmann 	if (type) {
8812beee5f5SDaniel Borkmann 		seq_printf(m, "owner_prog_type:\t%u\n", type);
8822beee5f5SDaniel Borkmann 		seq_printf(m, "owner_jited:\t%u\n", jited);
8839780c0abSDaniel Borkmann 	}
884f99bf205SDaniel Borkmann }
885f99bf205SDaniel Borkmann #endif
886f99bf205SDaniel Borkmann 
8876e71b04aSChenbo Feng static ssize_t bpf_dummy_read(struct file *filp, char __user *buf, size_t siz,
8886e71b04aSChenbo Feng 			      loff_t *ppos)
8896e71b04aSChenbo Feng {
8906e71b04aSChenbo Feng 	/* We need this handler such that alloc_file() enables
8916e71b04aSChenbo Feng 	 * f_mode with FMODE_CAN_READ.
8926e71b04aSChenbo Feng 	 */
8936e71b04aSChenbo Feng 	return -EINVAL;
8946e71b04aSChenbo Feng }
8956e71b04aSChenbo Feng 
8966e71b04aSChenbo Feng static ssize_t bpf_dummy_write(struct file *filp, const char __user *buf,
8976e71b04aSChenbo Feng 			       size_t siz, loff_t *ppos)
8986e71b04aSChenbo Feng {
8996e71b04aSChenbo Feng 	/* We need this handler such that alloc_file() enables
9006e71b04aSChenbo Feng 	 * f_mode with FMODE_CAN_WRITE.
9016e71b04aSChenbo Feng 	 */
9026e71b04aSChenbo Feng 	return -EINVAL;
9036e71b04aSChenbo Feng }
9046e71b04aSChenbo Feng 
905fc970227SAndrii Nakryiko /* called for any extra memory-mapped regions (except initial) */
906fc970227SAndrii Nakryiko static void bpf_map_mmap_open(struct vm_area_struct *vma)
907fc970227SAndrii Nakryiko {
908fc970227SAndrii Nakryiko 	struct bpf_map *map = vma->vm_file->private_data;
909fc970227SAndrii Nakryiko 
910353050beSDaniel Borkmann 	if (vma->vm_flags & VM_MAYWRITE)
911353050beSDaniel Borkmann 		bpf_map_write_active_inc(map);
912fc970227SAndrii Nakryiko }
913fc970227SAndrii Nakryiko 
914fc970227SAndrii Nakryiko /* called for all unmapped memory region (including initial) */
915fc970227SAndrii Nakryiko static void bpf_map_mmap_close(struct vm_area_struct *vma)
916fc970227SAndrii Nakryiko {
917fc970227SAndrii Nakryiko 	struct bpf_map *map = vma->vm_file->private_data;
918fc970227SAndrii Nakryiko 
919353050beSDaniel Borkmann 	if (vma->vm_flags & VM_MAYWRITE)
920353050beSDaniel Borkmann 		bpf_map_write_active_dec(map);
921fc970227SAndrii Nakryiko }
922fc970227SAndrii Nakryiko 
923fc970227SAndrii Nakryiko static const struct vm_operations_struct bpf_map_default_vmops = {
924fc970227SAndrii Nakryiko 	.open		= bpf_map_mmap_open,
925fc970227SAndrii Nakryiko 	.close		= bpf_map_mmap_close,
926fc970227SAndrii Nakryiko };
927fc970227SAndrii Nakryiko 
928fc970227SAndrii Nakryiko static int bpf_map_mmap(struct file *filp, struct vm_area_struct *vma)
929fc970227SAndrii Nakryiko {
930fc970227SAndrii Nakryiko 	struct bpf_map *map = filp->private_data;
931fc970227SAndrii Nakryiko 	int err;
932fc970227SAndrii Nakryiko 
933db559117SKumar Kartikeya Dwivedi 	if (!map->ops->map_mmap || !IS_ERR_OR_NULL(map->record))
934fc970227SAndrii Nakryiko 		return -ENOTSUPP;
935fc970227SAndrii Nakryiko 
936fc970227SAndrii Nakryiko 	if (!(vma->vm_flags & VM_SHARED))
937fc970227SAndrii Nakryiko 		return -EINVAL;
938fc970227SAndrii Nakryiko 
939fc970227SAndrii Nakryiko 	mutex_lock(&map->freeze_mutex);
940fc970227SAndrii Nakryiko 
941dfeb376dSAndrii Nakryiko 	if (vma->vm_flags & VM_WRITE) {
942dfeb376dSAndrii Nakryiko 		if (map->frozen) {
943fc970227SAndrii Nakryiko 			err = -EPERM;
944fc970227SAndrii Nakryiko 			goto out;
945fc970227SAndrii Nakryiko 		}
946dfeb376dSAndrii Nakryiko 		/* map is meant to be read-only, so do not allow mapping as
947dfeb376dSAndrii Nakryiko 		 * writable, because it's possible to leak a writable page
948dfeb376dSAndrii Nakryiko 		 * reference and allows user-space to still modify it after
949dfeb376dSAndrii Nakryiko 		 * freezing, while verifier will assume contents do not change
950dfeb376dSAndrii Nakryiko 		 */
951dfeb376dSAndrii Nakryiko 		if (map->map_flags & BPF_F_RDONLY_PROG) {
952dfeb376dSAndrii Nakryiko 			err = -EACCES;
953dfeb376dSAndrii Nakryiko 			goto out;
954dfeb376dSAndrii Nakryiko 		}
955dfeb376dSAndrii Nakryiko 	}
956fc970227SAndrii Nakryiko 
957fc970227SAndrii Nakryiko 	/* set default open/close callbacks */
958fc970227SAndrii Nakryiko 	vma->vm_ops = &bpf_map_default_vmops;
959fc970227SAndrii Nakryiko 	vma->vm_private_data = map;
9601c71222eSSuren Baghdasaryan 	vm_flags_clear(vma, VM_MAYEXEC);
9611f6cb19bSAndrii Nakryiko 	if (!(vma->vm_flags & VM_WRITE))
9621f6cb19bSAndrii Nakryiko 		/* disallow re-mapping with PROT_WRITE */
9631c71222eSSuren Baghdasaryan 		vm_flags_clear(vma, VM_MAYWRITE);
964fc970227SAndrii Nakryiko 
965fc970227SAndrii Nakryiko 	err = map->ops->map_mmap(map, vma);
966fc970227SAndrii Nakryiko 	if (err)
967fc970227SAndrii Nakryiko 		goto out;
968fc970227SAndrii Nakryiko 
9691f6cb19bSAndrii Nakryiko 	if (vma->vm_flags & VM_MAYWRITE)
970353050beSDaniel Borkmann 		bpf_map_write_active_inc(map);
971fc970227SAndrii Nakryiko out:
972fc970227SAndrii Nakryiko 	mutex_unlock(&map->freeze_mutex);
973fc970227SAndrii Nakryiko 	return err;
974fc970227SAndrii Nakryiko }
975fc970227SAndrii Nakryiko 
976457f4436SAndrii Nakryiko static __poll_t bpf_map_poll(struct file *filp, struct poll_table_struct *pts)
977457f4436SAndrii Nakryiko {
978457f4436SAndrii Nakryiko 	struct bpf_map *map = filp->private_data;
979457f4436SAndrii Nakryiko 
980457f4436SAndrii Nakryiko 	if (map->ops->map_poll)
981457f4436SAndrii Nakryiko 		return map->ops->map_poll(map, filp, pts);
982457f4436SAndrii Nakryiko 
983457f4436SAndrii Nakryiko 	return EPOLLERR;
984457f4436SAndrii Nakryiko }
985457f4436SAndrii Nakryiko 
986cf2c2e4aSAlexei Starovoitov static unsigned long bpf_get_unmapped_area(struct file *filp, unsigned long addr,
987cf2c2e4aSAlexei Starovoitov 					   unsigned long len, unsigned long pgoff,
988cf2c2e4aSAlexei Starovoitov 					   unsigned long flags)
989cf2c2e4aSAlexei Starovoitov {
990cf2c2e4aSAlexei Starovoitov 	struct bpf_map *map = filp->private_data;
991cf2c2e4aSAlexei Starovoitov 
992cf2c2e4aSAlexei Starovoitov 	if (map->ops->map_get_unmapped_area)
993cf2c2e4aSAlexei Starovoitov 		return map->ops->map_get_unmapped_area(filp, addr, len, pgoff, flags);
994cf2c2e4aSAlexei Starovoitov #ifdef CONFIG_MMU
995529ce23aSRick Edgecombe 	return mm_get_unmapped_area(current->mm, filp, addr, len, pgoff, flags);
996cf2c2e4aSAlexei Starovoitov #else
997cf2c2e4aSAlexei Starovoitov 	return addr;
998cf2c2e4aSAlexei Starovoitov #endif
999cf2c2e4aSAlexei Starovoitov }
1000cf2c2e4aSAlexei Starovoitov 
1001f66e448cSChenbo Feng const struct file_operations bpf_map_fops = {
1002f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
1003f99bf205SDaniel Borkmann 	.show_fdinfo	= bpf_map_show_fdinfo,
1004f99bf205SDaniel Borkmann #endif
100599c55f7dSAlexei Starovoitov 	.release	= bpf_map_release,
10066e71b04aSChenbo Feng 	.read		= bpf_dummy_read,
10076e71b04aSChenbo Feng 	.write		= bpf_dummy_write,
1008fc970227SAndrii Nakryiko 	.mmap		= bpf_map_mmap,
1009457f4436SAndrii Nakryiko 	.poll		= bpf_map_poll,
1010cf2c2e4aSAlexei Starovoitov 	.get_unmapped_area = bpf_get_unmapped_area,
101199c55f7dSAlexei Starovoitov };
101299c55f7dSAlexei Starovoitov 
10136e71b04aSChenbo Feng int bpf_map_new_fd(struct bpf_map *map, int flags)
1014aa79781bSDaniel Borkmann {
1015afdb09c7SChenbo Feng 	int ret;
1016afdb09c7SChenbo Feng 
1017afdb09c7SChenbo Feng 	ret = security_bpf_map(map, OPEN_FMODE(flags));
1018afdb09c7SChenbo Feng 	if (ret < 0)
1019afdb09c7SChenbo Feng 		return ret;
1020afdb09c7SChenbo Feng 
1021aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-map", &bpf_map_fops, map,
10226e71b04aSChenbo Feng 				flags | O_CLOEXEC);
10236e71b04aSChenbo Feng }
10246e71b04aSChenbo Feng 
10256e71b04aSChenbo Feng int bpf_get_file_flag(int flags)
10266e71b04aSChenbo Feng {
10276e71b04aSChenbo Feng 	if ((flags & BPF_F_RDONLY) && (flags & BPF_F_WRONLY))
10286e71b04aSChenbo Feng 		return -EINVAL;
10296e71b04aSChenbo Feng 	if (flags & BPF_F_RDONLY)
10306e71b04aSChenbo Feng 		return O_RDONLY;
10316e71b04aSChenbo Feng 	if (flags & BPF_F_WRONLY)
10326e71b04aSChenbo Feng 		return O_WRONLY;
10336e71b04aSChenbo Feng 	return O_RDWR;
1034aa79781bSDaniel Borkmann }
1035aa79781bSDaniel Borkmann 
103699c55f7dSAlexei Starovoitov /* helper macro to check that unused fields 'union bpf_attr' are zero */
103799c55f7dSAlexei Starovoitov #define CHECK_ATTR(CMD) \
103899c55f7dSAlexei Starovoitov 	memchr_inv((void *) &attr->CMD##_LAST_FIELD + \
103999c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD), 0, \
104099c55f7dSAlexei Starovoitov 		   sizeof(*attr) - \
104199c55f7dSAlexei Starovoitov 		   offsetof(union bpf_attr, CMD##_LAST_FIELD) - \
104299c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD)) != NULL
104399c55f7dSAlexei Starovoitov 
10448e7ae251SMartin KaFai Lau /* dst and src must have at least "size" number of bytes.
10458e7ae251SMartin KaFai Lau  * Return strlen on success and < 0 on error.
1046cb4d2b3fSMartin KaFai Lau  */
10478e7ae251SMartin KaFai Lau int bpf_obj_name_cpy(char *dst, const char *src, unsigned int size)
1048cb4d2b3fSMartin KaFai Lau {
10498e7ae251SMartin KaFai Lau 	const char *end = src + size;
10508e7ae251SMartin KaFai Lau 	const char *orig_src = src;
1051cb4d2b3fSMartin KaFai Lau 
10528e7ae251SMartin KaFai Lau 	memset(dst, 0, size);
10533e0ddc4fSDaniel Borkmann 	/* Copy all isalnum(), '_' and '.' chars. */
1054cb4d2b3fSMartin KaFai Lau 	while (src < end && *src) {
10553e0ddc4fSDaniel Borkmann 		if (!isalnum(*src) &&
10563e0ddc4fSDaniel Borkmann 		    *src != '_' && *src != '.')
1057cb4d2b3fSMartin KaFai Lau 			return -EINVAL;
1058cb4d2b3fSMartin KaFai Lau 		*dst++ = *src++;
1059cb4d2b3fSMartin KaFai Lau 	}
1060cb4d2b3fSMartin KaFai Lau 
10618e7ae251SMartin KaFai Lau 	/* No '\0' found in "size" number of bytes */
1062cb4d2b3fSMartin KaFai Lau 	if (src == end)
1063cb4d2b3fSMartin KaFai Lau 		return -EINVAL;
1064cb4d2b3fSMartin KaFai Lau 
10658e7ae251SMartin KaFai Lau 	return src - orig_src;
1066cb4d2b3fSMartin KaFai Lau }
1067cb4d2b3fSMartin KaFai Lau 
1068e8d2bec0SDaniel Borkmann int map_check_no_btf(const struct bpf_map *map,
10691b2b234bSRoman Gushchin 		     const struct btf *btf,
1070e8d2bec0SDaniel Borkmann 		     const struct btf_type *key_type,
1071e8d2bec0SDaniel Borkmann 		     const struct btf_type *value_type)
1072e8d2bec0SDaniel Borkmann {
1073e8d2bec0SDaniel Borkmann 	return -ENOTSUPP;
1074e8d2bec0SDaniel Borkmann }
1075e8d2bec0SDaniel Borkmann 
1076a177fc2bSAndrii Nakryiko static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
1077a177fc2bSAndrii Nakryiko 			 const struct btf *btf, u32 btf_key_id, u32 btf_value_id)
1078e8d2bec0SDaniel Borkmann {
1079e8d2bec0SDaniel Borkmann 	const struct btf_type *key_type, *value_type;
1080e8d2bec0SDaniel Borkmann 	u32 key_size, value_size;
1081e8d2bec0SDaniel Borkmann 	int ret = 0;
1082e8d2bec0SDaniel Borkmann 
10832824ecb7SDaniel Borkmann 	/* Some maps allow key to be unspecified. */
10842824ecb7SDaniel Borkmann 	if (btf_key_id) {
1085e8d2bec0SDaniel Borkmann 		key_type = btf_type_id_size(btf, &btf_key_id, &key_size);
1086e8d2bec0SDaniel Borkmann 		if (!key_type || key_size != map->key_size)
1087e8d2bec0SDaniel Borkmann 			return -EINVAL;
10882824ecb7SDaniel Borkmann 	} else {
10892824ecb7SDaniel Borkmann 		key_type = btf_type_by_id(btf, 0);
10902824ecb7SDaniel Borkmann 		if (!map->ops->map_check_btf)
10912824ecb7SDaniel Borkmann 			return -EINVAL;
10922824ecb7SDaniel Borkmann 	}
1093e8d2bec0SDaniel Borkmann 
1094e8d2bec0SDaniel Borkmann 	value_type = btf_type_id_size(btf, &btf_value_id, &value_size);
1095e8d2bec0SDaniel Borkmann 	if (!value_type || value_size != map->value_size)
1096e8d2bec0SDaniel Borkmann 		return -EINVAL;
1097e8d2bec0SDaniel Borkmann 
1098f0c5941fSKumar Kartikeya Dwivedi 	map->record = btf_parse_fields(btf, value_type,
10999c395c1bSDave Marchevsky 				       BPF_SPIN_LOCK | BPF_TIMER | BPF_KPTR | BPF_LIST_HEAD |
1100d56b63cfSBenjamin Tissoires 				       BPF_RB_ROOT | BPF_REFCOUNT | BPF_WORKQUEUE,
1101db559117SKumar Kartikeya Dwivedi 				       map->value_size);
1102aa3496acSKumar Kartikeya Dwivedi 	if (!IS_ERR_OR_NULL(map->record)) {
1103aa3496acSKumar Kartikeya Dwivedi 		int i;
1104aa3496acSKumar Kartikeya Dwivedi 
1105a177fc2bSAndrii Nakryiko 		if (!bpf_token_capable(token, CAP_BPF)) {
110661df10c7SKumar Kartikeya Dwivedi 			ret = -EPERM;
110761df10c7SKumar Kartikeya Dwivedi 			goto free_map_tab;
110861df10c7SKumar Kartikeya Dwivedi 		}
110961df10c7SKumar Kartikeya Dwivedi 		if (map->map_flags & (BPF_F_RDONLY_PROG | BPF_F_WRONLY_PROG)) {
111061df10c7SKumar Kartikeya Dwivedi 			ret = -EACCES;
111161df10c7SKumar Kartikeya Dwivedi 			goto free_map_tab;
111261df10c7SKumar Kartikeya Dwivedi 		}
1113aa3496acSKumar Kartikeya Dwivedi 		for (i = 0; i < sizeof(map->record->field_mask) * 8; i++) {
1114aa3496acSKumar Kartikeya Dwivedi 			switch (map->record->field_mask & (1 << i)) {
1115aa3496acSKumar Kartikeya Dwivedi 			case 0:
1116aa3496acSKumar Kartikeya Dwivedi 				continue;
1117db559117SKumar Kartikeya Dwivedi 			case BPF_SPIN_LOCK:
1118db559117SKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
1119db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY &&
1120db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_CGROUP_STORAGE &&
1121db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_SK_STORAGE &&
1122db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_INODE_STORAGE &&
1123db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_TASK_STORAGE &&
1124db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_CGRP_STORAGE) {
1125db559117SKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
1126db559117SKumar Kartikeya Dwivedi 					goto free_map_tab;
1127db559117SKumar Kartikeya Dwivedi 				}
1128db559117SKumar Kartikeya Dwivedi 				break;
1129db559117SKumar Kartikeya Dwivedi 			case BPF_TIMER:
1130246331e3SBenjamin Tissoires 			case BPF_WORKQUEUE:
1131db559117SKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
1132db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
1133db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY) {
1134c237bfa5SKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
1135db559117SKumar Kartikeya Dwivedi 					goto free_map_tab;
1136db559117SKumar Kartikeya Dwivedi 				}
1137db559117SKumar Kartikeya Dwivedi 				break;
1138aa3496acSKumar Kartikeya Dwivedi 			case BPF_KPTR_UNREF:
1139aa3496acSKumar Kartikeya Dwivedi 			case BPF_KPTR_REF:
114055db92f4SYonghong Song 			case BPF_KPTR_PERCPU:
1141d54730b5SDave Marchevsky 			case BPF_REFCOUNT:
114261df10c7SKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
114365334e64SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_PERCPU_HASH &&
114461df10c7SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
114565334e64SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_LRU_PERCPU_HASH &&
11466df4ea1fSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY &&
11479db44fddSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_PERCPU_ARRAY &&
11489db44fddSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_SK_STORAGE &&
11499db44fddSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_INODE_STORAGE &&
11509db44fddSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_TASK_STORAGE &&
11519db44fddSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_CGRP_STORAGE) {
115261df10c7SKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
115361df10c7SKumar Kartikeya Dwivedi 					goto free_map_tab;
115461df10c7SKumar Kartikeya Dwivedi 				}
1155aa3496acSKumar Kartikeya Dwivedi 				break;
1156f0c5941fSKumar Kartikeya Dwivedi 			case BPF_LIST_HEAD:
11579c395c1bSDave Marchevsky 			case BPF_RB_ROOT:
1158f0c5941fSKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
1159f0c5941fSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
1160f0c5941fSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY) {
1161f0c5941fSKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
1162f0c5941fSKumar Kartikeya Dwivedi 					goto free_map_tab;
1163f0c5941fSKumar Kartikeya Dwivedi 				}
1164f0c5941fSKumar Kartikeya Dwivedi 				break;
1165aa3496acSKumar Kartikeya Dwivedi 			default:
1166aa3496acSKumar Kartikeya Dwivedi 				/* Fail if map_type checks are missing for a field type */
1167aa3496acSKumar Kartikeya Dwivedi 				ret = -EOPNOTSUPP;
1168aa3496acSKumar Kartikeya Dwivedi 				goto free_map_tab;
1169aa3496acSKumar Kartikeya Dwivedi 			}
1170aa3496acSKumar Kartikeya Dwivedi 		}
117161df10c7SKumar Kartikeya Dwivedi 	}
1172e8d2bec0SDaniel Borkmann 
1173865ce09aSKumar Kartikeya Dwivedi 	ret = btf_check_and_fixup_fields(btf, map->record);
1174865ce09aSKumar Kartikeya Dwivedi 	if (ret < 0)
1175865ce09aSKumar Kartikeya Dwivedi 		goto free_map_tab;
1176865ce09aSKumar Kartikeya Dwivedi 
117761df10c7SKumar Kartikeya Dwivedi 	if (map->ops->map_check_btf) {
117861df10c7SKumar Kartikeya Dwivedi 		ret = map->ops->map_check_btf(map, btf, key_type, value_type);
117961df10c7SKumar Kartikeya Dwivedi 		if (ret < 0)
118061df10c7SKumar Kartikeya Dwivedi 			goto free_map_tab;
118161df10c7SKumar Kartikeya Dwivedi 	}
118261df10c7SKumar Kartikeya Dwivedi 
118361df10c7SKumar Kartikeya Dwivedi 	return ret;
118461df10c7SKumar Kartikeya Dwivedi free_map_tab:
1185aa3496acSKumar Kartikeya Dwivedi 	bpf_map_free_record(map);
1186e8d2bec0SDaniel Borkmann 	return ret;
1187e8d2bec0SDaniel Borkmann }
1188e8d2bec0SDaniel Borkmann 
1189ed1ad5a7SAndrii Nakryiko static bool bpf_net_capable(void)
1190ed1ad5a7SAndrii Nakryiko {
1191ed1ad5a7SAndrii Nakryiko 	return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
1192ed1ad5a7SAndrii Nakryiko }
1193ed1ad5a7SAndrii Nakryiko 
1194a177fc2bSAndrii Nakryiko #define BPF_MAP_CREATE_LAST_FIELD map_token_fd
119599c55f7dSAlexei Starovoitov /* called via syscall */
119699c55f7dSAlexei Starovoitov static int map_create(union bpf_attr *attr)
119799c55f7dSAlexei Starovoitov {
119822db4122SAndrii Nakryiko 	const struct bpf_map_ops *ops;
1199a177fc2bSAndrii Nakryiko 	struct bpf_token *token = NULL;
120096eabe7aSMartin KaFai Lau 	int numa_node = bpf_map_attr_numa_node(attr);
120122db4122SAndrii Nakryiko 	u32 map_type = attr->map_type;
120299c55f7dSAlexei Starovoitov 	struct bpf_map *map;
1203a177fc2bSAndrii Nakryiko 	bool token_flag;
12046e71b04aSChenbo Feng 	int f_flags;
120599c55f7dSAlexei Starovoitov 	int err;
120699c55f7dSAlexei Starovoitov 
120799c55f7dSAlexei Starovoitov 	err = CHECK_ATTR(BPF_MAP_CREATE);
120899c55f7dSAlexei Starovoitov 	if (err)
120999c55f7dSAlexei Starovoitov 		return -EINVAL;
121099c55f7dSAlexei Starovoitov 
1211a177fc2bSAndrii Nakryiko 	/* check BPF_F_TOKEN_FD flag, remember if it's set, and then clear it
1212a177fc2bSAndrii Nakryiko 	 * to avoid per-map type checks tripping on unknown flag
1213a177fc2bSAndrii Nakryiko 	 */
1214a177fc2bSAndrii Nakryiko 	token_flag = attr->map_flags & BPF_F_TOKEN_FD;
1215a177fc2bSAndrii Nakryiko 	attr->map_flags &= ~BPF_F_TOKEN_FD;
1216a177fc2bSAndrii Nakryiko 
121785d33df3SMartin KaFai Lau 	if (attr->btf_vmlinux_value_type_id) {
121885d33df3SMartin KaFai Lau 		if (attr->map_type != BPF_MAP_TYPE_STRUCT_OPS ||
121985d33df3SMartin KaFai Lau 		    attr->btf_key_type_id || attr->btf_value_type_id)
122085d33df3SMartin KaFai Lau 			return -EINVAL;
122185d33df3SMartin KaFai Lau 	} else if (attr->btf_key_type_id && !attr->btf_value_type_id) {
122285d33df3SMartin KaFai Lau 		return -EINVAL;
122385d33df3SMartin KaFai Lau 	}
122485d33df3SMartin KaFai Lau 
12259330986cSJoanne Koong 	if (attr->map_type != BPF_MAP_TYPE_BLOOM_FILTER &&
122631746031SAlexei Starovoitov 	    attr->map_type != BPF_MAP_TYPE_ARENA &&
12279330986cSJoanne Koong 	    attr->map_extra != 0)
12289330986cSJoanne Koong 		return -EINVAL;
12299330986cSJoanne Koong 
12306e71b04aSChenbo Feng 	f_flags = bpf_get_file_flag(attr->map_flags);
12316e71b04aSChenbo Feng 	if (f_flags < 0)
12326e71b04aSChenbo Feng 		return f_flags;
12336e71b04aSChenbo Feng 
123496eabe7aSMartin KaFai Lau 	if (numa_node != NUMA_NO_NODE &&
123596e5ae4eSEric Dumazet 	    ((unsigned int)numa_node >= nr_node_ids ||
123696e5ae4eSEric Dumazet 	     !node_online(numa_node)))
123796eabe7aSMartin KaFai Lau 		return -EINVAL;
123896eabe7aSMartin KaFai Lau 
123999c55f7dSAlexei Starovoitov 	/* find map type and init map: hashtable vs rbtree vs bloom vs ... */
124022db4122SAndrii Nakryiko 	map_type = attr->map_type;
124122db4122SAndrii Nakryiko 	if (map_type >= ARRAY_SIZE(bpf_map_types))
124222db4122SAndrii Nakryiko 		return -EINVAL;
124322db4122SAndrii Nakryiko 	map_type = array_index_nospec(map_type, ARRAY_SIZE(bpf_map_types));
124422db4122SAndrii Nakryiko 	ops = bpf_map_types[map_type];
124522db4122SAndrii Nakryiko 	if (!ops)
124622db4122SAndrii Nakryiko 		return -EINVAL;
124722db4122SAndrii Nakryiko 
124822db4122SAndrii Nakryiko 	if (ops->map_alloc_check) {
124922db4122SAndrii Nakryiko 		err = ops->map_alloc_check(attr);
125022db4122SAndrii Nakryiko 		if (err)
125122db4122SAndrii Nakryiko 			return err;
125222db4122SAndrii Nakryiko 	}
125322db4122SAndrii Nakryiko 	if (attr->map_ifindex)
125422db4122SAndrii Nakryiko 		ops = &bpf_map_offload_ops;
125522db4122SAndrii Nakryiko 	if (!ops->map_mem_usage)
125622db4122SAndrii Nakryiko 		return -EINVAL;
125722db4122SAndrii Nakryiko 
1258a177fc2bSAndrii Nakryiko 	if (token_flag) {
1259a177fc2bSAndrii Nakryiko 		token = bpf_token_get_from_fd(attr->map_token_fd);
1260a177fc2bSAndrii Nakryiko 		if (IS_ERR(token))
1261a177fc2bSAndrii Nakryiko 			return PTR_ERR(token);
1262a177fc2bSAndrii Nakryiko 
1263a177fc2bSAndrii Nakryiko 		/* if current token doesn't grant map creation permissions,
1264a177fc2bSAndrii Nakryiko 		 * then we can't use this token, so ignore it and rely on
1265a177fc2bSAndrii Nakryiko 		 * system-wide capabilities checks
1266a177fc2bSAndrii Nakryiko 		 */
1267a177fc2bSAndrii Nakryiko 		if (!bpf_token_allow_cmd(token, BPF_MAP_CREATE) ||
1268a177fc2bSAndrii Nakryiko 		    !bpf_token_allow_map_type(token, attr->map_type)) {
1269a177fc2bSAndrii Nakryiko 			bpf_token_put(token);
1270a177fc2bSAndrii Nakryiko 			token = NULL;
1271a177fc2bSAndrii Nakryiko 		}
1272a177fc2bSAndrii Nakryiko 	}
1273a177fc2bSAndrii Nakryiko 
1274a177fc2bSAndrii Nakryiko 	err = -EPERM;
1275a177fc2bSAndrii Nakryiko 
12761d28635aSAndrii Nakryiko 	/* Intent here is for unprivileged_bpf_disabled to block BPF map
12771d28635aSAndrii Nakryiko 	 * creation for unprivileged users; other actions depend
12781d28635aSAndrii Nakryiko 	 * on fd availability and access to bpffs, so are dependent on
12791d28635aSAndrii Nakryiko 	 * object creation success. Even with unprivileged BPF disabled,
12801d28635aSAndrii Nakryiko 	 * capability checks are still carried out.
12811d28635aSAndrii Nakryiko 	 */
1282a177fc2bSAndrii Nakryiko 	if (sysctl_unprivileged_bpf_disabled && !bpf_token_capable(token, CAP_BPF))
1283a177fc2bSAndrii Nakryiko 		goto put_token;
12841d28635aSAndrii Nakryiko 
12856c3eba1cSAndrii Nakryiko 	/* check privileged map type permissions */
12866c3eba1cSAndrii Nakryiko 	switch (map_type) {
12876c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_ARRAY:
12886c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_PERCPU_ARRAY:
12896c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_PROG_ARRAY:
12906c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
12916c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_CGROUP_ARRAY:
12926c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_ARRAY_OF_MAPS:
12936c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_HASH:
12946c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_PERCPU_HASH:
12956c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_HASH_OF_MAPS:
12966c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_RINGBUF:
12976c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_USER_RINGBUF:
12986c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_CGROUP_STORAGE:
12996c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE:
13006c3eba1cSAndrii Nakryiko 		/* unprivileged */
13016c3eba1cSAndrii Nakryiko 		break;
13026c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_SK_STORAGE:
13036c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_INODE_STORAGE:
13046c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_TASK_STORAGE:
13056c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_CGRP_STORAGE:
13066c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_BLOOM_FILTER:
13076c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_LPM_TRIE:
13086c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY:
13096c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_STACK_TRACE:
13106c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_QUEUE:
13116c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_STACK:
13126c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_LRU_HASH:
13136c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_LRU_PERCPU_HASH:
13146c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_STRUCT_OPS:
13156c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_CPUMAP:
131631746031SAlexei Starovoitov 	case BPF_MAP_TYPE_ARENA:
1317a177fc2bSAndrii Nakryiko 		if (!bpf_token_capable(token, CAP_BPF))
1318a177fc2bSAndrii Nakryiko 			goto put_token;
13196c3eba1cSAndrii Nakryiko 		break;
13206c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_SOCKMAP:
13216c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_SOCKHASH:
13226c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_DEVMAP:
13236c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_DEVMAP_HASH:
13246c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_XSKMAP:
1325a177fc2bSAndrii Nakryiko 		if (!bpf_token_capable(token, CAP_NET_ADMIN))
1326a177fc2bSAndrii Nakryiko 			goto put_token;
13276c3eba1cSAndrii Nakryiko 		break;
13286c3eba1cSAndrii Nakryiko 	default:
13296c3eba1cSAndrii Nakryiko 		WARN(1, "unsupported map type %d", map_type);
1330a177fc2bSAndrii Nakryiko 		goto put_token;
13316c3eba1cSAndrii Nakryiko 	}
13326c3eba1cSAndrii Nakryiko 
133322db4122SAndrii Nakryiko 	map = ops->map_alloc(attr);
1334a177fc2bSAndrii Nakryiko 	if (IS_ERR(map)) {
1335a177fc2bSAndrii Nakryiko 		err = PTR_ERR(map);
1336a177fc2bSAndrii Nakryiko 		goto put_token;
1337a177fc2bSAndrii Nakryiko 	}
133822db4122SAndrii Nakryiko 	map->ops = ops;
133922db4122SAndrii Nakryiko 	map->map_type = map_type;
134099c55f7dSAlexei Starovoitov 
13418e7ae251SMartin KaFai Lau 	err = bpf_obj_name_cpy(map->name, attr->map_name,
13428e7ae251SMartin KaFai Lau 			       sizeof(attr->map_name));
13438e7ae251SMartin KaFai Lau 	if (err < 0)
1344b936ca64SRoman Gushchin 		goto free_map;
1345ad5b177bSMartin KaFai Lau 
13461e0bd5a0SAndrii Nakryiko 	atomic64_set(&map->refcnt, 1);
13471e0bd5a0SAndrii Nakryiko 	atomic64_set(&map->usercnt, 1);
1348fc970227SAndrii Nakryiko 	mutex_init(&map->freeze_mutex);
1349f45d5b6cSToke Hoiland-Jorgensen 	spin_lock_init(&map->owner.lock);
135099c55f7dSAlexei Starovoitov 
135185d33df3SMartin KaFai Lau 	if (attr->btf_key_type_id || attr->btf_value_type_id ||
135285d33df3SMartin KaFai Lau 	    /* Even the map's value is a kernel's struct,
135385d33df3SMartin KaFai Lau 	     * the bpf_prog.o must have BTF to begin with
135485d33df3SMartin KaFai Lau 	     * to figure out the corresponding kernel's
135585d33df3SMartin KaFai Lau 	     * counter part.  Thus, attr->btf_fd has
135685d33df3SMartin KaFai Lau 	     * to be valid also.
135785d33df3SMartin KaFai Lau 	     */
135885d33df3SMartin KaFai Lau 	    attr->btf_vmlinux_value_type_id) {
1359a26ca7c9SMartin KaFai Lau 		struct btf *btf;
1360a26ca7c9SMartin KaFai Lau 
1361a26ca7c9SMartin KaFai Lau 		btf = btf_get_by_fd(attr->btf_fd);
1362a26ca7c9SMartin KaFai Lau 		if (IS_ERR(btf)) {
1363a26ca7c9SMartin KaFai Lau 			err = PTR_ERR(btf);
1364b936ca64SRoman Gushchin 			goto free_map;
1365a26ca7c9SMartin KaFai Lau 		}
1366350a5c4dSAlexei Starovoitov 		if (btf_is_kernel(btf)) {
1367350a5c4dSAlexei Starovoitov 			btf_put(btf);
1368350a5c4dSAlexei Starovoitov 			err = -EACCES;
1369350a5c4dSAlexei Starovoitov 			goto free_map;
1370350a5c4dSAlexei Starovoitov 		}
137185d33df3SMartin KaFai Lau 		map->btf = btf;
1372a26ca7c9SMartin KaFai Lau 
137385d33df3SMartin KaFai Lau 		if (attr->btf_value_type_id) {
1374a177fc2bSAndrii Nakryiko 			err = map_check_btf(map, token, btf, attr->btf_key_type_id,
13759b2cf328SMartin KaFai Lau 					    attr->btf_value_type_id);
137685d33df3SMartin KaFai Lau 			if (err)
1377b936ca64SRoman Gushchin 				goto free_map;
1378a26ca7c9SMartin KaFai Lau 		}
1379a26ca7c9SMartin KaFai Lau 
13809b2cf328SMartin KaFai Lau 		map->btf_key_type_id = attr->btf_key_type_id;
13819b2cf328SMartin KaFai Lau 		map->btf_value_type_id = attr->btf_value_type_id;
138285d33df3SMartin KaFai Lau 		map->btf_vmlinux_value_type_id =
138385d33df3SMartin KaFai Lau 			attr->btf_vmlinux_value_type_id;
1384a26ca7c9SMartin KaFai Lau 	}
1385a26ca7c9SMartin KaFai Lau 
1386a2431c7eSAndrii Nakryiko 	err = security_bpf_map_create(map, attr, token);
13874d7d7f69SKumar Kartikeya Dwivedi 	if (err)
1388a2431c7eSAndrii Nakryiko 		goto free_map_sec;
13894d7d7f69SKumar Kartikeya Dwivedi 
1390f3f1c054SMartin KaFai Lau 	err = bpf_map_alloc_id(map);
1391f3f1c054SMartin KaFai Lau 	if (err)
1392b936ca64SRoman Gushchin 		goto free_map_sec;
1393f3f1c054SMartin KaFai Lau 
139448edc1f7SRoman Gushchin 	bpf_map_save_memcg(map);
1395a177fc2bSAndrii Nakryiko 	bpf_token_put(token);
139648edc1f7SRoman Gushchin 
13976e71b04aSChenbo Feng 	err = bpf_map_new_fd(map, f_flags);
1398bd5f5f4eSMartin KaFai Lau 	if (err < 0) {
1399bd5f5f4eSMartin KaFai Lau 		/* failed to allocate fd.
1400352d20d6SPeng Sun 		 * bpf_map_put_with_uref() is needed because the above
1401bd5f5f4eSMartin KaFai Lau 		 * bpf_map_alloc_id() has published the map
1402bd5f5f4eSMartin KaFai Lau 		 * to the userspace and the userspace may
1403bd5f5f4eSMartin KaFai Lau 		 * have refcnt-ed it through BPF_MAP_GET_FD_BY_ID.
1404bd5f5f4eSMartin KaFai Lau 		 */
1405352d20d6SPeng Sun 		bpf_map_put_with_uref(map);
1406bd5f5f4eSMartin KaFai Lau 		return err;
1407bd5f5f4eSMartin KaFai Lau 	}
140899c55f7dSAlexei Starovoitov 
140999c55f7dSAlexei Starovoitov 	return err;
141099c55f7dSAlexei Starovoitov 
1411afdb09c7SChenbo Feng free_map_sec:
1412afdb09c7SChenbo Feng 	security_bpf_map_free(map);
1413b936ca64SRoman Gushchin free_map:
1414a26ca7c9SMartin KaFai Lau 	btf_put(map->btf);
141599c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
1416a177fc2bSAndrii Nakryiko put_token:
1417a177fc2bSAndrii Nakryiko 	bpf_token_put(token);
141899c55f7dSAlexei Starovoitov 	return err;
141999c55f7dSAlexei Starovoitov }
142099c55f7dSAlexei Starovoitov 
1421db20fd2bSAlexei Starovoitov /* if error is returned, fd is released.
1422db20fd2bSAlexei Starovoitov  * On success caller should complete fd access with matching fdput()
1423db20fd2bSAlexei Starovoitov  */
1424c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f)
1425db20fd2bSAlexei Starovoitov {
1426db20fd2bSAlexei Starovoitov 	if (!f.file)
1427db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EBADF);
1428db20fd2bSAlexei Starovoitov 	if (f.file->f_op != &bpf_map_fops) {
1429db20fd2bSAlexei Starovoitov 		fdput(f);
1430db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EINVAL);
1431db20fd2bSAlexei Starovoitov 	}
1432db20fd2bSAlexei Starovoitov 
1433c2101297SDaniel Borkmann 	return f.file->private_data;
1434c2101297SDaniel Borkmann }
1435c2101297SDaniel Borkmann 
14361e0bd5a0SAndrii Nakryiko void bpf_map_inc(struct bpf_map *map)
1437c9da161cSDaniel Borkmann {
14381e0bd5a0SAndrii Nakryiko 	atomic64_inc(&map->refcnt);
1439c9da161cSDaniel Borkmann }
1440630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_inc);
1441c9da161cSDaniel Borkmann 
14421e0bd5a0SAndrii Nakryiko void bpf_map_inc_with_uref(struct bpf_map *map)
14431e0bd5a0SAndrii Nakryiko {
14441e0bd5a0SAndrii Nakryiko 	atomic64_inc(&map->refcnt);
14451e0bd5a0SAndrii Nakryiko 	atomic64_inc(&map->usercnt);
14461e0bd5a0SAndrii Nakryiko }
14471e0bd5a0SAndrii Nakryiko EXPORT_SYMBOL_GPL(bpf_map_inc_with_uref);
14481e0bd5a0SAndrii Nakryiko 
14491ed4d924SMartin KaFai Lau struct bpf_map *bpf_map_get(u32 ufd)
14501ed4d924SMartin KaFai Lau {
14511ed4d924SMartin KaFai Lau 	struct fd f = fdget(ufd);
14521ed4d924SMartin KaFai Lau 	struct bpf_map *map;
14531ed4d924SMartin KaFai Lau 
14541ed4d924SMartin KaFai Lau 	map = __bpf_map_get(f);
14551ed4d924SMartin KaFai Lau 	if (IS_ERR(map))
14561ed4d924SMartin KaFai Lau 		return map;
14571ed4d924SMartin KaFai Lau 
14581ed4d924SMartin KaFai Lau 	bpf_map_inc(map);
14591ed4d924SMartin KaFai Lau 	fdput(f);
14601ed4d924SMartin KaFai Lau 
14611ed4d924SMartin KaFai Lau 	return map;
14621ed4d924SMartin KaFai Lau }
1463b1d18a75SAlexei Starovoitov EXPORT_SYMBOL(bpf_map_get);
14641ed4d924SMartin KaFai Lau 
1465c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd)
1466c2101297SDaniel Borkmann {
1467c2101297SDaniel Borkmann 	struct fd f = fdget(ufd);
1468c2101297SDaniel Borkmann 	struct bpf_map *map;
1469c2101297SDaniel Borkmann 
1470c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1471c2101297SDaniel Borkmann 	if (IS_ERR(map))
1472c2101297SDaniel Borkmann 		return map;
1473c2101297SDaniel Borkmann 
14741e0bd5a0SAndrii Nakryiko 	bpf_map_inc_with_uref(map);
1475c2101297SDaniel Borkmann 	fdput(f);
1476db20fd2bSAlexei Starovoitov 
1477db20fd2bSAlexei Starovoitov 	return map;
1478db20fd2bSAlexei Starovoitov }
1479db20fd2bSAlexei Starovoitov 
1480b671c206SKui-Feng Lee /* map_idr_lock should have been held or the map should have been
1481b671c206SKui-Feng Lee  * protected by rcu read lock.
1482b671c206SKui-Feng Lee  */
1483b671c206SKui-Feng Lee struct bpf_map *__bpf_map_inc_not_zero(struct bpf_map *map, bool uref)
1484bd5f5f4eSMartin KaFai Lau {
1485bd5f5f4eSMartin KaFai Lau 	int refold;
1486bd5f5f4eSMartin KaFai Lau 
14871e0bd5a0SAndrii Nakryiko 	refold = atomic64_fetch_add_unless(&map->refcnt, 1, 0);
1488bd5f5f4eSMartin KaFai Lau 	if (!refold)
1489bd5f5f4eSMartin KaFai Lau 		return ERR_PTR(-ENOENT);
1490bd5f5f4eSMartin KaFai Lau 	if (uref)
14911e0bd5a0SAndrii Nakryiko 		atomic64_inc(&map->usercnt);
1492bd5f5f4eSMartin KaFai Lau 
1493bd5f5f4eSMartin KaFai Lau 	return map;
1494bd5f5f4eSMartin KaFai Lau }
1495bd5f5f4eSMartin KaFai Lau 
14961e0bd5a0SAndrii Nakryiko struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map)
1497b0e4701cSStanislav Fomichev {
1498b0e4701cSStanislav Fomichev 	spin_lock_bh(&map_idr_lock);
14991e0bd5a0SAndrii Nakryiko 	map = __bpf_map_inc_not_zero(map, false);
1500b0e4701cSStanislav Fomichev 	spin_unlock_bh(&map_idr_lock);
1501b0e4701cSStanislav Fomichev 
1502b0e4701cSStanislav Fomichev 	return map;
1503b0e4701cSStanislav Fomichev }
1504b0e4701cSStanislav Fomichev EXPORT_SYMBOL_GPL(bpf_map_inc_not_zero);
1505b0e4701cSStanislav Fomichev 
1506b8cdc051SAlexei Starovoitov int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
1507b8cdc051SAlexei Starovoitov {
1508b8cdc051SAlexei Starovoitov 	return -ENOTSUPP;
1509b8cdc051SAlexei Starovoitov }
1510b8cdc051SAlexei Starovoitov 
1511c9d29f46SMauricio Vasquez B static void *__bpf_copy_key(void __user *ukey, u64 key_size)
1512c9d29f46SMauricio Vasquez B {
1513c9d29f46SMauricio Vasquez B 	if (key_size)
151444779a4bSStanislav Fomichev 		return vmemdup_user(ukey, key_size);
1515c9d29f46SMauricio Vasquez B 
1516c9d29f46SMauricio Vasquez B 	if (ukey)
1517c9d29f46SMauricio Vasquez B 		return ERR_PTR(-EINVAL);
1518c9d29f46SMauricio Vasquez B 
1519c9d29f46SMauricio Vasquez B 	return NULL;
1520c9d29f46SMauricio Vasquez B }
1521c9d29f46SMauricio Vasquez B 
1522af2ac3e1SAlexei Starovoitov static void *___bpf_copy_key(bpfptr_t ukey, u64 key_size)
1523af2ac3e1SAlexei Starovoitov {
1524af2ac3e1SAlexei Starovoitov 	if (key_size)
152544779a4bSStanislav Fomichev 		return kvmemdup_bpfptr(ukey, key_size);
1526af2ac3e1SAlexei Starovoitov 
1527af2ac3e1SAlexei Starovoitov 	if (!bpfptr_is_null(ukey))
1528af2ac3e1SAlexei Starovoitov 		return ERR_PTR(-EINVAL);
1529af2ac3e1SAlexei Starovoitov 
1530af2ac3e1SAlexei Starovoitov 	return NULL;
1531af2ac3e1SAlexei Starovoitov }
1532af2ac3e1SAlexei Starovoitov 
1533db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
153496049f3aSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD flags
1535db20fd2bSAlexei Starovoitov 
1536db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr)
1537db20fd2bSAlexei Starovoitov {
1538535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
1539535e7b4bSMickaël Salaün 	void __user *uvalue = u64_to_user_ptr(attr->value);
1540db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1541db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
154215c14a3dSBrian Vazquez 	void *key, *value;
154315a07b33SAlexei Starovoitov 	u32 value_size;
1544592867bfSDaniel Borkmann 	struct fd f;
1545db20fd2bSAlexei Starovoitov 	int err;
1546db20fd2bSAlexei Starovoitov 
1547db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
1548db20fd2bSAlexei Starovoitov 		return -EINVAL;
1549db20fd2bSAlexei Starovoitov 
155096049f3aSAlexei Starovoitov 	if (attr->flags & ~BPF_F_LOCK)
155196049f3aSAlexei Starovoitov 		return -EINVAL;
155296049f3aSAlexei Starovoitov 
1553592867bfSDaniel Borkmann 	f = fdget(ufd);
1554c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1555db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1556db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
155787df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
15586e71b04aSChenbo Feng 		err = -EPERM;
15596e71b04aSChenbo Feng 		goto err_put;
15606e71b04aSChenbo Feng 	}
15616e71b04aSChenbo Feng 
156296049f3aSAlexei Starovoitov 	if ((attr->flags & BPF_F_LOCK) &&
1563db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
156496049f3aSAlexei Starovoitov 		err = -EINVAL;
156596049f3aSAlexei Starovoitov 		goto err_put;
156696049f3aSAlexei Starovoitov 	}
156796049f3aSAlexei Starovoitov 
1568c9d29f46SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
1569e4448ed8SAl Viro 	if (IS_ERR(key)) {
1570e4448ed8SAl Viro 		err = PTR_ERR(key);
1571db20fd2bSAlexei Starovoitov 		goto err_put;
1572e4448ed8SAl Viro 	}
1573db20fd2bSAlexei Starovoitov 
157415c14a3dSBrian Vazquez 	value_size = bpf_map_value_size(map);
157515a07b33SAlexei Starovoitov 
15768ebe667cSAlexei Starovoitov 	err = -ENOMEM;
1577f0dce1d9SStanislav Fomichev 	value = kvmalloc(value_size, GFP_USER | __GFP_NOWARN);
1578db20fd2bSAlexei Starovoitov 	if (!value)
15798ebe667cSAlexei Starovoitov 		goto free_key;
15808ebe667cSAlexei Starovoitov 
15819330986cSJoanne Koong 	if (map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) {
15829330986cSJoanne Koong 		if (copy_from_user(value, uvalue, value_size))
15839330986cSJoanne Koong 			err = -EFAULT;
15849330986cSJoanne Koong 		else
15859330986cSJoanne Koong 			err = bpf_map_copy_value(map, key, value, attr->flags);
15869330986cSJoanne Koong 		goto free_value;
15879330986cSJoanne Koong 	}
15889330986cSJoanne Koong 
158915c14a3dSBrian Vazquez 	err = bpf_map_copy_value(map, key, value, attr->flags);
159015a07b33SAlexei Starovoitov 	if (err)
15918ebe667cSAlexei Starovoitov 		goto free_value;
1592db20fd2bSAlexei Starovoitov 
1593db20fd2bSAlexei Starovoitov 	err = -EFAULT;
159415a07b33SAlexei Starovoitov 	if (copy_to_user(uvalue, value, value_size) != 0)
15958ebe667cSAlexei Starovoitov 		goto free_value;
1596db20fd2bSAlexei Starovoitov 
1597db20fd2bSAlexei Starovoitov 	err = 0;
1598db20fd2bSAlexei Starovoitov 
15998ebe667cSAlexei Starovoitov free_value:
1600f0dce1d9SStanislav Fomichev 	kvfree(value);
1601db20fd2bSAlexei Starovoitov free_key:
160244779a4bSStanislav Fomichev 	kvfree(key);
1603db20fd2bSAlexei Starovoitov err_put:
1604db20fd2bSAlexei Starovoitov 	fdput(f);
1605db20fd2bSAlexei Starovoitov 	return err;
1606db20fd2bSAlexei Starovoitov }
1607db20fd2bSAlexei Starovoitov 
16081ae80cf3SDaniel Colascione 
16093274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags
1610db20fd2bSAlexei Starovoitov 
1611af2ac3e1SAlexei Starovoitov static int map_update_elem(union bpf_attr *attr, bpfptr_t uattr)
1612db20fd2bSAlexei Starovoitov {
1613af2ac3e1SAlexei Starovoitov 	bpfptr_t ukey = make_bpfptr(attr->key, uattr.is_kernel);
1614af2ac3e1SAlexei Starovoitov 	bpfptr_t uvalue = make_bpfptr(attr->value, uattr.is_kernel);
1615db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1616db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
1617db20fd2bSAlexei Starovoitov 	void *key, *value;
161815a07b33SAlexei Starovoitov 	u32 value_size;
1619592867bfSDaniel Borkmann 	struct fd f;
1620db20fd2bSAlexei Starovoitov 	int err;
1621db20fd2bSAlexei Starovoitov 
1622db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM))
1623db20fd2bSAlexei Starovoitov 		return -EINVAL;
1624db20fd2bSAlexei Starovoitov 
1625592867bfSDaniel Borkmann 	f = fdget(ufd);
1626c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1627db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1628db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
1629353050beSDaniel Borkmann 	bpf_map_write_active_inc(map);
163087df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
16316e71b04aSChenbo Feng 		err = -EPERM;
16326e71b04aSChenbo Feng 		goto err_put;
16336e71b04aSChenbo Feng 	}
16346e71b04aSChenbo Feng 
163596049f3aSAlexei Starovoitov 	if ((attr->flags & BPF_F_LOCK) &&
1636db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
163796049f3aSAlexei Starovoitov 		err = -EINVAL;
163896049f3aSAlexei Starovoitov 		goto err_put;
163996049f3aSAlexei Starovoitov 	}
164096049f3aSAlexei Starovoitov 
1641af2ac3e1SAlexei Starovoitov 	key = ___bpf_copy_key(ukey, map->key_size);
1642e4448ed8SAl Viro 	if (IS_ERR(key)) {
1643e4448ed8SAl Viro 		err = PTR_ERR(key);
1644db20fd2bSAlexei Starovoitov 		goto err_put;
1645e4448ed8SAl Viro 	}
1646db20fd2bSAlexei Starovoitov 
1647f0dce1d9SStanislav Fomichev 	value_size = bpf_map_value_size(map);
1648a02c118eSWang Yufen 	value = kvmemdup_bpfptr(uvalue, value_size);
1649a02c118eSWang Yufen 	if (IS_ERR(value)) {
1650a02c118eSWang Yufen 		err = PTR_ERR(value);
1651db20fd2bSAlexei Starovoitov 		goto free_key;
1652a02c118eSWang Yufen 	}
1653db20fd2bSAlexei Starovoitov 
16543af43ba4SHou Tao 	err = bpf_map_update_value(map, f.file, key, value, attr->flags);
165567ad2c73SHou Tao 	if (!err)
165637ba5b59SHou Tao 		maybe_wait_bpf_programs(map);
16576710e112SJesper Dangaard Brouer 
1658f0dce1d9SStanislav Fomichev 	kvfree(value);
1659db20fd2bSAlexei Starovoitov free_key:
166044779a4bSStanislav Fomichev 	kvfree(key);
1661db20fd2bSAlexei Starovoitov err_put:
1662353050beSDaniel Borkmann 	bpf_map_write_active_dec(map);
1663db20fd2bSAlexei Starovoitov 	fdput(f);
1664db20fd2bSAlexei Starovoitov 	return err;
1665db20fd2bSAlexei Starovoitov }
1666db20fd2bSAlexei Starovoitov 
1667db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key
1668db20fd2bSAlexei Starovoitov 
1669b88df697SBenjamin Tissoires static int map_delete_elem(union bpf_attr *attr, bpfptr_t uattr)
1670db20fd2bSAlexei Starovoitov {
1671b88df697SBenjamin Tissoires 	bpfptr_t ukey = make_bpfptr(attr->key, uattr.is_kernel);
1672db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1673db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
1674592867bfSDaniel Borkmann 	struct fd f;
1675db20fd2bSAlexei Starovoitov 	void *key;
1676db20fd2bSAlexei Starovoitov 	int err;
1677db20fd2bSAlexei Starovoitov 
1678db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_DELETE_ELEM))
1679db20fd2bSAlexei Starovoitov 		return -EINVAL;
1680db20fd2bSAlexei Starovoitov 
1681592867bfSDaniel Borkmann 	f = fdget(ufd);
1682c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1683db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1684db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
1685353050beSDaniel Borkmann 	bpf_map_write_active_inc(map);
168687df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
16876e71b04aSChenbo Feng 		err = -EPERM;
16886e71b04aSChenbo Feng 		goto err_put;
16896e71b04aSChenbo Feng 	}
16906e71b04aSChenbo Feng 
1691b88df697SBenjamin Tissoires 	key = ___bpf_copy_key(ukey, map->key_size);
1692e4448ed8SAl Viro 	if (IS_ERR(key)) {
1693e4448ed8SAl Viro 		err = PTR_ERR(key);
1694db20fd2bSAlexei Starovoitov 		goto err_put;
1695e4448ed8SAl Viro 	}
1696db20fd2bSAlexei Starovoitov 
16979d03ebc7SStanislav Fomichev 	if (bpf_map_is_offloaded(map)) {
1698a3884572SJakub Kicinski 		err = bpf_map_offload_delete_elem(map, key);
1699a3884572SJakub Kicinski 		goto out;
170085d33df3SMartin KaFai Lau 	} else if (IS_FD_PROG_ARRAY(map) ||
170185d33df3SMartin KaFai Lau 		   map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
170285d33df3SMartin KaFai Lau 		/* These maps require sleepable context */
1703da765a2fSDaniel Borkmann 		err = map->ops->map_delete_elem(map, key);
1704da765a2fSDaniel Borkmann 		goto out;
1705a3884572SJakub Kicinski 	}
1706a3884572SJakub Kicinski 
1707b6e5dae1SThomas Gleixner 	bpf_disable_instrumentation();
1708db20fd2bSAlexei Starovoitov 	rcu_read_lock();
1709db20fd2bSAlexei Starovoitov 	err = map->ops->map_delete_elem(map, key);
1710db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
1711b6e5dae1SThomas Gleixner 	bpf_enable_instrumentation();
171267ad2c73SHou Tao 	if (!err)
17131ae80cf3SDaniel Colascione 		maybe_wait_bpf_programs(map);
1714a3884572SJakub Kicinski out:
171544779a4bSStanislav Fomichev 	kvfree(key);
1716db20fd2bSAlexei Starovoitov err_put:
1717353050beSDaniel Borkmann 	bpf_map_write_active_dec(map);
1718db20fd2bSAlexei Starovoitov 	fdput(f);
1719db20fd2bSAlexei Starovoitov 	return err;
1720db20fd2bSAlexei Starovoitov }
1721db20fd2bSAlexei Starovoitov 
1722db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
1723db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key
1724db20fd2bSAlexei Starovoitov 
1725db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr)
1726db20fd2bSAlexei Starovoitov {
1727535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
1728535e7b4bSMickaël Salaün 	void __user *unext_key = u64_to_user_ptr(attr->next_key);
1729db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1730db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
1731db20fd2bSAlexei Starovoitov 	void *key, *next_key;
1732592867bfSDaniel Borkmann 	struct fd f;
1733db20fd2bSAlexei Starovoitov 	int err;
1734db20fd2bSAlexei Starovoitov 
1735db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY))
1736db20fd2bSAlexei Starovoitov 		return -EINVAL;
1737db20fd2bSAlexei Starovoitov 
1738592867bfSDaniel Borkmann 	f = fdget(ufd);
1739c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1740db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1741db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
174287df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
17436e71b04aSChenbo Feng 		err = -EPERM;
17446e71b04aSChenbo Feng 		goto err_put;
17456e71b04aSChenbo Feng 	}
17466e71b04aSChenbo Feng 
17478fe45924STeng Qin 	if (ukey) {
1748c9d29f46SMauricio Vasquez B 		key = __bpf_copy_key(ukey, map->key_size);
1749e4448ed8SAl Viro 		if (IS_ERR(key)) {
1750e4448ed8SAl Viro 			err = PTR_ERR(key);
1751db20fd2bSAlexei Starovoitov 			goto err_put;
1752e4448ed8SAl Viro 		}
17538fe45924STeng Qin 	} else {
17548fe45924STeng Qin 		key = NULL;
17558fe45924STeng Qin 	}
1756db20fd2bSAlexei Starovoitov 
1757db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
175844779a4bSStanislav Fomichev 	next_key = kvmalloc(map->key_size, GFP_USER);
1759db20fd2bSAlexei Starovoitov 	if (!next_key)
1760db20fd2bSAlexei Starovoitov 		goto free_key;
1761db20fd2bSAlexei Starovoitov 
17629d03ebc7SStanislav Fomichev 	if (bpf_map_is_offloaded(map)) {
1763a3884572SJakub Kicinski 		err = bpf_map_offload_get_next_key(map, key, next_key);
1764a3884572SJakub Kicinski 		goto out;
1765a3884572SJakub Kicinski 	}
1766a3884572SJakub Kicinski 
1767db20fd2bSAlexei Starovoitov 	rcu_read_lock();
1768db20fd2bSAlexei Starovoitov 	err = map->ops->map_get_next_key(map, key, next_key);
1769db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
1770a3884572SJakub Kicinski out:
1771db20fd2bSAlexei Starovoitov 	if (err)
1772db20fd2bSAlexei Starovoitov 		goto free_next_key;
1773db20fd2bSAlexei Starovoitov 
1774db20fd2bSAlexei Starovoitov 	err = -EFAULT;
1775db20fd2bSAlexei Starovoitov 	if (copy_to_user(unext_key, next_key, map->key_size) != 0)
1776db20fd2bSAlexei Starovoitov 		goto free_next_key;
1777db20fd2bSAlexei Starovoitov 
1778db20fd2bSAlexei Starovoitov 	err = 0;
1779db20fd2bSAlexei Starovoitov 
1780db20fd2bSAlexei Starovoitov free_next_key:
178144779a4bSStanislav Fomichev 	kvfree(next_key);
1782db20fd2bSAlexei Starovoitov free_key:
178344779a4bSStanislav Fomichev 	kvfree(key);
1784db20fd2bSAlexei Starovoitov err_put:
1785db20fd2bSAlexei Starovoitov 	fdput(f);
1786db20fd2bSAlexei Starovoitov 	return err;
1787db20fd2bSAlexei Starovoitov }
1788db20fd2bSAlexei Starovoitov 
1789aa2e93b8SBrian Vazquez int generic_map_delete_batch(struct bpf_map *map,
1790aa2e93b8SBrian Vazquez 			     const union bpf_attr *attr,
1791aa2e93b8SBrian Vazquez 			     union bpf_attr __user *uattr)
1792aa2e93b8SBrian Vazquez {
1793aa2e93b8SBrian Vazquez 	void __user *keys = u64_to_user_ptr(attr->batch.keys);
1794aa2e93b8SBrian Vazquez 	u32 cp, max_count;
1795aa2e93b8SBrian Vazquez 	int err = 0;
1796aa2e93b8SBrian Vazquez 	void *key;
1797aa2e93b8SBrian Vazquez 
1798aa2e93b8SBrian Vazquez 	if (attr->batch.elem_flags & ~BPF_F_LOCK)
1799aa2e93b8SBrian Vazquez 		return -EINVAL;
1800aa2e93b8SBrian Vazquez 
1801aa2e93b8SBrian Vazquez 	if ((attr->batch.elem_flags & BPF_F_LOCK) &&
1802db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
1803aa2e93b8SBrian Vazquez 		return -EINVAL;
1804aa2e93b8SBrian Vazquez 	}
1805aa2e93b8SBrian Vazquez 
1806aa2e93b8SBrian Vazquez 	max_count = attr->batch.count;
1807aa2e93b8SBrian Vazquez 	if (!max_count)
1808aa2e93b8SBrian Vazquez 		return 0;
1809aa2e93b8SBrian Vazquez 
181006e5c999SHou Tao 	if (put_user(0, &uattr->batch.count))
181106e5c999SHou Tao 		return -EFAULT;
181206e5c999SHou Tao 
181344779a4bSStanislav Fomichev 	key = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN);
18142e3a94aaSBrian Vazquez 	if (!key)
18152e3a94aaSBrian Vazquez 		return -ENOMEM;
18162e3a94aaSBrian Vazquez 
1817aa2e93b8SBrian Vazquez 	for (cp = 0; cp < max_count; cp++) {
18182e3a94aaSBrian Vazquez 		err = -EFAULT;
18192e3a94aaSBrian Vazquez 		if (copy_from_user(key, keys + cp * map->key_size,
18202e3a94aaSBrian Vazquez 				   map->key_size))
1821aa2e93b8SBrian Vazquez 			break;
1822aa2e93b8SBrian Vazquez 
18239d03ebc7SStanislav Fomichev 		if (bpf_map_is_offloaded(map)) {
1824aa2e93b8SBrian Vazquez 			err = bpf_map_offload_delete_elem(map, key);
1825aa2e93b8SBrian Vazquez 			break;
1826aa2e93b8SBrian Vazquez 		}
1827aa2e93b8SBrian Vazquez 
1828b6e5dae1SThomas Gleixner 		bpf_disable_instrumentation();
1829aa2e93b8SBrian Vazquez 		rcu_read_lock();
1830aa2e93b8SBrian Vazquez 		err = map->ops->map_delete_elem(map, key);
1831aa2e93b8SBrian Vazquez 		rcu_read_unlock();
1832b6e5dae1SThomas Gleixner 		bpf_enable_instrumentation();
1833aa2e93b8SBrian Vazquez 		if (err)
1834aa2e93b8SBrian Vazquez 			break;
183575134f16SEric Dumazet 		cond_resched();
1836aa2e93b8SBrian Vazquez 	}
1837aa2e93b8SBrian Vazquez 	if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp)))
1838aa2e93b8SBrian Vazquez 		err = -EFAULT;
18392e3a94aaSBrian Vazquez 
184044779a4bSStanislav Fomichev 	kvfree(key);
18419087c6ffSEric Dumazet 
1842aa2e93b8SBrian Vazquez 	return err;
1843aa2e93b8SBrian Vazquez }
1844aa2e93b8SBrian Vazquez 
18453af43ba4SHou Tao int generic_map_update_batch(struct bpf_map *map, struct file *map_file,
1846aa2e93b8SBrian Vazquez 			     const union bpf_attr *attr,
1847aa2e93b8SBrian Vazquez 			     union bpf_attr __user *uattr)
1848aa2e93b8SBrian Vazquez {
1849aa2e93b8SBrian Vazquez 	void __user *values = u64_to_user_ptr(attr->batch.values);
1850aa2e93b8SBrian Vazquez 	void __user *keys = u64_to_user_ptr(attr->batch.keys);
1851aa2e93b8SBrian Vazquez 	u32 value_size, cp, max_count;
1852aa2e93b8SBrian Vazquez 	void *key, *value;
1853aa2e93b8SBrian Vazquez 	int err = 0;
1854aa2e93b8SBrian Vazquez 
1855aa2e93b8SBrian Vazquez 	if (attr->batch.elem_flags & ~BPF_F_LOCK)
1856aa2e93b8SBrian Vazquez 		return -EINVAL;
1857aa2e93b8SBrian Vazquez 
1858aa2e93b8SBrian Vazquez 	if ((attr->batch.elem_flags & BPF_F_LOCK) &&
1859db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
1860aa2e93b8SBrian Vazquez 		return -EINVAL;
1861aa2e93b8SBrian Vazquez 	}
1862aa2e93b8SBrian Vazquez 
1863aa2e93b8SBrian Vazquez 	value_size = bpf_map_value_size(map);
1864aa2e93b8SBrian Vazquez 
1865aa2e93b8SBrian Vazquez 	max_count = attr->batch.count;
1866aa2e93b8SBrian Vazquez 	if (!max_count)
1867aa2e93b8SBrian Vazquez 		return 0;
1868aa2e93b8SBrian Vazquez 
186906e5c999SHou Tao 	if (put_user(0, &uattr->batch.count))
187006e5c999SHou Tao 		return -EFAULT;
187106e5c999SHou Tao 
187244779a4bSStanislav Fomichev 	key = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN);
18732e3a94aaSBrian Vazquez 	if (!key)
1874aa2e93b8SBrian Vazquez 		return -ENOMEM;
1875aa2e93b8SBrian Vazquez 
1876f0dce1d9SStanislav Fomichev 	value = kvmalloc(value_size, GFP_USER | __GFP_NOWARN);
18772e3a94aaSBrian Vazquez 	if (!value) {
187844779a4bSStanislav Fomichev 		kvfree(key);
18792e3a94aaSBrian Vazquez 		return -ENOMEM;
1880aa2e93b8SBrian Vazquez 	}
18812e3a94aaSBrian Vazquez 
18822e3a94aaSBrian Vazquez 	for (cp = 0; cp < max_count; cp++) {
1883aa2e93b8SBrian Vazquez 		err = -EFAULT;
18842e3a94aaSBrian Vazquez 		if (copy_from_user(key, keys + cp * map->key_size,
18852e3a94aaSBrian Vazquez 		    map->key_size) ||
18862e3a94aaSBrian Vazquez 		    copy_from_user(value, values + cp * value_size, value_size))
1887aa2e93b8SBrian Vazquez 			break;
1888aa2e93b8SBrian Vazquez 
18893af43ba4SHou Tao 		err = bpf_map_update_value(map, map_file, key, value,
1890aa2e93b8SBrian Vazquez 					   attr->batch.elem_flags);
1891aa2e93b8SBrian Vazquez 
1892aa2e93b8SBrian Vazquez 		if (err)
1893aa2e93b8SBrian Vazquez 			break;
189475134f16SEric Dumazet 		cond_resched();
1895aa2e93b8SBrian Vazquez 	}
1896aa2e93b8SBrian Vazquez 
1897aa2e93b8SBrian Vazquez 	if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp)))
1898aa2e93b8SBrian Vazquez 		err = -EFAULT;
1899aa2e93b8SBrian Vazquez 
1900f0dce1d9SStanislav Fomichev 	kvfree(value);
190144779a4bSStanislav Fomichev 	kvfree(key);
190237ba5b59SHou Tao 
1903aa2e93b8SBrian Vazquez 	return err;
1904aa2e93b8SBrian Vazquez }
1905aa2e93b8SBrian Vazquez 
1906cb4d03abSBrian Vazquez #define MAP_LOOKUP_RETRIES 3
1907cb4d03abSBrian Vazquez 
1908cb4d03abSBrian Vazquez int generic_map_lookup_batch(struct bpf_map *map,
1909cb4d03abSBrian Vazquez 				    const union bpf_attr *attr,
1910cb4d03abSBrian Vazquez 				    union bpf_attr __user *uattr)
1911cb4d03abSBrian Vazquez {
1912cb4d03abSBrian Vazquez 	void __user *uobatch = u64_to_user_ptr(attr->batch.out_batch);
1913cb4d03abSBrian Vazquez 	void __user *ubatch = u64_to_user_ptr(attr->batch.in_batch);
1914cb4d03abSBrian Vazquez 	void __user *values = u64_to_user_ptr(attr->batch.values);
1915cb4d03abSBrian Vazquez 	void __user *keys = u64_to_user_ptr(attr->batch.keys);
1916cb4d03abSBrian Vazquez 	void *buf, *buf_prevkey, *prev_key, *key, *value;
1917cb4d03abSBrian Vazquez 	int err, retry = MAP_LOOKUP_RETRIES;
1918cb4d03abSBrian Vazquez 	u32 value_size, cp, max_count;
1919cb4d03abSBrian Vazquez 
1920cb4d03abSBrian Vazquez 	if (attr->batch.elem_flags & ~BPF_F_LOCK)
1921cb4d03abSBrian Vazquez 		return -EINVAL;
1922cb4d03abSBrian Vazquez 
1923cb4d03abSBrian Vazquez 	if ((attr->batch.elem_flags & BPF_F_LOCK) &&
1924db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK))
1925cb4d03abSBrian Vazquez 		return -EINVAL;
1926cb4d03abSBrian Vazquez 
1927cb4d03abSBrian Vazquez 	value_size = bpf_map_value_size(map);
1928cb4d03abSBrian Vazquez 
1929cb4d03abSBrian Vazquez 	max_count = attr->batch.count;
1930cb4d03abSBrian Vazquez 	if (!max_count)
1931cb4d03abSBrian Vazquez 		return 0;
1932cb4d03abSBrian Vazquez 
1933cb4d03abSBrian Vazquez 	if (put_user(0, &uattr->batch.count))
1934cb4d03abSBrian Vazquez 		return -EFAULT;
1935cb4d03abSBrian Vazquez 
193644779a4bSStanislav Fomichev 	buf_prevkey = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN);
1937cb4d03abSBrian Vazquez 	if (!buf_prevkey)
1938cb4d03abSBrian Vazquez 		return -ENOMEM;
1939cb4d03abSBrian Vazquez 
1940f0dce1d9SStanislav Fomichev 	buf = kvmalloc(map->key_size + value_size, GFP_USER | __GFP_NOWARN);
1941cb4d03abSBrian Vazquez 	if (!buf) {
194244779a4bSStanislav Fomichev 		kvfree(buf_prevkey);
1943cb4d03abSBrian Vazquez 		return -ENOMEM;
1944cb4d03abSBrian Vazquez 	}
1945cb4d03abSBrian Vazquez 
1946cb4d03abSBrian Vazquez 	err = -EFAULT;
1947cb4d03abSBrian Vazquez 	prev_key = NULL;
1948cb4d03abSBrian Vazquez 	if (ubatch && copy_from_user(buf_prevkey, ubatch, map->key_size))
1949cb4d03abSBrian Vazquez 		goto free_buf;
1950cb4d03abSBrian Vazquez 	key = buf;
1951cb4d03abSBrian Vazquez 	value = key + map->key_size;
1952cb4d03abSBrian Vazquez 	if (ubatch)
1953cb4d03abSBrian Vazquez 		prev_key = buf_prevkey;
1954cb4d03abSBrian Vazquez 
1955cb4d03abSBrian Vazquez 	for (cp = 0; cp < max_count;) {
1956cb4d03abSBrian Vazquez 		rcu_read_lock();
1957cb4d03abSBrian Vazquez 		err = map->ops->map_get_next_key(map, prev_key, key);
1958cb4d03abSBrian Vazquez 		rcu_read_unlock();
1959cb4d03abSBrian Vazquez 		if (err)
1960cb4d03abSBrian Vazquez 			break;
1961cb4d03abSBrian Vazquez 		err = bpf_map_copy_value(map, key, value,
1962cb4d03abSBrian Vazquez 					 attr->batch.elem_flags);
1963cb4d03abSBrian Vazquez 
1964cb4d03abSBrian Vazquez 		if (err == -ENOENT) {
1965cb4d03abSBrian Vazquez 			if (retry) {
1966cb4d03abSBrian Vazquez 				retry--;
1967cb4d03abSBrian Vazquez 				continue;
1968cb4d03abSBrian Vazquez 			}
1969cb4d03abSBrian Vazquez 			err = -EINTR;
1970cb4d03abSBrian Vazquez 			break;
1971cb4d03abSBrian Vazquez 		}
1972cb4d03abSBrian Vazquez 
1973cb4d03abSBrian Vazquez 		if (err)
1974cb4d03abSBrian Vazquez 			goto free_buf;
1975cb4d03abSBrian Vazquez 
1976cb4d03abSBrian Vazquez 		if (copy_to_user(keys + cp * map->key_size, key,
1977cb4d03abSBrian Vazquez 				 map->key_size)) {
1978cb4d03abSBrian Vazquez 			err = -EFAULT;
1979cb4d03abSBrian Vazquez 			goto free_buf;
1980cb4d03abSBrian Vazquez 		}
1981cb4d03abSBrian Vazquez 		if (copy_to_user(values + cp * value_size, value, value_size)) {
1982cb4d03abSBrian Vazquez 			err = -EFAULT;
1983cb4d03abSBrian Vazquez 			goto free_buf;
1984cb4d03abSBrian Vazquez 		}
1985cb4d03abSBrian Vazquez 
1986cb4d03abSBrian Vazquez 		if (!prev_key)
1987cb4d03abSBrian Vazquez 			prev_key = buf_prevkey;
1988cb4d03abSBrian Vazquez 
1989cb4d03abSBrian Vazquez 		swap(prev_key, key);
1990cb4d03abSBrian Vazquez 		retry = MAP_LOOKUP_RETRIES;
1991cb4d03abSBrian Vazquez 		cp++;
199275134f16SEric Dumazet 		cond_resched();
1993cb4d03abSBrian Vazquez 	}
1994cb4d03abSBrian Vazquez 
1995cb4d03abSBrian Vazquez 	if (err == -EFAULT)
1996cb4d03abSBrian Vazquez 		goto free_buf;
1997cb4d03abSBrian Vazquez 
1998cb4d03abSBrian Vazquez 	if ((copy_to_user(&uattr->batch.count, &cp, sizeof(cp)) ||
1999cb4d03abSBrian Vazquez 		    (cp && copy_to_user(uobatch, prev_key, map->key_size))))
2000cb4d03abSBrian Vazquez 		err = -EFAULT;
2001cb4d03abSBrian Vazquez 
2002cb4d03abSBrian Vazquez free_buf:
200344779a4bSStanislav Fomichev 	kvfree(buf_prevkey);
2004f0dce1d9SStanislav Fomichev 	kvfree(buf);
2005cb4d03abSBrian Vazquez 	return err;
2006cb4d03abSBrian Vazquez }
2007cb4d03abSBrian Vazquez 
20083e87f192SDenis Salopek #define BPF_MAP_LOOKUP_AND_DELETE_ELEM_LAST_FIELD flags
2009bd513cd0SMauricio Vasquez B 
2010bd513cd0SMauricio Vasquez B static int map_lookup_and_delete_elem(union bpf_attr *attr)
2011bd513cd0SMauricio Vasquez B {
2012bd513cd0SMauricio Vasquez B 	void __user *ukey = u64_to_user_ptr(attr->key);
2013bd513cd0SMauricio Vasquez B 	void __user *uvalue = u64_to_user_ptr(attr->value);
2014bd513cd0SMauricio Vasquez B 	int ufd = attr->map_fd;
2015bd513cd0SMauricio Vasquez B 	struct bpf_map *map;
2016540fefc0SAlexei Starovoitov 	void *key, *value;
2017bd513cd0SMauricio Vasquez B 	u32 value_size;
2018bd513cd0SMauricio Vasquez B 	struct fd f;
2019bd513cd0SMauricio Vasquez B 	int err;
2020bd513cd0SMauricio Vasquez B 
2021bd513cd0SMauricio Vasquez B 	if (CHECK_ATTR(BPF_MAP_LOOKUP_AND_DELETE_ELEM))
2022bd513cd0SMauricio Vasquez B 		return -EINVAL;
2023bd513cd0SMauricio Vasquez B 
20243e87f192SDenis Salopek 	if (attr->flags & ~BPF_F_LOCK)
20253e87f192SDenis Salopek 		return -EINVAL;
20263e87f192SDenis Salopek 
2027bd513cd0SMauricio Vasquez B 	f = fdget(ufd);
2028bd513cd0SMauricio Vasquez B 	map = __bpf_map_get(f);
2029bd513cd0SMauricio Vasquez B 	if (IS_ERR(map))
2030bd513cd0SMauricio Vasquez B 		return PTR_ERR(map);
2031353050beSDaniel Borkmann 	bpf_map_write_active_inc(map);
20321ea0f912SAnton Protopopov 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ) ||
20331ea0f912SAnton Protopopov 	    !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
2034bd513cd0SMauricio Vasquez B 		err = -EPERM;
2035bd513cd0SMauricio Vasquez B 		goto err_put;
2036bd513cd0SMauricio Vasquez B 	}
2037bd513cd0SMauricio Vasquez B 
20383e87f192SDenis Salopek 	if (attr->flags &&
20393e87f192SDenis Salopek 	    (map->map_type == BPF_MAP_TYPE_QUEUE ||
20403e87f192SDenis Salopek 	     map->map_type == BPF_MAP_TYPE_STACK)) {
20413e87f192SDenis Salopek 		err = -EINVAL;
20423e87f192SDenis Salopek 		goto err_put;
20433e87f192SDenis Salopek 	}
20443e87f192SDenis Salopek 
20453e87f192SDenis Salopek 	if ((attr->flags & BPF_F_LOCK) &&
2046db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
20473e87f192SDenis Salopek 		err = -EINVAL;
20483e87f192SDenis Salopek 		goto err_put;
20493e87f192SDenis Salopek 	}
20503e87f192SDenis Salopek 
2051bd513cd0SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
2052bd513cd0SMauricio Vasquez B 	if (IS_ERR(key)) {
2053bd513cd0SMauricio Vasquez B 		err = PTR_ERR(key);
2054bd513cd0SMauricio Vasquez B 		goto err_put;
2055bd513cd0SMauricio Vasquez B 	}
2056bd513cd0SMauricio Vasquez B 
20573e87f192SDenis Salopek 	value_size = bpf_map_value_size(map);
2058bd513cd0SMauricio Vasquez B 
2059bd513cd0SMauricio Vasquez B 	err = -ENOMEM;
2060f0dce1d9SStanislav Fomichev 	value = kvmalloc(value_size, GFP_USER | __GFP_NOWARN);
2061bd513cd0SMauricio Vasquez B 	if (!value)
2062bd513cd0SMauricio Vasquez B 		goto free_key;
2063bd513cd0SMauricio Vasquez B 
20643e87f192SDenis Salopek 	err = -ENOTSUPP;
2065bd513cd0SMauricio Vasquez B 	if (map->map_type == BPF_MAP_TYPE_QUEUE ||
2066bd513cd0SMauricio Vasquez B 	    map->map_type == BPF_MAP_TYPE_STACK) {
2067bd513cd0SMauricio Vasquez B 		err = map->ops->map_pop_elem(map, value);
20683e87f192SDenis Salopek 	} else if (map->map_type == BPF_MAP_TYPE_HASH ||
20693e87f192SDenis Salopek 		   map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
20703e87f192SDenis Salopek 		   map->map_type == BPF_MAP_TYPE_LRU_HASH ||
20713e87f192SDenis Salopek 		   map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
20729d03ebc7SStanislav Fomichev 		if (!bpf_map_is_offloaded(map)) {
20733e87f192SDenis Salopek 			bpf_disable_instrumentation();
20743e87f192SDenis Salopek 			rcu_read_lock();
20753e87f192SDenis Salopek 			err = map->ops->map_lookup_and_delete_elem(map, key, value, attr->flags);
20763e87f192SDenis Salopek 			rcu_read_unlock();
20773e87f192SDenis Salopek 			bpf_enable_instrumentation();
20783e87f192SDenis Salopek 		}
2079bd513cd0SMauricio Vasquez B 	}
2080bd513cd0SMauricio Vasquez B 
2081bd513cd0SMauricio Vasquez B 	if (err)
2082bd513cd0SMauricio Vasquez B 		goto free_value;
2083bd513cd0SMauricio Vasquez B 
20847f645462SWei Yongjun 	if (copy_to_user(uvalue, value, value_size) != 0) {
20857f645462SWei Yongjun 		err = -EFAULT;
2086bd513cd0SMauricio Vasquez B 		goto free_value;
20877f645462SWei Yongjun 	}
2088bd513cd0SMauricio Vasquez B 
2089bd513cd0SMauricio Vasquez B 	err = 0;
2090bd513cd0SMauricio Vasquez B 
2091bd513cd0SMauricio Vasquez B free_value:
2092f0dce1d9SStanislav Fomichev 	kvfree(value);
2093bd513cd0SMauricio Vasquez B free_key:
209444779a4bSStanislav Fomichev 	kvfree(key);
2095bd513cd0SMauricio Vasquez B err_put:
2096353050beSDaniel Borkmann 	bpf_map_write_active_dec(map);
2097bd513cd0SMauricio Vasquez B 	fdput(f);
2098bd513cd0SMauricio Vasquez B 	return err;
2099bd513cd0SMauricio Vasquez B }
2100bd513cd0SMauricio Vasquez B 
210187df15deSDaniel Borkmann #define BPF_MAP_FREEZE_LAST_FIELD map_fd
210287df15deSDaniel Borkmann 
210387df15deSDaniel Borkmann static int map_freeze(const union bpf_attr *attr)
210487df15deSDaniel Borkmann {
210587df15deSDaniel Borkmann 	int err = 0, ufd = attr->map_fd;
210687df15deSDaniel Borkmann 	struct bpf_map *map;
210787df15deSDaniel Borkmann 	struct fd f;
210887df15deSDaniel Borkmann 
210987df15deSDaniel Borkmann 	if (CHECK_ATTR(BPF_MAP_FREEZE))
211087df15deSDaniel Borkmann 		return -EINVAL;
211187df15deSDaniel Borkmann 
211287df15deSDaniel Borkmann 	f = fdget(ufd);
211387df15deSDaniel Borkmann 	map = __bpf_map_get(f);
211487df15deSDaniel Borkmann 	if (IS_ERR(map))
211587df15deSDaniel Borkmann 		return PTR_ERR(map);
2116fc970227SAndrii Nakryiko 
2117db559117SKumar Kartikeya Dwivedi 	if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS || !IS_ERR_OR_NULL(map->record)) {
2118849b4d94SMartin KaFai Lau 		fdput(f);
2119849b4d94SMartin KaFai Lau 		return -ENOTSUPP;
2120849b4d94SMartin KaFai Lau 	}
2121849b4d94SMartin KaFai Lau 
2122c4c84f6fSAndrii Nakryiko 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
21234266f41fSDaniel Borkmann 		fdput(f);
21244266f41fSDaniel Borkmann 		return -EPERM;
2125c4c84f6fSAndrii Nakryiko 	}
2126c4c84f6fSAndrii Nakryiko 
2127fc970227SAndrii Nakryiko 	mutex_lock(&map->freeze_mutex);
2128353050beSDaniel Borkmann 	if (bpf_map_write_active(map)) {
2129fc970227SAndrii Nakryiko 		err = -EBUSY;
2130fc970227SAndrii Nakryiko 		goto err_put;
2131fc970227SAndrii Nakryiko 	}
213287df15deSDaniel Borkmann 	if (READ_ONCE(map->frozen)) {
213387df15deSDaniel Borkmann 		err = -EBUSY;
213487df15deSDaniel Borkmann 		goto err_put;
213587df15deSDaniel Borkmann 	}
213687df15deSDaniel Borkmann 
213787df15deSDaniel Borkmann 	WRITE_ONCE(map->frozen, true);
213887df15deSDaniel Borkmann err_put:
2139fc970227SAndrii Nakryiko 	mutex_unlock(&map->freeze_mutex);
214087df15deSDaniel Borkmann 	fdput(f);
214187df15deSDaniel Borkmann 	return err;
214287df15deSDaniel Borkmann }
214387df15deSDaniel Borkmann 
21447de16e3aSJakub Kicinski static const struct bpf_prog_ops * const bpf_prog_types[] = {
214591cc1a99SAlexei Starovoitov #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \
21467de16e3aSJakub Kicinski 	[_id] = & _name ## _prog_ops,
21477de16e3aSJakub Kicinski #define BPF_MAP_TYPE(_id, _ops)
2148f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name)
21497de16e3aSJakub Kicinski #include <linux/bpf_types.h>
21507de16e3aSJakub Kicinski #undef BPF_PROG_TYPE
21517de16e3aSJakub Kicinski #undef BPF_MAP_TYPE
2152f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE
21537de16e3aSJakub Kicinski };
21547de16e3aSJakub Kicinski 
215509756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
215609756af4SAlexei Starovoitov {
2157d0f1a451SDaniel Borkmann 	const struct bpf_prog_ops *ops;
2158d0f1a451SDaniel Borkmann 
2159d0f1a451SDaniel Borkmann 	if (type >= ARRAY_SIZE(bpf_prog_types))
2160d0f1a451SDaniel Borkmann 		return -EINVAL;
2161d0f1a451SDaniel Borkmann 	type = array_index_nospec(type, ARRAY_SIZE(bpf_prog_types));
2162d0f1a451SDaniel Borkmann 	ops = bpf_prog_types[type];
2163d0f1a451SDaniel Borkmann 	if (!ops)
2164be9370a7SJohannes Berg 		return -EINVAL;
216509756af4SAlexei Starovoitov 
21669d03ebc7SStanislav Fomichev 	if (!bpf_prog_is_offloaded(prog->aux))
2167d0f1a451SDaniel Borkmann 		prog->aux->ops = ops;
2168ab3f0063SJakub Kicinski 	else
2169ab3f0063SJakub Kicinski 		prog->aux->ops = &bpf_offload_prog_ops;
217024701eceSDaniel Borkmann 	prog->type = type;
217109756af4SAlexei Starovoitov 	return 0;
217209756af4SAlexei Starovoitov }
217309756af4SAlexei Starovoitov 
2174bae141f5SDaniel Borkmann enum bpf_audit {
2175bae141f5SDaniel Borkmann 	BPF_AUDIT_LOAD,
2176bae141f5SDaniel Borkmann 	BPF_AUDIT_UNLOAD,
2177bae141f5SDaniel Borkmann 	BPF_AUDIT_MAX,
2178bae141f5SDaniel Borkmann };
2179bae141f5SDaniel Borkmann 
2180bae141f5SDaniel Borkmann static const char * const bpf_audit_str[BPF_AUDIT_MAX] = {
2181bae141f5SDaniel Borkmann 	[BPF_AUDIT_LOAD]   = "LOAD",
2182bae141f5SDaniel Borkmann 	[BPF_AUDIT_UNLOAD] = "UNLOAD",
2183bae141f5SDaniel Borkmann };
2184bae141f5SDaniel Borkmann 
2185bae141f5SDaniel Borkmann static void bpf_audit_prog(const struct bpf_prog *prog, unsigned int op)
2186bae141f5SDaniel Borkmann {
2187bae141f5SDaniel Borkmann 	struct audit_context *ctx = NULL;
2188bae141f5SDaniel Borkmann 	struct audit_buffer *ab;
2189bae141f5SDaniel Borkmann 
2190bae141f5SDaniel Borkmann 	if (WARN_ON_ONCE(op >= BPF_AUDIT_MAX))
2191bae141f5SDaniel Borkmann 		return;
2192bae141f5SDaniel Borkmann 	if (audit_enabled == AUDIT_OFF)
2193bae141f5SDaniel Borkmann 		return;
2194ef01f4e2SPaul Moore 	if (!in_irq() && !irqs_disabled())
2195bae141f5SDaniel Borkmann 		ctx = audit_context();
2196bae141f5SDaniel Borkmann 	ab = audit_log_start(ctx, GFP_ATOMIC, AUDIT_BPF);
2197bae141f5SDaniel Borkmann 	if (unlikely(!ab))
2198bae141f5SDaniel Borkmann 		return;
2199bae141f5SDaniel Borkmann 	audit_log_format(ab, "prog-id=%u op=%s",
2200bae141f5SDaniel Borkmann 			 prog->aux->id, bpf_audit_str[op]);
2201bae141f5SDaniel Borkmann 	audit_log_end(ab);
2202bae141f5SDaniel Borkmann }
2203bae141f5SDaniel Borkmann 
2204dc4bb0e2SMartin KaFai Lau static int bpf_prog_alloc_id(struct bpf_prog *prog)
2205dc4bb0e2SMartin KaFai Lau {
2206dc4bb0e2SMartin KaFai Lau 	int id;
2207dc4bb0e2SMartin KaFai Lau 
2208b76354cdSShaohua Li 	idr_preload(GFP_KERNEL);
2209dc4bb0e2SMartin KaFai Lau 	spin_lock_bh(&prog_idr_lock);
2210dc4bb0e2SMartin KaFai Lau 	id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC);
2211dc4bb0e2SMartin KaFai Lau 	if (id > 0)
2212dc4bb0e2SMartin KaFai Lau 		prog->aux->id = id;
2213dc4bb0e2SMartin KaFai Lau 	spin_unlock_bh(&prog_idr_lock);
2214b76354cdSShaohua Li 	idr_preload_end();
2215dc4bb0e2SMartin KaFai Lau 
2216dc4bb0e2SMartin KaFai Lau 	/* id is in [1, INT_MAX) */
2217dc4bb0e2SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
2218dc4bb0e2SMartin KaFai Lau 		return -ENOSPC;
2219dc4bb0e2SMartin KaFai Lau 
2220dc4bb0e2SMartin KaFai Lau 	return id > 0 ? 0 : id;
2221dc4bb0e2SMartin KaFai Lau }
2222dc4bb0e2SMartin KaFai Lau 
2223e7895f01SPaul Moore void bpf_prog_free_id(struct bpf_prog *prog)
2224dc4bb0e2SMartin KaFai Lau {
2225d809e134SAlexei Starovoitov 	unsigned long flags;
2226d809e134SAlexei Starovoitov 
2227ad8ad79fSJakub Kicinski 	/* cBPF to eBPF migrations are currently not in the idr store.
2228ad8ad79fSJakub Kicinski 	 * Offloaded programs are removed from the store when their device
2229ad8ad79fSJakub Kicinski 	 * disappears - even if someone grabs an fd to them they are unusable,
2230ad8ad79fSJakub Kicinski 	 * simply waiting for refcnt to drop to be freed.
2231ad8ad79fSJakub Kicinski 	 */
2232dc4bb0e2SMartin KaFai Lau 	if (!prog->aux->id)
2233dc4bb0e2SMartin KaFai Lau 		return;
2234dc4bb0e2SMartin KaFai Lau 
2235d809e134SAlexei Starovoitov 	spin_lock_irqsave(&prog_idr_lock, flags);
2236dc4bb0e2SMartin KaFai Lau 	idr_remove(&prog_idr, prog->aux->id);
2237ad8ad79fSJakub Kicinski 	prog->aux->id = 0;
2238d809e134SAlexei Starovoitov 	spin_unlock_irqrestore(&prog_idr_lock, flags);
2239dc4bb0e2SMartin KaFai Lau }
2240dc4bb0e2SMartin KaFai Lau 
22411aacde3dSDaniel Borkmann static void __bpf_prog_put_rcu(struct rcu_head *rcu)
2242abf2e7d6SAlexei Starovoitov {
2243abf2e7d6SAlexei Starovoitov 	struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
2244abf2e7d6SAlexei Starovoitov 
22453b4d9eb2SDaniel Borkmann 	kvfree(aux->func_info);
22468c1b6e69SAlexei Starovoitov 	kfree(aux->func_info_aux);
22473ac1f01bSRoman Gushchin 	free_uid(aux->user);
22481b67772eSAndrii Nakryiko 	security_bpf_prog_free(aux->prog);
2249abf2e7d6SAlexei Starovoitov 	bpf_prog_free(aux->prog);
2250abf2e7d6SAlexei Starovoitov }
2251abf2e7d6SAlexei Starovoitov 
2252cd7455f1SDaniel Borkmann static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
2253cd7455f1SDaniel Borkmann {
2254cd7455f1SDaniel Borkmann 	bpf_prog_kallsyms_del_all(prog);
2255cd7455f1SDaniel Borkmann 	btf_put(prog->aux->btf);
225631bf1dbcSViktor Malik 	module_put(prog->aux->mod);
2257e16301fbSMartin KaFai Lau 	kvfree(prog->aux->jited_linfo);
2258e16301fbSMartin KaFai Lau 	kvfree(prog->aux->linfo);
2259e6ac2450SMartin KaFai Lau 	kfree(prog->aux->kfunc_tab);
226022dc4a0fSAndrii Nakryiko 	if (prog->aux->attach_btf)
226122dc4a0fSAndrii Nakryiko 		btf_put(prog->aux->attach_btf);
2262cd7455f1SDaniel Borkmann 
22631e6c62a8SAlexei Starovoitov 	if (deferred) {
226466c84731SAndrii Nakryiko 		if (prog->sleepable)
22651e6c62a8SAlexei Starovoitov 			call_rcu_tasks_trace(&prog->aux->rcu, __bpf_prog_put_rcu);
2266cd7455f1SDaniel Borkmann 		else
22671e6c62a8SAlexei Starovoitov 			call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
22681e6c62a8SAlexei Starovoitov 	} else {
2269cd7455f1SDaniel Borkmann 		__bpf_prog_put_rcu(&prog->aux->rcu);
2270cd7455f1SDaniel Borkmann 	}
22711e6c62a8SAlexei Starovoitov }
2272cd7455f1SDaniel Borkmann 
2273d809e134SAlexei Starovoitov static void bpf_prog_put_deferred(struct work_struct *work)
227409756af4SAlexei Starovoitov {
2275d809e134SAlexei Starovoitov 	struct bpf_prog_aux *aux;
2276d809e134SAlexei Starovoitov 	struct bpf_prog *prog;
2277d809e134SAlexei Starovoitov 
2278d809e134SAlexei Starovoitov 	aux = container_of(work, struct bpf_prog_aux, work);
2279d809e134SAlexei Starovoitov 	prog = aux->prog;
22806ee52e2aSSong Liu 	perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0);
2281bae141f5SDaniel Borkmann 	bpf_audit_prog(prog, BPF_AUDIT_UNLOAD);
2282e7895f01SPaul Moore 	bpf_prog_free_id(prog);
2283d809e134SAlexei Starovoitov 	__bpf_prog_put_noref(prog, true);
2284d809e134SAlexei Starovoitov }
2285d809e134SAlexei Starovoitov 
2286e7895f01SPaul Moore static void __bpf_prog_put(struct bpf_prog *prog)
2287d809e134SAlexei Starovoitov {
2288d809e134SAlexei Starovoitov 	struct bpf_prog_aux *aux = prog->aux;
2289d809e134SAlexei Starovoitov 
2290d809e134SAlexei Starovoitov 	if (atomic64_dec_and_test(&aux->refcnt)) {
2291d809e134SAlexei Starovoitov 		if (in_irq() || irqs_disabled()) {
2292d809e134SAlexei Starovoitov 			INIT_WORK(&aux->work, bpf_prog_put_deferred);
2293d809e134SAlexei Starovoitov 			schedule_work(&aux->work);
2294d809e134SAlexei Starovoitov 		} else {
2295d809e134SAlexei Starovoitov 			bpf_prog_put_deferred(&aux->work);
2296d809e134SAlexei Starovoitov 		}
229709756af4SAlexei Starovoitov 	}
2298a67edbf4SDaniel Borkmann }
2299b16d9aa4SMartin KaFai Lau 
2300b16d9aa4SMartin KaFai Lau void bpf_prog_put(struct bpf_prog *prog)
2301b16d9aa4SMartin KaFai Lau {
2302e7895f01SPaul Moore 	__bpf_prog_put(prog);
2303b16d9aa4SMartin KaFai Lau }
2304e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put);
230509756af4SAlexei Starovoitov 
230609756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp)
230709756af4SAlexei Starovoitov {
230809756af4SAlexei Starovoitov 	struct bpf_prog *prog = filp->private_data;
230909756af4SAlexei Starovoitov 
23101aacde3dSDaniel Borkmann 	bpf_prog_put(prog);
231109756af4SAlexei Starovoitov 	return 0;
231209756af4SAlexei Starovoitov }
231309756af4SAlexei Starovoitov 
231461a0abaeSEric Dumazet struct bpf_prog_kstats {
231561a0abaeSEric Dumazet 	u64 nsecs;
231661a0abaeSEric Dumazet 	u64 cnt;
231761a0abaeSEric Dumazet 	u64 misses;
231861a0abaeSEric Dumazet };
231961a0abaeSEric Dumazet 
232005b24ff9SJiri Olsa void notrace bpf_prog_inc_misses_counter(struct bpf_prog *prog)
232105b24ff9SJiri Olsa {
232205b24ff9SJiri Olsa 	struct bpf_prog_stats *stats;
232305b24ff9SJiri Olsa 	unsigned int flags;
232405b24ff9SJiri Olsa 
232505b24ff9SJiri Olsa 	stats = this_cpu_ptr(prog->stats);
232605b24ff9SJiri Olsa 	flags = u64_stats_update_begin_irqsave(&stats->syncp);
232705b24ff9SJiri Olsa 	u64_stats_inc(&stats->misses);
232805b24ff9SJiri Olsa 	u64_stats_update_end_irqrestore(&stats->syncp, flags);
232905b24ff9SJiri Olsa }
233005b24ff9SJiri Olsa 
2331492ecee8SAlexei Starovoitov static void bpf_prog_get_stats(const struct bpf_prog *prog,
233261a0abaeSEric Dumazet 			       struct bpf_prog_kstats *stats)
2333492ecee8SAlexei Starovoitov {
23349ed9e9baSAlexei Starovoitov 	u64 nsecs = 0, cnt = 0, misses = 0;
2335492ecee8SAlexei Starovoitov 	int cpu;
2336492ecee8SAlexei Starovoitov 
2337492ecee8SAlexei Starovoitov 	for_each_possible_cpu(cpu) {
2338492ecee8SAlexei Starovoitov 		const struct bpf_prog_stats *st;
2339492ecee8SAlexei Starovoitov 		unsigned int start;
23409ed9e9baSAlexei Starovoitov 		u64 tnsecs, tcnt, tmisses;
2341492ecee8SAlexei Starovoitov 
2342700d4796SAlexei Starovoitov 		st = per_cpu_ptr(prog->stats, cpu);
2343492ecee8SAlexei Starovoitov 		do {
234497c4090bSThomas Gleixner 			start = u64_stats_fetch_begin(&st->syncp);
234561a0abaeSEric Dumazet 			tnsecs = u64_stats_read(&st->nsecs);
234661a0abaeSEric Dumazet 			tcnt = u64_stats_read(&st->cnt);
234761a0abaeSEric Dumazet 			tmisses = u64_stats_read(&st->misses);
234897c4090bSThomas Gleixner 		} while (u64_stats_fetch_retry(&st->syncp, start));
2349492ecee8SAlexei Starovoitov 		nsecs += tnsecs;
2350492ecee8SAlexei Starovoitov 		cnt += tcnt;
23519ed9e9baSAlexei Starovoitov 		misses += tmisses;
2352492ecee8SAlexei Starovoitov 	}
2353492ecee8SAlexei Starovoitov 	stats->nsecs = nsecs;
2354492ecee8SAlexei Starovoitov 	stats->cnt = cnt;
23559ed9e9baSAlexei Starovoitov 	stats->misses = misses;
2356492ecee8SAlexei Starovoitov }
2357492ecee8SAlexei Starovoitov 
23587bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
23597bd509e3SDaniel Borkmann static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp)
23607bd509e3SDaniel Borkmann {
23617bd509e3SDaniel Borkmann 	const struct bpf_prog *prog = filp->private_data;
2362f1f7714eSDaniel Borkmann 	char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
236361a0abaeSEric Dumazet 	struct bpf_prog_kstats stats;
23647bd509e3SDaniel Borkmann 
2365492ecee8SAlexei Starovoitov 	bpf_prog_get_stats(prog, &stats);
2366f1f7714eSDaniel Borkmann 	bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
23677bd509e3SDaniel Borkmann 	seq_printf(m,
23687bd509e3SDaniel Borkmann 		   "prog_type:\t%u\n"
23697bd509e3SDaniel Borkmann 		   "prog_jited:\t%u\n"
2370f1f7714eSDaniel Borkmann 		   "prog_tag:\t%s\n"
23714316b409SDaniel Borkmann 		   "memlock:\t%llu\n"
2372492ecee8SAlexei Starovoitov 		   "prog_id:\t%u\n"
2373492ecee8SAlexei Starovoitov 		   "run_time_ns:\t%llu\n"
23749ed9e9baSAlexei Starovoitov 		   "run_cnt:\t%llu\n"
2375aba64c7dSDave Marchevsky 		   "recursion_misses:\t%llu\n"
2376aba64c7dSDave Marchevsky 		   "verified_insns:\t%u\n",
23777bd509e3SDaniel Borkmann 		   prog->type,
23787bd509e3SDaniel Borkmann 		   prog->jited,
2379f1f7714eSDaniel Borkmann 		   prog_tag,
23804316b409SDaniel Borkmann 		   prog->pages * 1ULL << PAGE_SHIFT,
2381492ecee8SAlexei Starovoitov 		   prog->aux->id,
2382492ecee8SAlexei Starovoitov 		   stats.nsecs,
23839ed9e9baSAlexei Starovoitov 		   stats.cnt,
2384aba64c7dSDave Marchevsky 		   stats.misses,
2385aba64c7dSDave Marchevsky 		   prog->aux->verified_insns);
23867bd509e3SDaniel Borkmann }
23877bd509e3SDaniel Borkmann #endif
23887bd509e3SDaniel Borkmann 
2389f66e448cSChenbo Feng const struct file_operations bpf_prog_fops = {
23907bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
23917bd509e3SDaniel Borkmann 	.show_fdinfo	= bpf_prog_show_fdinfo,
23927bd509e3SDaniel Borkmann #endif
239309756af4SAlexei Starovoitov 	.release	= bpf_prog_release,
23946e71b04aSChenbo Feng 	.read		= bpf_dummy_read,
23956e71b04aSChenbo Feng 	.write		= bpf_dummy_write,
239609756af4SAlexei Starovoitov };
239709756af4SAlexei Starovoitov 
2398b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog)
2399aa79781bSDaniel Borkmann {
2400afdb09c7SChenbo Feng 	int ret;
2401afdb09c7SChenbo Feng 
2402afdb09c7SChenbo Feng 	ret = security_bpf_prog(prog);
2403afdb09c7SChenbo Feng 	if (ret < 0)
2404afdb09c7SChenbo Feng 		return ret;
2405afdb09c7SChenbo Feng 
2406aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog,
2407aa79781bSDaniel Borkmann 				O_RDWR | O_CLOEXEC);
2408aa79781bSDaniel Borkmann }
2409aa79781bSDaniel Borkmann 
2410113214beSDaniel Borkmann static struct bpf_prog *____bpf_prog_get(struct fd f)
241109756af4SAlexei Starovoitov {
241209756af4SAlexei Starovoitov 	if (!f.file)
241309756af4SAlexei Starovoitov 		return ERR_PTR(-EBADF);
241409756af4SAlexei Starovoitov 	if (f.file->f_op != &bpf_prog_fops) {
241509756af4SAlexei Starovoitov 		fdput(f);
241609756af4SAlexei Starovoitov 		return ERR_PTR(-EINVAL);
241709756af4SAlexei Starovoitov 	}
241809756af4SAlexei Starovoitov 
2419c2101297SDaniel Borkmann 	return f.file->private_data;
242009756af4SAlexei Starovoitov }
242109756af4SAlexei Starovoitov 
242285192dbfSAndrii Nakryiko void bpf_prog_add(struct bpf_prog *prog, int i)
242392117d84SAlexei Starovoitov {
242485192dbfSAndrii Nakryiko 	atomic64_add(i, &prog->aux->refcnt);
242592117d84SAlexei Starovoitov }
242659d3656dSBrenden Blanco EXPORT_SYMBOL_GPL(bpf_prog_add);
242759d3656dSBrenden Blanco 
2428c540594fSDaniel Borkmann void bpf_prog_sub(struct bpf_prog *prog, int i)
2429c540594fSDaniel Borkmann {
2430c540594fSDaniel Borkmann 	/* Only to be used for undoing previous bpf_prog_add() in some
2431c540594fSDaniel Borkmann 	 * error path. We still know that another entity in our call
2432c540594fSDaniel Borkmann 	 * path holds a reference to the program, thus atomic_sub() can
2433c540594fSDaniel Borkmann 	 * be safely used in such cases!
2434c540594fSDaniel Borkmann 	 */
243585192dbfSAndrii Nakryiko 	WARN_ON(atomic64_sub_return(i, &prog->aux->refcnt) == 0);
2436c540594fSDaniel Borkmann }
2437c540594fSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_sub);
2438c540594fSDaniel Borkmann 
243985192dbfSAndrii Nakryiko void bpf_prog_inc(struct bpf_prog *prog)
244059d3656dSBrenden Blanco {
244185192dbfSAndrii Nakryiko 	atomic64_inc(&prog->aux->refcnt);
244259d3656dSBrenden Blanco }
244397bc402dSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_inc);
244492117d84SAlexei Starovoitov 
2445b16d9aa4SMartin KaFai Lau /* prog_idr_lock should have been held */
2446a6f6df69SJohn Fastabend struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog)
2447b16d9aa4SMartin KaFai Lau {
2448b16d9aa4SMartin KaFai Lau 	int refold;
2449b16d9aa4SMartin KaFai Lau 
245085192dbfSAndrii Nakryiko 	refold = atomic64_fetch_add_unless(&prog->aux->refcnt, 1, 0);
2451b16d9aa4SMartin KaFai Lau 
2452b16d9aa4SMartin KaFai Lau 	if (!refold)
2453b16d9aa4SMartin KaFai Lau 		return ERR_PTR(-ENOENT);
2454b16d9aa4SMartin KaFai Lau 
2455b16d9aa4SMartin KaFai Lau 	return prog;
2456b16d9aa4SMartin KaFai Lau }
2457a6f6df69SJohn Fastabend EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero);
2458b16d9aa4SMartin KaFai Lau 
2459040ee692SAl Viro bool bpf_prog_get_ok(struct bpf_prog *prog,
2460288b3de5SJakub Kicinski 			    enum bpf_prog_type *attach_type, bool attach_drv)
2461248f346fSJakub Kicinski {
2462288b3de5SJakub Kicinski 	/* not an attachment, just a refcount inc, always allow */
2463288b3de5SJakub Kicinski 	if (!attach_type)
2464288b3de5SJakub Kicinski 		return true;
2465248f346fSJakub Kicinski 
2466248f346fSJakub Kicinski 	if (prog->type != *attach_type)
2467248f346fSJakub Kicinski 		return false;
24689d03ebc7SStanislav Fomichev 	if (bpf_prog_is_offloaded(prog->aux) && !attach_drv)
2469248f346fSJakub Kicinski 		return false;
2470248f346fSJakub Kicinski 
2471248f346fSJakub Kicinski 	return true;
2472248f346fSJakub Kicinski }
2473248f346fSJakub Kicinski 
2474248f346fSJakub Kicinski static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type,
2475288b3de5SJakub Kicinski 				       bool attach_drv)
247609756af4SAlexei Starovoitov {
247709756af4SAlexei Starovoitov 	struct fd f = fdget(ufd);
247809756af4SAlexei Starovoitov 	struct bpf_prog *prog;
247909756af4SAlexei Starovoitov 
2480113214beSDaniel Borkmann 	prog = ____bpf_prog_get(f);
248109756af4SAlexei Starovoitov 	if (IS_ERR(prog))
248209756af4SAlexei Starovoitov 		return prog;
2483288b3de5SJakub Kicinski 	if (!bpf_prog_get_ok(prog, attach_type, attach_drv)) {
2484113214beSDaniel Borkmann 		prog = ERR_PTR(-EINVAL);
2485113214beSDaniel Borkmann 		goto out;
2486113214beSDaniel Borkmann 	}
248709756af4SAlexei Starovoitov 
248885192dbfSAndrii Nakryiko 	bpf_prog_inc(prog);
2489113214beSDaniel Borkmann out:
249009756af4SAlexei Starovoitov 	fdput(f);
249109756af4SAlexei Starovoitov 	return prog;
249209756af4SAlexei Starovoitov }
2493113214beSDaniel Borkmann 
2494113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get(u32 ufd)
2495113214beSDaniel Borkmann {
2496288b3de5SJakub Kicinski 	return __bpf_prog_get(ufd, NULL, false);
2497113214beSDaniel Borkmann }
2498113214beSDaniel Borkmann 
2499248f346fSJakub Kicinski struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type,
2500288b3de5SJakub Kicinski 				       bool attach_drv)
2501248f346fSJakub Kicinski {
25024d220ed0SAlexei Starovoitov 	return __bpf_prog_get(ufd, &type, attach_drv);
2503248f346fSJakub Kicinski }
25046c8dfe21SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_prog_get_type_dev);
2505248f346fSJakub Kicinski 
2506aac3fc32SAndrey Ignatov /* Initially all BPF programs could be loaded w/o specifying
2507aac3fc32SAndrey Ignatov  * expected_attach_type. Later for some of them specifying expected_attach_type
2508aac3fc32SAndrey Ignatov  * at load time became required so that program could be validated properly.
2509aac3fc32SAndrey Ignatov  * Programs of types that are allowed to be loaded both w/ and w/o (for
2510aac3fc32SAndrey Ignatov  * backward compatibility) expected_attach_type, should have the default attach
2511aac3fc32SAndrey Ignatov  * type assigned to expected_attach_type for the latter case, so that it can be
2512aac3fc32SAndrey Ignatov  * validated later at attach time.
2513aac3fc32SAndrey Ignatov  *
2514aac3fc32SAndrey Ignatov  * bpf_prog_load_fixup_attach_type() sets expected_attach_type in @attr if
2515aac3fc32SAndrey Ignatov  * prog type requires it but has some attach types that have to be backward
2516aac3fc32SAndrey Ignatov  * compatible.
2517aac3fc32SAndrey Ignatov  */
2518aac3fc32SAndrey Ignatov static void bpf_prog_load_fixup_attach_type(union bpf_attr *attr)
2519aac3fc32SAndrey Ignatov {
2520aac3fc32SAndrey Ignatov 	switch (attr->prog_type) {
2521aac3fc32SAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK:
2522aac3fc32SAndrey Ignatov 		/* Unfortunately BPF_ATTACH_TYPE_UNSPEC enumeration doesn't
2523aac3fc32SAndrey Ignatov 		 * exist so checking for non-zero is the way to go here.
2524aac3fc32SAndrey Ignatov 		 */
2525aac3fc32SAndrey Ignatov 		if (!attr->expected_attach_type)
2526aac3fc32SAndrey Ignatov 			attr->expected_attach_type =
2527aac3fc32SAndrey Ignatov 				BPF_CGROUP_INET_SOCK_CREATE;
2528aac3fc32SAndrey Ignatov 		break;
2529d5e4ddaeSKuniyuki Iwashima 	case BPF_PROG_TYPE_SK_REUSEPORT:
2530d5e4ddaeSKuniyuki Iwashima 		if (!attr->expected_attach_type)
2531d5e4ddaeSKuniyuki Iwashima 			attr->expected_attach_type =
2532d5e4ddaeSKuniyuki Iwashima 				BPF_SK_REUSEPORT_SELECT;
2533d5e4ddaeSKuniyuki Iwashima 		break;
2534aac3fc32SAndrey Ignatov 	}
2535aac3fc32SAndrey Ignatov }
2536aac3fc32SAndrey Ignatov 
25375e43f899SAndrey Ignatov static int
2538ccfe29ebSAlexei Starovoitov bpf_prog_load_check_attach(enum bpf_prog_type prog_type,
2539ccfe29ebSAlexei Starovoitov 			   enum bpf_attach_type expected_attach_type,
2540290248a5SAndrii Nakryiko 			   struct btf *attach_btf, u32 btf_id,
2541290248a5SAndrii Nakryiko 			   struct bpf_prog *dst_prog)
25425e43f899SAndrey Ignatov {
254327ae7997SMartin KaFai Lau 	if (btf_id) {
2544c108e3c1SAlexei Starovoitov 		if (btf_id > BTF_MAX_TYPE)
2545c108e3c1SAlexei Starovoitov 			return -EINVAL;
254627ae7997SMartin KaFai Lau 
2547290248a5SAndrii Nakryiko 		if (!attach_btf && !dst_prog)
2548290248a5SAndrii Nakryiko 			return -EINVAL;
2549290248a5SAndrii Nakryiko 
255027ae7997SMartin KaFai Lau 		switch (prog_type) {
255127ae7997SMartin KaFai Lau 		case BPF_PROG_TYPE_TRACING:
25529e4e01dfSKP Singh 		case BPF_PROG_TYPE_LSM:
255327ae7997SMartin KaFai Lau 		case BPF_PROG_TYPE_STRUCT_OPS:
2554be8704ffSAlexei Starovoitov 		case BPF_PROG_TYPE_EXT:
2555c108e3c1SAlexei Starovoitov 			break;
2556c108e3c1SAlexei Starovoitov 		default:
2557c108e3c1SAlexei Starovoitov 			return -EINVAL;
2558c108e3c1SAlexei Starovoitov 		}
255927ae7997SMartin KaFai Lau 	}
256027ae7997SMartin KaFai Lau 
2561290248a5SAndrii Nakryiko 	if (attach_btf && (!btf_id || dst_prog))
2562290248a5SAndrii Nakryiko 		return -EINVAL;
2563290248a5SAndrii Nakryiko 
2564290248a5SAndrii Nakryiko 	if (dst_prog && prog_type != BPF_PROG_TYPE_TRACING &&
2565be8704ffSAlexei Starovoitov 	    prog_type != BPF_PROG_TYPE_EXT)
256627ae7997SMartin KaFai Lau 		return -EINVAL;
2567c108e3c1SAlexei Starovoitov 
2568c108e3c1SAlexei Starovoitov 	switch (prog_type) {
2569aac3fc32SAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK:
2570aac3fc32SAndrey Ignatov 		switch (expected_attach_type) {
2571aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET_SOCK_CREATE:
2572f5836749SStanislav Fomichev 		case BPF_CGROUP_INET_SOCK_RELEASE:
2573aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET4_POST_BIND:
2574aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET6_POST_BIND:
2575aac3fc32SAndrey Ignatov 			return 0;
2576aac3fc32SAndrey Ignatov 		default:
2577aac3fc32SAndrey Ignatov 			return -EINVAL;
2578aac3fc32SAndrey Ignatov 		}
25794fbac77dSAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
25804fbac77dSAndrey Ignatov 		switch (expected_attach_type) {
25814fbac77dSAndrey Ignatov 		case BPF_CGROUP_INET4_BIND:
25824fbac77dSAndrey Ignatov 		case BPF_CGROUP_INET6_BIND:
2583d74bad4eSAndrey Ignatov 		case BPF_CGROUP_INET4_CONNECT:
2584d74bad4eSAndrey Ignatov 		case BPF_CGROUP_INET6_CONNECT:
2585859051ddSDaan De Meyer 		case BPF_CGROUP_UNIX_CONNECT:
25861b66d253SDaniel Borkmann 		case BPF_CGROUP_INET4_GETPEERNAME:
25871b66d253SDaniel Borkmann 		case BPF_CGROUP_INET6_GETPEERNAME:
2588859051ddSDaan De Meyer 		case BPF_CGROUP_UNIX_GETPEERNAME:
25891b66d253SDaniel Borkmann 		case BPF_CGROUP_INET4_GETSOCKNAME:
25901b66d253SDaniel Borkmann 		case BPF_CGROUP_INET6_GETSOCKNAME:
2591859051ddSDaan De Meyer 		case BPF_CGROUP_UNIX_GETSOCKNAME:
25921cedee13SAndrey Ignatov 		case BPF_CGROUP_UDP4_SENDMSG:
25931cedee13SAndrey Ignatov 		case BPF_CGROUP_UDP6_SENDMSG:
2594859051ddSDaan De Meyer 		case BPF_CGROUP_UNIX_SENDMSG:
2595983695faSDaniel Borkmann 		case BPF_CGROUP_UDP4_RECVMSG:
2596983695faSDaniel Borkmann 		case BPF_CGROUP_UDP6_RECVMSG:
2597859051ddSDaan De Meyer 		case BPF_CGROUP_UNIX_RECVMSG:
25985e43f899SAndrey Ignatov 			return 0;
25994fbac77dSAndrey Ignatov 		default:
26004fbac77dSAndrey Ignatov 			return -EINVAL;
26014fbac77dSAndrey Ignatov 		}
26025cf1e914Sbrakmo 	case BPF_PROG_TYPE_CGROUP_SKB:
26035cf1e914Sbrakmo 		switch (expected_attach_type) {
26045cf1e914Sbrakmo 		case BPF_CGROUP_INET_INGRESS:
26055cf1e914Sbrakmo 		case BPF_CGROUP_INET_EGRESS:
26065cf1e914Sbrakmo 			return 0;
26075cf1e914Sbrakmo 		default:
26085cf1e914Sbrakmo 			return -EINVAL;
26095cf1e914Sbrakmo 		}
26100d01da6aSStanislav Fomichev 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
26110d01da6aSStanislav Fomichev 		switch (expected_attach_type) {
26120d01da6aSStanislav Fomichev 		case BPF_CGROUP_SETSOCKOPT:
26130d01da6aSStanislav Fomichev 		case BPF_CGROUP_GETSOCKOPT:
26140d01da6aSStanislav Fomichev 			return 0;
26150d01da6aSStanislav Fomichev 		default:
26160d01da6aSStanislav Fomichev 			return -EINVAL;
26170d01da6aSStanislav Fomichev 		}
2618e9ddbb77SJakub Sitnicki 	case BPF_PROG_TYPE_SK_LOOKUP:
2619e9ddbb77SJakub Sitnicki 		if (expected_attach_type == BPF_SK_LOOKUP)
2620e9ddbb77SJakub Sitnicki 			return 0;
2621e9ddbb77SJakub Sitnicki 		return -EINVAL;
2622d5e4ddaeSKuniyuki Iwashima 	case BPF_PROG_TYPE_SK_REUSEPORT:
2623d5e4ddaeSKuniyuki Iwashima 		switch (expected_attach_type) {
2624d5e4ddaeSKuniyuki Iwashima 		case BPF_SK_REUSEPORT_SELECT:
2625d5e4ddaeSKuniyuki Iwashima 		case BPF_SK_REUSEPORT_SELECT_OR_MIGRATE:
2626d5e4ddaeSKuniyuki Iwashima 			return 0;
2627d5e4ddaeSKuniyuki Iwashima 		default:
2628d5e4ddaeSKuniyuki Iwashima 			return -EINVAL;
2629d5e4ddaeSKuniyuki Iwashima 		}
2630132328e8SFlorian Westphal 	case BPF_PROG_TYPE_NETFILTER:
2631132328e8SFlorian Westphal 		if (expected_attach_type == BPF_NETFILTER)
2632132328e8SFlorian Westphal 			return 0;
2633132328e8SFlorian Westphal 		return -EINVAL;
263479a7f8bdSAlexei Starovoitov 	case BPF_PROG_TYPE_SYSCALL:
2635be8704ffSAlexei Starovoitov 	case BPF_PROG_TYPE_EXT:
2636be8704ffSAlexei Starovoitov 		if (expected_attach_type)
2637be8704ffSAlexei Starovoitov 			return -EINVAL;
2638df561f66SGustavo A. R. Silva 		fallthrough;
26394fbac77dSAndrey Ignatov 	default:
26404fbac77dSAndrey Ignatov 		return 0;
26414fbac77dSAndrey Ignatov 	}
26425e43f899SAndrey Ignatov }
26435e43f899SAndrey Ignatov 
26442c78ee89SAlexei Starovoitov static bool is_net_admin_prog_type(enum bpf_prog_type prog_type)
26452c78ee89SAlexei Starovoitov {
26462c78ee89SAlexei Starovoitov 	switch (prog_type) {
26472c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SCHED_CLS:
26482c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SCHED_ACT:
26492c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_XDP:
26502c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_IN:
26512c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_OUT:
26522c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_XMIT:
26532c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_SEG6LOCAL:
26542c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SK_SKB:
26552c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SK_MSG:
26562c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
26572c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_DEVICE:
26582c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SOCK:
26592c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
26602c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
26612c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
26622c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SOCK_OPS:
26632c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_EXT: /* extends any prog */
266484601d6eSFlorian Westphal 	case BPF_PROG_TYPE_NETFILTER:
26652c78ee89SAlexei Starovoitov 		return true;
26662c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SKB:
26672c78ee89SAlexei Starovoitov 		/* always unpriv */
26682c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SK_REUSEPORT:
26692c78ee89SAlexei Starovoitov 		/* equivalent to SOCKET_FILTER. need CAP_BPF only */
26702c78ee89SAlexei Starovoitov 	default:
26712c78ee89SAlexei Starovoitov 		return false;
26722c78ee89SAlexei Starovoitov 	}
26732c78ee89SAlexei Starovoitov }
26742c78ee89SAlexei Starovoitov 
26752c78ee89SAlexei Starovoitov static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
26762c78ee89SAlexei Starovoitov {
26772c78ee89SAlexei Starovoitov 	switch (prog_type) {
26782c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_KPROBE:
26792c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_TRACEPOINT:
26802c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_PERF_EVENT:
26812c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_RAW_TRACEPOINT:
26822c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
26832c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_TRACING:
26842c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LSM:
26852c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_STRUCT_OPS: /* has access to struct sock */
26862c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_EXT: /* extends any prog */
26872c78ee89SAlexei Starovoitov 		return true;
26882c78ee89SAlexei Starovoitov 	default:
26892c78ee89SAlexei Starovoitov 		return false;
26902c78ee89SAlexei Starovoitov 	}
26912c78ee89SAlexei Starovoitov }
26922c78ee89SAlexei Starovoitov 
269309756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
2694caf8f28eSAndrii Nakryiko #define BPF_PROG_LOAD_LAST_FIELD prog_token_fd
269509756af4SAlexei Starovoitov 
269647a71c1fSAndrii Nakryiko static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
269709756af4SAlexei Starovoitov {
269809756af4SAlexei Starovoitov 	enum bpf_prog_type type = attr->prog_type;
2699290248a5SAndrii Nakryiko 	struct bpf_prog *prog, *dst_prog = NULL;
2700290248a5SAndrii Nakryiko 	struct btf *attach_btf = NULL;
2701caf8f28eSAndrii Nakryiko 	struct bpf_token *token = NULL;
2702caf8f28eSAndrii Nakryiko 	bool bpf_cap;
270309756af4SAlexei Starovoitov 	int err;
270409756af4SAlexei Starovoitov 	char license[128];
270509756af4SAlexei Starovoitov 
270609756af4SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_LOAD))
270709756af4SAlexei Starovoitov 		return -EINVAL;
270809756af4SAlexei Starovoitov 
2709c240eff6SJiong Wang 	if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT |
2710c240eff6SJiong Wang 				 BPF_F_ANY_ALIGNMENT |
271110d274e8SAlexei Starovoitov 				 BPF_F_TEST_STATE_FREQ |
27121e6c62a8SAlexei Starovoitov 				 BPF_F_SLEEPABLE |
2713c2f2cdbeSLorenzo Bianconi 				 BPF_F_TEST_RND_HI32 |
27142b3486bcSStanislav Fomichev 				 BPF_F_XDP_HAS_FRAGS |
27155f99f312SAndrii Nakryiko 				 BPF_F_XDP_DEV_BOUND_ONLY |
2716caf8f28eSAndrii Nakryiko 				 BPF_F_TEST_REG_INVARIANTS |
2717caf8f28eSAndrii Nakryiko 				 BPF_F_TOKEN_FD))
2718e07b98d9SDavid S. Miller 		return -EINVAL;
2719e07b98d9SDavid S. Miller 
2720caf8f28eSAndrii Nakryiko 	bpf_prog_load_fixup_attach_type(attr);
2721caf8f28eSAndrii Nakryiko 
2722caf8f28eSAndrii Nakryiko 	if (attr->prog_flags & BPF_F_TOKEN_FD) {
2723caf8f28eSAndrii Nakryiko 		token = bpf_token_get_from_fd(attr->prog_token_fd);
2724caf8f28eSAndrii Nakryiko 		if (IS_ERR(token))
2725caf8f28eSAndrii Nakryiko 			return PTR_ERR(token);
2726caf8f28eSAndrii Nakryiko 		/* if current token doesn't grant prog loading permissions,
2727caf8f28eSAndrii Nakryiko 		 * then we can't use this token, so ignore it and rely on
2728caf8f28eSAndrii Nakryiko 		 * system-wide capabilities checks
2729caf8f28eSAndrii Nakryiko 		 */
2730caf8f28eSAndrii Nakryiko 		if (!bpf_token_allow_cmd(token, BPF_PROG_LOAD) ||
2731caf8f28eSAndrii Nakryiko 		    !bpf_token_allow_prog_type(token, attr->prog_type,
2732caf8f28eSAndrii Nakryiko 					       attr->expected_attach_type)) {
2733caf8f28eSAndrii Nakryiko 			bpf_token_put(token);
2734caf8f28eSAndrii Nakryiko 			token = NULL;
2735caf8f28eSAndrii Nakryiko 		}
2736caf8f28eSAndrii Nakryiko 	}
2737caf8f28eSAndrii Nakryiko 
2738caf8f28eSAndrii Nakryiko 	bpf_cap = bpf_token_capable(token, CAP_BPF);
2739caf8f28eSAndrii Nakryiko 	err = -EPERM;
2740caf8f28eSAndrii Nakryiko 
2741e9ee9efcSDavid Miller 	if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
2742e9ee9efcSDavid Miller 	    (attr->prog_flags & BPF_F_ANY_ALIGNMENT) &&
2743caf8f28eSAndrii Nakryiko 	    !bpf_cap)
2744caf8f28eSAndrii Nakryiko 		goto put_token;
2745e9ee9efcSDavid Miller 
27461d28635aSAndrii Nakryiko 	/* Intent here is for unprivileged_bpf_disabled to block BPF program
27471d28635aSAndrii Nakryiko 	 * creation for unprivileged users; other actions depend
27481d28635aSAndrii Nakryiko 	 * on fd availability and access to bpffs, so are dependent on
27491d28635aSAndrii Nakryiko 	 * object creation success. Even with unprivileged BPF disabled,
27501d28635aSAndrii Nakryiko 	 * capability checks are still carried out for these
27511d28635aSAndrii Nakryiko 	 * and other operations.
27521d28635aSAndrii Nakryiko 	 */
2753caf8f28eSAndrii Nakryiko 	if (sysctl_unprivileged_bpf_disabled && !bpf_cap)
2754caf8f28eSAndrii Nakryiko 		goto put_token;
275509756af4SAlexei Starovoitov 
2756c04c0d2bSAlexei Starovoitov 	if (attr->insn_cnt == 0 ||
2757caf8f28eSAndrii Nakryiko 	    attr->insn_cnt > (bpf_cap ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) {
2758caf8f28eSAndrii Nakryiko 		err = -E2BIG;
2759caf8f28eSAndrii Nakryiko 		goto put_token;
2760caf8f28eSAndrii Nakryiko 	}
276180b7d819SChenbo Feng 	if (type != BPF_PROG_TYPE_SOCKET_FILTER &&
276280b7d819SChenbo Feng 	    type != BPF_PROG_TYPE_CGROUP_SKB &&
2763caf8f28eSAndrii Nakryiko 	    !bpf_cap)
2764caf8f28eSAndrii Nakryiko 		goto put_token;
27652c78ee89SAlexei Starovoitov 
2766caf8f28eSAndrii Nakryiko 	if (is_net_admin_prog_type(type) && !bpf_token_capable(token, CAP_NET_ADMIN))
2767caf8f28eSAndrii Nakryiko 		goto put_token;
2768caf8f28eSAndrii Nakryiko 	if (is_perfmon_prog_type(type) && !bpf_token_capable(token, CAP_PERFMON))
2769caf8f28eSAndrii Nakryiko 		goto put_token;
27701be7f75dSAlexei Starovoitov 
2771290248a5SAndrii Nakryiko 	/* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog
2772290248a5SAndrii Nakryiko 	 * or btf, we need to check which one it is
2773290248a5SAndrii Nakryiko 	 */
2774290248a5SAndrii Nakryiko 	if (attr->attach_prog_fd) {
2775290248a5SAndrii Nakryiko 		dst_prog = bpf_prog_get(attr->attach_prog_fd);
2776290248a5SAndrii Nakryiko 		if (IS_ERR(dst_prog)) {
2777290248a5SAndrii Nakryiko 			dst_prog = NULL;
2778290248a5SAndrii Nakryiko 			attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd);
2779caf8f28eSAndrii Nakryiko 			if (IS_ERR(attach_btf)) {
2780caf8f28eSAndrii Nakryiko 				err = -EINVAL;
2781caf8f28eSAndrii Nakryiko 				goto put_token;
2782caf8f28eSAndrii Nakryiko 			}
2783290248a5SAndrii Nakryiko 			if (!btf_is_kernel(attach_btf)) {
27848bdd8e27SAndrii Nakryiko 				/* attaching through specifying bpf_prog's BTF
27858bdd8e27SAndrii Nakryiko 				 * objects directly might be supported eventually
27868bdd8e27SAndrii Nakryiko 				 */
2787290248a5SAndrii Nakryiko 				btf_put(attach_btf);
2788caf8f28eSAndrii Nakryiko 				err = -ENOTSUPP;
2789caf8f28eSAndrii Nakryiko 				goto put_token;
2790290248a5SAndrii Nakryiko 			}
2791290248a5SAndrii Nakryiko 		}
2792290248a5SAndrii Nakryiko 	} else if (attr->attach_btf_id) {
2793290248a5SAndrii Nakryiko 		/* fall back to vmlinux BTF, if BTF type ID is specified */
2794290248a5SAndrii Nakryiko 		attach_btf = bpf_get_btf_vmlinux();
2795caf8f28eSAndrii Nakryiko 		if (IS_ERR(attach_btf)) {
2796caf8f28eSAndrii Nakryiko 			err = PTR_ERR(attach_btf);
2797caf8f28eSAndrii Nakryiko 			goto put_token;
2798caf8f28eSAndrii Nakryiko 		}
2799caf8f28eSAndrii Nakryiko 		if (!attach_btf) {
2800caf8f28eSAndrii Nakryiko 			err = -EINVAL;
2801caf8f28eSAndrii Nakryiko 			goto put_token;
2802caf8f28eSAndrii Nakryiko 		}
2803290248a5SAndrii Nakryiko 		btf_get(attach_btf);
2804290248a5SAndrii Nakryiko 	}
2805290248a5SAndrii Nakryiko 
2806ccfe29ebSAlexei Starovoitov 	if (bpf_prog_load_check_attach(type, attr->expected_attach_type,
2807290248a5SAndrii Nakryiko 				       attach_btf, attr->attach_btf_id,
2808290248a5SAndrii Nakryiko 				       dst_prog)) {
2809290248a5SAndrii Nakryiko 		if (dst_prog)
2810290248a5SAndrii Nakryiko 			bpf_prog_put(dst_prog);
2811290248a5SAndrii Nakryiko 		if (attach_btf)
2812290248a5SAndrii Nakryiko 			btf_put(attach_btf);
2813caf8f28eSAndrii Nakryiko 		err = -EINVAL;
2814caf8f28eSAndrii Nakryiko 		goto put_token;
2815290248a5SAndrii Nakryiko 	}
28165e43f899SAndrey Ignatov 
281709756af4SAlexei Starovoitov 	/* plain bpf_prog allocation */
281809756af4SAlexei Starovoitov 	prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
2819290248a5SAndrii Nakryiko 	if (!prog) {
2820290248a5SAndrii Nakryiko 		if (dst_prog)
2821290248a5SAndrii Nakryiko 			bpf_prog_put(dst_prog);
2822290248a5SAndrii Nakryiko 		if (attach_btf)
2823290248a5SAndrii Nakryiko 			btf_put(attach_btf);
2824caf8f28eSAndrii Nakryiko 		err = -EINVAL;
2825caf8f28eSAndrii Nakryiko 		goto put_token;
2826290248a5SAndrii Nakryiko 	}
282709756af4SAlexei Starovoitov 
28285e43f899SAndrey Ignatov 	prog->expected_attach_type = attr->expected_attach_type;
282966c84731SAndrii Nakryiko 	prog->sleepable = !!(attr->prog_flags & BPF_F_SLEEPABLE);
2830290248a5SAndrii Nakryiko 	prog->aux->attach_btf = attach_btf;
2831ccfe29ebSAlexei Starovoitov 	prog->aux->attach_btf_id = attr->attach_btf_id;
28323aac1eadSToke Høiland-Jørgensen 	prog->aux->dst_prog = dst_prog;
28332b3486bcSStanislav Fomichev 	prog->aux->dev_bound = !!attr->prog_ifindex;
2834c2f2cdbeSLorenzo Bianconi 	prog->aux->xdp_has_frags = attr->prog_flags & BPF_F_XDP_HAS_FRAGS;
28359a18eedbSJakub Kicinski 
2836caf8f28eSAndrii Nakryiko 	/* move token into prog->aux, reuse taken refcnt */
2837caf8f28eSAndrii Nakryiko 	prog->aux->token = token;
2838caf8f28eSAndrii Nakryiko 	token = NULL;
2839caf8f28eSAndrii Nakryiko 
28403ac1f01bSRoman Gushchin 	prog->aux->user = get_current_user();
284109756af4SAlexei Starovoitov 	prog->len = attr->insn_cnt;
284209756af4SAlexei Starovoitov 
284309756af4SAlexei Starovoitov 	err = -EFAULT;
2844af2ac3e1SAlexei Starovoitov 	if (copy_from_bpfptr(prog->insns,
2845af2ac3e1SAlexei Starovoitov 			     make_bpfptr(attr->insns, uattr.is_kernel),
2846aafe6ae9SDaniel Borkmann 			     bpf_prog_insn_size(prog)) != 0)
28471b67772eSAndrii Nakryiko 		goto free_prog;
28487f6719f7SAndrii Nakryiko 	/* copy eBPF program license from user space */
28497f6719f7SAndrii Nakryiko 	if (strncpy_from_bpfptr(license,
28507f6719f7SAndrii Nakryiko 				make_bpfptr(attr->license, uattr.is_kernel),
28517f6719f7SAndrii Nakryiko 				sizeof(license) - 1) < 0)
28521b67772eSAndrii Nakryiko 		goto free_prog;
28537f6719f7SAndrii Nakryiko 	license[sizeof(license) - 1] = 0;
28547f6719f7SAndrii Nakryiko 
28557f6719f7SAndrii Nakryiko 	/* eBPF programs must be GPL compatible to use GPL-ed functions */
28567f6719f7SAndrii Nakryiko 	prog->gpl_compatible = license_is_gpl_compatible(license) ? 1 : 0;
285709756af4SAlexei Starovoitov 
285809756af4SAlexei Starovoitov 	prog->orig_prog = NULL;
2859a91263d5SDaniel Borkmann 	prog->jited = 0;
286009756af4SAlexei Starovoitov 
286185192dbfSAndrii Nakryiko 	atomic64_set(&prog->aux->refcnt, 1);
286209756af4SAlexei Starovoitov 
28639a18eedbSJakub Kicinski 	if (bpf_prog_is_dev_bound(prog->aux)) {
28642b3486bcSStanislav Fomichev 		err = bpf_prog_dev_bound_init(prog, attr);
2865ab3f0063SJakub Kicinski 		if (err)
28661b67772eSAndrii Nakryiko 			goto free_prog;
2867ab3f0063SJakub Kicinski 	}
2868ab3f0063SJakub Kicinski 
2869fd7c211dSToke Høiland-Jørgensen 	if (type == BPF_PROG_TYPE_EXT && dst_prog &&
2870fd7c211dSToke Høiland-Jørgensen 	    bpf_prog_is_dev_bound(dst_prog->aux)) {
2871fd7c211dSToke Høiland-Jørgensen 		err = bpf_prog_dev_bound_inherit(prog, dst_prog);
2872cb4d2b3fSMartin KaFai Lau 		if (err)
28731b67772eSAndrii Nakryiko 			goto free_prog;
2874cb4d2b3fSMartin KaFai Lau 	}
2875cb4d2b3fSMartin KaFai Lau 
287619bfcdf9SDmitrii Dolgov 	/*
287719bfcdf9SDmitrii Dolgov 	 * Bookkeeping for managing the program attachment chain.
287819bfcdf9SDmitrii Dolgov 	 *
287919bfcdf9SDmitrii Dolgov 	 * It might be tempting to set attach_tracing_prog flag at the attachment
288019bfcdf9SDmitrii Dolgov 	 * time, but this will not prevent from loading bunch of tracing prog
288119bfcdf9SDmitrii Dolgov 	 * first, then attach them one to another.
288219bfcdf9SDmitrii Dolgov 	 *
288319bfcdf9SDmitrii Dolgov 	 * The flag attach_tracing_prog is set for the whole program lifecycle, and
288419bfcdf9SDmitrii Dolgov 	 * doesn't have to be cleared in bpf_tracing_link_release, since tracing
288519bfcdf9SDmitrii Dolgov 	 * programs cannot change attachment target.
288619bfcdf9SDmitrii Dolgov 	 */
288719bfcdf9SDmitrii Dolgov 	if (type == BPF_PROG_TYPE_TRACING && dst_prog &&
288819bfcdf9SDmitrii Dolgov 	    dst_prog->type == BPF_PROG_TYPE_TRACING) {
288919bfcdf9SDmitrii Dolgov 		prog->aux->attach_tracing_prog = true;
289019bfcdf9SDmitrii Dolgov 	}
289119bfcdf9SDmitrii Dolgov 
289209756af4SAlexei Starovoitov 	/* find program type: socket_filter vs tracing_filter */
289309756af4SAlexei Starovoitov 	err = find_prog_type(type, prog);
289409756af4SAlexei Starovoitov 	if (err < 0)
28951b67772eSAndrii Nakryiko 		goto free_prog;
289609756af4SAlexei Starovoitov 
28979285ec4cSJason A. Donenfeld 	prog->aux->load_time = ktime_get_boottime_ns();
28988e7ae251SMartin KaFai Lau 	err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name,
28998e7ae251SMartin KaFai Lau 			       sizeof(attr->prog_name));
29008e7ae251SMartin KaFai Lau 	if (err < 0)
29011b67772eSAndrii Nakryiko 		goto free_prog;
29021b67772eSAndrii Nakryiko 
29031b67772eSAndrii Nakryiko 	err = security_bpf_prog_load(prog, attr, token);
29041b67772eSAndrii Nakryiko 	if (err)
29053ac1f01bSRoman Gushchin 		goto free_prog_sec;
2906cb4d2b3fSMartin KaFai Lau 
290709756af4SAlexei Starovoitov 	/* run eBPF verifier */
290847a71c1fSAndrii Nakryiko 	err = bpf_check(&prog, attr, uattr, uattr_size);
290909756af4SAlexei Starovoitov 	if (err < 0)
291009756af4SAlexei Starovoitov 		goto free_used_maps;
291109756af4SAlexei Starovoitov 
2912d1c55ab5SDaniel Borkmann 	prog = bpf_prog_select_runtime(prog, &err);
291304fd61abSAlexei Starovoitov 	if (err < 0)
291404fd61abSAlexei Starovoitov 		goto free_used_maps;
291509756af4SAlexei Starovoitov 
2916dc4bb0e2SMartin KaFai Lau 	err = bpf_prog_alloc_id(prog);
2917dc4bb0e2SMartin KaFai Lau 	if (err)
2918dc4bb0e2SMartin KaFai Lau 		goto free_used_maps;
2919dc4bb0e2SMartin KaFai Lau 
2920c751798aSDaniel Borkmann 	/* Upon success of bpf_prog_alloc_id(), the BPF prog is
2921c751798aSDaniel Borkmann 	 * effectively publicly exposed. However, retrieving via
2922c751798aSDaniel Borkmann 	 * bpf_prog_get_fd_by_id() will take another reference,
2923c751798aSDaniel Borkmann 	 * therefore it cannot be gone underneath us.
2924c751798aSDaniel Borkmann 	 *
2925c751798aSDaniel Borkmann 	 * Only for the time /after/ successful bpf_prog_new_fd()
2926c751798aSDaniel Borkmann 	 * and before returning to userspace, we might just hold
2927c751798aSDaniel Borkmann 	 * one reference and any parallel close on that fd could
2928c751798aSDaniel Borkmann 	 * rip everything out. Hence, below notifications must
2929c751798aSDaniel Borkmann 	 * happen before bpf_prog_new_fd().
2930c751798aSDaniel Borkmann 	 *
2931c751798aSDaniel Borkmann 	 * Also, any failure handling from this point onwards must
2932c751798aSDaniel Borkmann 	 * be using bpf_prog_put() given the program is exposed.
2933b16d9aa4SMartin KaFai Lau 	 */
293474451e66SDaniel Borkmann 	bpf_prog_kallsyms_add(prog);
29356ee52e2aSSong Liu 	perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0);
2936bae141f5SDaniel Borkmann 	bpf_audit_prog(prog, BPF_AUDIT_LOAD);
2937c751798aSDaniel Borkmann 
2938c751798aSDaniel Borkmann 	err = bpf_prog_new_fd(prog);
2939c751798aSDaniel Borkmann 	if (err < 0)
2940c751798aSDaniel Borkmann 		bpf_prog_put(prog);
294109756af4SAlexei Starovoitov 	return err;
294209756af4SAlexei Starovoitov 
294309756af4SAlexei Starovoitov free_used_maps:
2944cd7455f1SDaniel Borkmann 	/* In case we have subprogs, we need to wait for a grace
2945cd7455f1SDaniel Borkmann 	 * period before we can tear down JIT memory since symbols
2946cd7455f1SDaniel Borkmann 	 * are already exposed under kallsyms.
2947cd7455f1SDaniel Borkmann 	 */
2948335d1c5bSKumar Kartikeya Dwivedi 	__bpf_prog_put_noref(prog, prog->aux->real_func_cnt);
2949cd7455f1SDaniel Borkmann 	return err;
29501b67772eSAndrii Nakryiko 
2951afdb09c7SChenbo Feng free_prog_sec:
29521b67772eSAndrii Nakryiko 	security_bpf_prog_free(prog);
2953d17aff80SAndrii Nakryiko free_prog:
29541b67772eSAndrii Nakryiko 	free_uid(prog->aux->user);
295522dc4a0fSAndrii Nakryiko 	if (prog->aux->attach_btf)
295622dc4a0fSAndrii Nakryiko 		btf_put(prog->aux->attach_btf);
295709756af4SAlexei Starovoitov 	bpf_prog_free(prog);
2958caf8f28eSAndrii Nakryiko put_token:
2959caf8f28eSAndrii Nakryiko 	bpf_token_put(token);
296009756af4SAlexei Starovoitov 	return err;
296109756af4SAlexei Starovoitov }
296209756af4SAlexei Starovoitov 
2963cb8edce2SAndrii Nakryiko #define BPF_OBJ_LAST_FIELD path_fd
2964b2197755SDaniel Borkmann 
2965b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr)
2966b2197755SDaniel Borkmann {
2967cb8edce2SAndrii Nakryiko 	int path_fd;
2968cb8edce2SAndrii Nakryiko 
2969cb8edce2SAndrii Nakryiko 	if (CHECK_ATTR(BPF_OBJ) || attr->file_flags & ~BPF_F_PATH_FD)
2970b2197755SDaniel Borkmann 		return -EINVAL;
2971b2197755SDaniel Borkmann 
2972cb8edce2SAndrii Nakryiko 	/* path_fd has to be accompanied by BPF_F_PATH_FD flag */
2973cb8edce2SAndrii Nakryiko 	if (!(attr->file_flags & BPF_F_PATH_FD) && attr->path_fd)
2974cb8edce2SAndrii Nakryiko 		return -EINVAL;
2975cb8edce2SAndrii Nakryiko 
2976cb8edce2SAndrii Nakryiko 	path_fd = attr->file_flags & BPF_F_PATH_FD ? attr->path_fd : AT_FDCWD;
2977cb8edce2SAndrii Nakryiko 	return bpf_obj_pin_user(attr->bpf_fd, path_fd,
2978cb8edce2SAndrii Nakryiko 				u64_to_user_ptr(attr->pathname));
2979b2197755SDaniel Borkmann }
2980b2197755SDaniel Borkmann 
2981b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr)
2982b2197755SDaniel Borkmann {
2983cb8edce2SAndrii Nakryiko 	int path_fd;
2984cb8edce2SAndrii Nakryiko 
29856e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0 ||
2986cb8edce2SAndrii Nakryiko 	    attr->file_flags & ~(BPF_OBJ_FLAG_MASK | BPF_F_PATH_FD))
2987b2197755SDaniel Borkmann 		return -EINVAL;
2988b2197755SDaniel Borkmann 
2989cb8edce2SAndrii Nakryiko 	/* path_fd has to be accompanied by BPF_F_PATH_FD flag */
2990cb8edce2SAndrii Nakryiko 	if (!(attr->file_flags & BPF_F_PATH_FD) && attr->path_fd)
2991cb8edce2SAndrii Nakryiko 		return -EINVAL;
2992cb8edce2SAndrii Nakryiko 
2993cb8edce2SAndrii Nakryiko 	path_fd = attr->file_flags & BPF_F_PATH_FD ? attr->path_fd : AT_FDCWD;
2994cb8edce2SAndrii Nakryiko 	return bpf_obj_get_user(path_fd, u64_to_user_ptr(attr->pathname),
29956e71b04aSChenbo Feng 				attr->file_flags);
2996b2197755SDaniel Borkmann }
2997b2197755SDaniel Borkmann 
2998f2e10bffSAndrii Nakryiko void bpf_link_init(struct bpf_link *link, enum bpf_link_type type,
2999a3b80e10SAndrii Nakryiko 		   const struct bpf_link_ops *ops, struct bpf_prog *prog)
300070ed506cSAndrii Nakryiko {
3001*2884dc7dSCong Wang 	WARN_ON(ops->dealloc && ops->dealloc_deferred);
300270ed506cSAndrii Nakryiko 	atomic64_set(&link->refcnt, 1);
3003f2e10bffSAndrii Nakryiko 	link->type = type;
3004a3b80e10SAndrii Nakryiko 	link->id = 0;
300570ed506cSAndrii Nakryiko 	link->ops = ops;
300670ed506cSAndrii Nakryiko 	link->prog = prog;
300770ed506cSAndrii Nakryiko }
300870ed506cSAndrii Nakryiko 
3009a3b80e10SAndrii Nakryiko static void bpf_link_free_id(int id)
3010a3b80e10SAndrii Nakryiko {
3011a3b80e10SAndrii Nakryiko 	if (!id)
3012a3b80e10SAndrii Nakryiko 		return;
3013a3b80e10SAndrii Nakryiko 
3014a3b80e10SAndrii Nakryiko 	spin_lock_bh(&link_idr_lock);
3015a3b80e10SAndrii Nakryiko 	idr_remove(&link_idr, id);
3016a3b80e10SAndrii Nakryiko 	spin_unlock_bh(&link_idr_lock);
3017a3b80e10SAndrii Nakryiko }
3018a3b80e10SAndrii Nakryiko 
301998868668SAndrii Nakryiko /* Clean up bpf_link and corresponding anon_inode file and FD. After
302098868668SAndrii Nakryiko  * anon_inode is created, bpf_link can't be just kfree()'d due to deferred
3021a3b80e10SAndrii Nakryiko  * anon_inode's release() call. This helper marks bpf_link as
3022a3b80e10SAndrii Nakryiko  * defunct, releases anon_inode file and puts reserved FD. bpf_prog's refcnt
3023a3b80e10SAndrii Nakryiko  * is not decremented, it's the responsibility of a calling code that failed
3024a3b80e10SAndrii Nakryiko  * to complete bpf_link initialization.
302589ae89f5SJiri Olsa  * This helper eventually calls link's dealloc callback, but does not call
302689ae89f5SJiri Olsa  * link's release callback.
302798868668SAndrii Nakryiko  */
3028a3b80e10SAndrii Nakryiko void bpf_link_cleanup(struct bpf_link_primer *primer)
3029babf3164SAndrii Nakryiko {
3030a3b80e10SAndrii Nakryiko 	primer->link->prog = NULL;
3031a3b80e10SAndrii Nakryiko 	bpf_link_free_id(primer->id);
3032a3b80e10SAndrii Nakryiko 	fput(primer->file);
3033a3b80e10SAndrii Nakryiko 	put_unused_fd(primer->fd);
3034babf3164SAndrii Nakryiko }
3035babf3164SAndrii Nakryiko 
303670ed506cSAndrii Nakryiko void bpf_link_inc(struct bpf_link *link)
303770ed506cSAndrii Nakryiko {
303870ed506cSAndrii Nakryiko 	atomic64_inc(&link->refcnt);
303970ed506cSAndrii Nakryiko }
304070ed506cSAndrii Nakryiko 
30411a80dbcbSAndrii Nakryiko static void bpf_link_defer_dealloc_rcu_gp(struct rcu_head *rcu)
30421a80dbcbSAndrii Nakryiko {
30431a80dbcbSAndrii Nakryiko 	struct bpf_link *link = container_of(rcu, struct bpf_link, rcu);
30441a80dbcbSAndrii Nakryiko 
30451a80dbcbSAndrii Nakryiko 	/* free bpf_link and its containing memory */
30461a80dbcbSAndrii Nakryiko 	link->ops->dealloc_deferred(link);
30471a80dbcbSAndrii Nakryiko }
30481a80dbcbSAndrii Nakryiko 
30491a80dbcbSAndrii Nakryiko static void bpf_link_defer_dealloc_mult_rcu_gp(struct rcu_head *rcu)
30501a80dbcbSAndrii Nakryiko {
30511a80dbcbSAndrii Nakryiko 	if (rcu_trace_implies_rcu_gp())
30521a80dbcbSAndrii Nakryiko 		bpf_link_defer_dealloc_rcu_gp(rcu);
30531a80dbcbSAndrii Nakryiko 	else
30541a80dbcbSAndrii Nakryiko 		call_rcu(rcu, bpf_link_defer_dealloc_rcu_gp);
30551a80dbcbSAndrii Nakryiko }
30561a80dbcbSAndrii Nakryiko 
305770ed506cSAndrii Nakryiko /* bpf_link_free is guaranteed to be called from process context */
305870ed506cSAndrii Nakryiko static void bpf_link_free(struct bpf_link *link)
305970ed506cSAndrii Nakryiko {
3060*2884dc7dSCong Wang 	const struct bpf_link_ops *ops = link->ops;
30611a80dbcbSAndrii Nakryiko 	bool sleepable = false;
30621a80dbcbSAndrii Nakryiko 
3063a3b80e10SAndrii Nakryiko 	bpf_link_free_id(link->id);
3064babf3164SAndrii Nakryiko 	if (link->prog) {
30651a80dbcbSAndrii Nakryiko 		sleepable = link->prog->sleepable;
3066babf3164SAndrii Nakryiko 		/* detach BPF program, clean up used resources */
3067*2884dc7dSCong Wang 		ops->release(link);
3068babf3164SAndrii Nakryiko 		bpf_prog_put(link->prog);
3069babf3164SAndrii Nakryiko 	}
3070*2884dc7dSCong Wang 	if (ops->dealloc_deferred) {
30711a80dbcbSAndrii Nakryiko 		/* schedule BPF link deallocation; if underlying BPF program
30721a80dbcbSAndrii Nakryiko 		 * is sleepable, we need to first wait for RCU tasks trace
30731a80dbcbSAndrii Nakryiko 		 * sync, then go through "classic" RCU grace period
30741a80dbcbSAndrii Nakryiko 		 */
30751a80dbcbSAndrii Nakryiko 		if (sleepable)
30761a80dbcbSAndrii Nakryiko 			call_rcu_tasks_trace(&link->rcu, bpf_link_defer_dealloc_mult_rcu_gp);
30771a80dbcbSAndrii Nakryiko 		else
30781a80dbcbSAndrii Nakryiko 			call_rcu(&link->rcu, bpf_link_defer_dealloc_rcu_gp);
3079*2884dc7dSCong Wang 	} else if (ops->dealloc)
3080*2884dc7dSCong Wang 		ops->dealloc(link);
308170ed506cSAndrii Nakryiko }
308270ed506cSAndrii Nakryiko 
308370ed506cSAndrii Nakryiko static void bpf_link_put_deferred(struct work_struct *work)
308470ed506cSAndrii Nakryiko {
308570ed506cSAndrii Nakryiko 	struct bpf_link *link = container_of(work, struct bpf_link, work);
308670ed506cSAndrii Nakryiko 
308770ed506cSAndrii Nakryiko 	bpf_link_free(link);
308870ed506cSAndrii Nakryiko }
308970ed506cSAndrii Nakryiko 
3090ab5d47bdSSebastian Andrzej Siewior /* bpf_link_put might be called from atomic context. It needs to be called
3091ab5d47bdSSebastian Andrzej Siewior  * from sleepable context in order to acquire sleeping locks during the process.
309270ed506cSAndrii Nakryiko  */
309370ed506cSAndrii Nakryiko void bpf_link_put(struct bpf_link *link)
309470ed506cSAndrii Nakryiko {
309570ed506cSAndrii Nakryiko 	if (!atomic64_dec_and_test(&link->refcnt))
309670ed506cSAndrii Nakryiko 		return;
309770ed506cSAndrii Nakryiko 
309870ed506cSAndrii Nakryiko 	INIT_WORK(&link->work, bpf_link_put_deferred);
309970ed506cSAndrii Nakryiko 	schedule_work(&link->work);
310070ed506cSAndrii Nakryiko }
3101cb80ddc6SAlexei Starovoitov EXPORT_SYMBOL(bpf_link_put);
310270ed506cSAndrii Nakryiko 
3103ab5d47bdSSebastian Andrzej Siewior static void bpf_link_put_direct(struct bpf_link *link)
3104ab5d47bdSSebastian Andrzej Siewior {
3105ab5d47bdSSebastian Andrzej Siewior 	if (!atomic64_dec_and_test(&link->refcnt))
3106ab5d47bdSSebastian Andrzej Siewior 		return;
3107ab5d47bdSSebastian Andrzej Siewior 	bpf_link_free(link);
3108ab5d47bdSSebastian Andrzej Siewior }
3109ab5d47bdSSebastian Andrzej Siewior 
311070ed506cSAndrii Nakryiko static int bpf_link_release(struct inode *inode, struct file *filp)
311170ed506cSAndrii Nakryiko {
311270ed506cSAndrii Nakryiko 	struct bpf_link *link = filp->private_data;
311370ed506cSAndrii Nakryiko 
3114ab5d47bdSSebastian Andrzej Siewior 	bpf_link_put_direct(link);
3115fec56f58SAlexei Starovoitov 	return 0;
3116fec56f58SAlexei Starovoitov }
3117fec56f58SAlexei Starovoitov 
311870ed506cSAndrii Nakryiko #ifdef CONFIG_PROC_FS
3119f2e10bffSAndrii Nakryiko #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type)
3120f2e10bffSAndrii Nakryiko #define BPF_MAP_TYPE(_id, _ops)
3121f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name) [_id] = #_name,
3122f2e10bffSAndrii Nakryiko static const char *bpf_link_type_strs[] = {
3123f2e10bffSAndrii Nakryiko 	[BPF_LINK_TYPE_UNSPEC] = "<invalid>",
3124f2e10bffSAndrii Nakryiko #include <linux/bpf_types.h>
3125f2e10bffSAndrii Nakryiko };
3126f2e10bffSAndrii Nakryiko #undef BPF_PROG_TYPE
3127f2e10bffSAndrii Nakryiko #undef BPF_MAP_TYPE
3128f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE
312970ed506cSAndrii Nakryiko 
313070ed506cSAndrii Nakryiko static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
313170ed506cSAndrii Nakryiko {
313270ed506cSAndrii Nakryiko 	const struct bpf_link *link = filp->private_data;
313370ed506cSAndrii Nakryiko 	const struct bpf_prog *prog = link->prog;
313470ed506cSAndrii Nakryiko 	char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
313570ed506cSAndrii Nakryiko 
313670ed506cSAndrii Nakryiko 	seq_printf(m,
313770ed506cSAndrii Nakryiko 		   "link_type:\t%s\n"
313868b04864SKui-Feng Lee 		   "link_id:\t%u\n",
313968b04864SKui-Feng Lee 		   bpf_link_type_strs[link->type],
314068b04864SKui-Feng Lee 		   link->id);
314168b04864SKui-Feng Lee 	if (prog) {
314268b04864SKui-Feng Lee 		bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
314368b04864SKui-Feng Lee 		seq_printf(m,
314470ed506cSAndrii Nakryiko 			   "prog_tag:\t%s\n"
314570ed506cSAndrii Nakryiko 			   "prog_id:\t%u\n",
314670ed506cSAndrii Nakryiko 			   prog_tag,
314770ed506cSAndrii Nakryiko 			   prog->aux->id);
314868b04864SKui-Feng Lee 	}
3149f2e10bffSAndrii Nakryiko 	if (link->ops->show_fdinfo)
3150f2e10bffSAndrii Nakryiko 		link->ops->show_fdinfo(link, m);
315170ed506cSAndrii Nakryiko }
315270ed506cSAndrii Nakryiko #endif
315370ed506cSAndrii Nakryiko 
31546f302bfbSZou Wei static const struct file_operations bpf_link_fops = {
315570ed506cSAndrii Nakryiko #ifdef CONFIG_PROC_FS
315670ed506cSAndrii Nakryiko 	.show_fdinfo	= bpf_link_show_fdinfo,
315770ed506cSAndrii Nakryiko #endif
315870ed506cSAndrii Nakryiko 	.release	= bpf_link_release,
3159fec56f58SAlexei Starovoitov 	.read		= bpf_dummy_read,
3160fec56f58SAlexei Starovoitov 	.write		= bpf_dummy_write,
3161fec56f58SAlexei Starovoitov };
3162fec56f58SAlexei Starovoitov 
3163a3b80e10SAndrii Nakryiko static int bpf_link_alloc_id(struct bpf_link *link)
316470ed506cSAndrii Nakryiko {
3165a3b80e10SAndrii Nakryiko 	int id;
3166a3b80e10SAndrii Nakryiko 
3167a3b80e10SAndrii Nakryiko 	idr_preload(GFP_KERNEL);
3168a3b80e10SAndrii Nakryiko 	spin_lock_bh(&link_idr_lock);
3169a3b80e10SAndrii Nakryiko 	id = idr_alloc_cyclic(&link_idr, link, 1, INT_MAX, GFP_ATOMIC);
3170a3b80e10SAndrii Nakryiko 	spin_unlock_bh(&link_idr_lock);
3171a3b80e10SAndrii Nakryiko 	idr_preload_end();
3172a3b80e10SAndrii Nakryiko 
3173a3b80e10SAndrii Nakryiko 	return id;
317470ed506cSAndrii Nakryiko }
317570ed506cSAndrii Nakryiko 
3176a3b80e10SAndrii Nakryiko /* Prepare bpf_link to be exposed to user-space by allocating anon_inode file,
3177a3b80e10SAndrii Nakryiko  * reserving unused FD and allocating ID from link_idr. This is to be paired
3178a3b80e10SAndrii Nakryiko  * with bpf_link_settle() to install FD and ID and expose bpf_link to
3179a3b80e10SAndrii Nakryiko  * user-space, if bpf_link is successfully attached. If not, bpf_link and
3180a3b80e10SAndrii Nakryiko  * pre-allocated resources are to be freed with bpf_cleanup() call. All the
3181a3b80e10SAndrii Nakryiko  * transient state is passed around in struct bpf_link_primer.
3182a3b80e10SAndrii Nakryiko  * This is preferred way to create and initialize bpf_link, especially when
3183a3b80e10SAndrii Nakryiko  * there are complicated and expensive operations in between creating bpf_link
3184a3b80e10SAndrii Nakryiko  * itself and attaching it to BPF hook. By using bpf_link_prime() and
3185a3b80e10SAndrii Nakryiko  * bpf_link_settle() kernel code using bpf_link doesn't have to perform
3186a3b80e10SAndrii Nakryiko  * expensive (and potentially failing) roll back operations in a rare case
3187a3b80e10SAndrii Nakryiko  * that file, FD, or ID can't be allocated.
3188babf3164SAndrii Nakryiko  */
3189a3b80e10SAndrii Nakryiko int bpf_link_prime(struct bpf_link *link, struct bpf_link_primer *primer)
3190babf3164SAndrii Nakryiko {
3191babf3164SAndrii Nakryiko 	struct file *file;
3192a3b80e10SAndrii Nakryiko 	int fd, id;
3193babf3164SAndrii Nakryiko 
3194babf3164SAndrii Nakryiko 	fd = get_unused_fd_flags(O_CLOEXEC);
3195babf3164SAndrii Nakryiko 	if (fd < 0)
3196a3b80e10SAndrii Nakryiko 		return fd;
3197babf3164SAndrii Nakryiko 
3198babf3164SAndrii Nakryiko 
3199a3b80e10SAndrii Nakryiko 	id = bpf_link_alloc_id(link);
3200a3b80e10SAndrii Nakryiko 	if (id < 0) {
3201a3b80e10SAndrii Nakryiko 		put_unused_fd(fd);
3202a3b80e10SAndrii Nakryiko 		return id;
3203a3b80e10SAndrii Nakryiko 	}
3204babf3164SAndrii Nakryiko 
3205babf3164SAndrii Nakryiko 	file = anon_inode_getfile("bpf_link", &bpf_link_fops, link, O_CLOEXEC);
3206babf3164SAndrii Nakryiko 	if (IS_ERR(file)) {
3207138c6767SAndrii Nakryiko 		bpf_link_free_id(id);
3208babf3164SAndrii Nakryiko 		put_unused_fd(fd);
3209138c6767SAndrii Nakryiko 		return PTR_ERR(file);
3210babf3164SAndrii Nakryiko 	}
3211babf3164SAndrii Nakryiko 
3212a3b80e10SAndrii Nakryiko 	primer->link = link;
3213a3b80e10SAndrii Nakryiko 	primer->file = file;
3214a3b80e10SAndrii Nakryiko 	primer->fd = fd;
3215a3b80e10SAndrii Nakryiko 	primer->id = id;
3216a3b80e10SAndrii Nakryiko 	return 0;
3217a3b80e10SAndrii Nakryiko }
3218a3b80e10SAndrii Nakryiko 
3219a3b80e10SAndrii Nakryiko int bpf_link_settle(struct bpf_link_primer *primer)
3220a3b80e10SAndrii Nakryiko {
3221a3b80e10SAndrii Nakryiko 	/* make bpf_link fetchable by ID */
3222a3b80e10SAndrii Nakryiko 	spin_lock_bh(&link_idr_lock);
3223a3b80e10SAndrii Nakryiko 	primer->link->id = primer->id;
3224a3b80e10SAndrii Nakryiko 	spin_unlock_bh(&link_idr_lock);
3225a3b80e10SAndrii Nakryiko 	/* make bpf_link fetchable by FD */
3226a3b80e10SAndrii Nakryiko 	fd_install(primer->fd, primer->file);
3227a3b80e10SAndrii Nakryiko 	/* pass through installed FD */
3228a3b80e10SAndrii Nakryiko 	return primer->fd;
3229a3b80e10SAndrii Nakryiko }
3230a3b80e10SAndrii Nakryiko 
3231a3b80e10SAndrii Nakryiko int bpf_link_new_fd(struct bpf_link *link)
3232a3b80e10SAndrii Nakryiko {
3233a3b80e10SAndrii Nakryiko 	return anon_inode_getfd("bpf-link", &bpf_link_fops, link, O_CLOEXEC);
3234babf3164SAndrii Nakryiko }
3235babf3164SAndrii Nakryiko 
323670ed506cSAndrii Nakryiko struct bpf_link *bpf_link_get_from_fd(u32 ufd)
323770ed506cSAndrii Nakryiko {
323870ed506cSAndrii Nakryiko 	struct fd f = fdget(ufd);
323970ed506cSAndrii Nakryiko 	struct bpf_link *link;
324070ed506cSAndrii Nakryiko 
324170ed506cSAndrii Nakryiko 	if (!f.file)
324270ed506cSAndrii Nakryiko 		return ERR_PTR(-EBADF);
324370ed506cSAndrii Nakryiko 	if (f.file->f_op != &bpf_link_fops) {
324470ed506cSAndrii Nakryiko 		fdput(f);
324570ed506cSAndrii Nakryiko 		return ERR_PTR(-EINVAL);
324670ed506cSAndrii Nakryiko 	}
324770ed506cSAndrii Nakryiko 
324870ed506cSAndrii Nakryiko 	link = f.file->private_data;
324970ed506cSAndrii Nakryiko 	bpf_link_inc(link);
325070ed506cSAndrii Nakryiko 	fdput(f);
325170ed506cSAndrii Nakryiko 
325270ed506cSAndrii Nakryiko 	return link;
325370ed506cSAndrii Nakryiko }
3254cb80ddc6SAlexei Starovoitov EXPORT_SYMBOL(bpf_link_get_from_fd);
325570ed506cSAndrii Nakryiko 
325670ed506cSAndrii Nakryiko static void bpf_tracing_link_release(struct bpf_link *link)
325770ed506cSAndrii Nakryiko {
32583aac1eadSToke Høiland-Jørgensen 	struct bpf_tracing_link *tr_link =
3259f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
32603aac1eadSToke Høiland-Jørgensen 
3261f7e0beafSKui-Feng Lee 	WARN_ON_ONCE(bpf_trampoline_unlink_prog(&tr_link->link,
32623aac1eadSToke Høiland-Jørgensen 						tr_link->trampoline));
32633aac1eadSToke Høiland-Jørgensen 
32643aac1eadSToke Høiland-Jørgensen 	bpf_trampoline_put(tr_link->trampoline);
32653aac1eadSToke Høiland-Jørgensen 
32663aac1eadSToke Høiland-Jørgensen 	/* tgt_prog is NULL if target is a kernel function */
32673aac1eadSToke Høiland-Jørgensen 	if (tr_link->tgt_prog)
32683aac1eadSToke Høiland-Jørgensen 		bpf_prog_put(tr_link->tgt_prog);
3269babf3164SAndrii Nakryiko }
3270babf3164SAndrii Nakryiko 
3271babf3164SAndrii Nakryiko static void bpf_tracing_link_dealloc(struct bpf_link *link)
3272babf3164SAndrii Nakryiko {
327370ed506cSAndrii Nakryiko 	struct bpf_tracing_link *tr_link =
3274f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
327570ed506cSAndrii Nakryiko 
327670ed506cSAndrii Nakryiko 	kfree(tr_link);
327770ed506cSAndrii Nakryiko }
327870ed506cSAndrii Nakryiko 
3279f2e10bffSAndrii Nakryiko static void bpf_tracing_link_show_fdinfo(const struct bpf_link *link,
3280f2e10bffSAndrii Nakryiko 					 struct seq_file *seq)
3281f2e10bffSAndrii Nakryiko {
3282f2e10bffSAndrii Nakryiko 	struct bpf_tracing_link *tr_link =
3283f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
3284e859e429SYafang Shao 	u32 target_btf_id, target_obj_id;
3285f2e10bffSAndrii Nakryiko 
3286e859e429SYafang Shao 	bpf_trampoline_unpack_key(tr_link->trampoline->key,
3287e859e429SYafang Shao 				  &target_obj_id, &target_btf_id);
3288f2e10bffSAndrii Nakryiko 	seq_printf(seq,
3289e859e429SYafang Shao 		   "attach_type:\t%d\n"
3290e859e429SYafang Shao 		   "target_obj_id:\t%u\n"
3291e859e429SYafang Shao 		   "target_btf_id:\t%u\n",
3292e859e429SYafang Shao 		   tr_link->attach_type,
3293e859e429SYafang Shao 		   target_obj_id,
3294e859e429SYafang Shao 		   target_btf_id);
3295f2e10bffSAndrii Nakryiko }
3296f2e10bffSAndrii Nakryiko 
3297f2e10bffSAndrii Nakryiko static int bpf_tracing_link_fill_link_info(const struct bpf_link *link,
3298f2e10bffSAndrii Nakryiko 					   struct bpf_link_info *info)
3299f2e10bffSAndrii Nakryiko {
3300f2e10bffSAndrii Nakryiko 	struct bpf_tracing_link *tr_link =
3301f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
3302f2e10bffSAndrii Nakryiko 
3303f2e10bffSAndrii Nakryiko 	info->tracing.attach_type = tr_link->attach_type;
3304441e8c66SToke Høiland-Jørgensen 	bpf_trampoline_unpack_key(tr_link->trampoline->key,
3305441e8c66SToke Høiland-Jørgensen 				  &info->tracing.target_obj_id,
3306441e8c66SToke Høiland-Jørgensen 				  &info->tracing.target_btf_id);
3307f2e10bffSAndrii Nakryiko 
3308f2e10bffSAndrii Nakryiko 	return 0;
3309f2e10bffSAndrii Nakryiko }
3310f2e10bffSAndrii Nakryiko 
331170ed506cSAndrii Nakryiko static const struct bpf_link_ops bpf_tracing_link_lops = {
331270ed506cSAndrii Nakryiko 	.release = bpf_tracing_link_release,
3313babf3164SAndrii Nakryiko 	.dealloc = bpf_tracing_link_dealloc,
3314f2e10bffSAndrii Nakryiko 	.show_fdinfo = bpf_tracing_link_show_fdinfo,
3315f2e10bffSAndrii Nakryiko 	.fill_link_info = bpf_tracing_link_fill_link_info,
331670ed506cSAndrii Nakryiko };
331770ed506cSAndrii Nakryiko 
33184a1e7c0cSToke Høiland-Jørgensen static int bpf_tracing_prog_attach(struct bpf_prog *prog,
33194a1e7c0cSToke Høiland-Jørgensen 				   int tgt_prog_fd,
33202fcc8241SKui-Feng Lee 				   u32 btf_id,
33212fcc8241SKui-Feng Lee 				   u64 bpf_cookie)
3322fec56f58SAlexei Starovoitov {
3323a3b80e10SAndrii Nakryiko 	struct bpf_link_primer link_primer;
33243aac1eadSToke Høiland-Jørgensen 	struct bpf_prog *tgt_prog = NULL;
33254a1e7c0cSToke Høiland-Jørgensen 	struct bpf_trampoline *tr = NULL;
332670ed506cSAndrii Nakryiko 	struct bpf_tracing_link *link;
33274a1e7c0cSToke Høiland-Jørgensen 	u64 key = 0;
3328a3b80e10SAndrii Nakryiko 	int err;
3329fec56f58SAlexei Starovoitov 
33309e4e01dfSKP Singh 	switch (prog->type) {
33319e4e01dfSKP Singh 	case BPF_PROG_TYPE_TRACING:
3332fec56f58SAlexei Starovoitov 		if (prog->expected_attach_type != BPF_TRACE_FENTRY &&
3333be8704ffSAlexei Starovoitov 		    prog->expected_attach_type != BPF_TRACE_FEXIT &&
33349e4e01dfSKP Singh 		    prog->expected_attach_type != BPF_MODIFY_RETURN) {
33359e4e01dfSKP Singh 			err = -EINVAL;
33369e4e01dfSKP Singh 			goto out_put_prog;
33379e4e01dfSKP Singh 		}
33389e4e01dfSKP Singh 		break;
33399e4e01dfSKP Singh 	case BPF_PROG_TYPE_EXT:
33409e4e01dfSKP Singh 		if (prog->expected_attach_type != 0) {
33419e4e01dfSKP Singh 			err = -EINVAL;
33429e4e01dfSKP Singh 			goto out_put_prog;
33439e4e01dfSKP Singh 		}
33449e4e01dfSKP Singh 		break;
33459e4e01dfSKP Singh 	case BPF_PROG_TYPE_LSM:
33469e4e01dfSKP Singh 		if (prog->expected_attach_type != BPF_LSM_MAC) {
33479e4e01dfSKP Singh 			err = -EINVAL;
33489e4e01dfSKP Singh 			goto out_put_prog;
33499e4e01dfSKP Singh 		}
33509e4e01dfSKP Singh 		break;
33519e4e01dfSKP Singh 	default:
3352fec56f58SAlexei Starovoitov 		err = -EINVAL;
3353fec56f58SAlexei Starovoitov 		goto out_put_prog;
3354fec56f58SAlexei Starovoitov 	}
3355fec56f58SAlexei Starovoitov 
33564a1e7c0cSToke Høiland-Jørgensen 	if (!!tgt_prog_fd != !!btf_id) {
33574a1e7c0cSToke Høiland-Jørgensen 		err = -EINVAL;
33584a1e7c0cSToke Høiland-Jørgensen 		goto out_put_prog;
33594a1e7c0cSToke Høiland-Jørgensen 	}
33604a1e7c0cSToke Høiland-Jørgensen 
33614a1e7c0cSToke Høiland-Jørgensen 	if (tgt_prog_fd) {
336219bfcdf9SDmitrii Dolgov 		/*
336319bfcdf9SDmitrii Dolgov 		 * For now we only allow new targets for BPF_PROG_TYPE_EXT. If this
336419bfcdf9SDmitrii Dolgov 		 * part would be changed to implement the same for
336519bfcdf9SDmitrii Dolgov 		 * BPF_PROG_TYPE_TRACING, do not forget to update the way how
336619bfcdf9SDmitrii Dolgov 		 * attach_tracing_prog flag is set.
336719bfcdf9SDmitrii Dolgov 		 */
33684a1e7c0cSToke Høiland-Jørgensen 		if (prog->type != BPF_PROG_TYPE_EXT) {
33694a1e7c0cSToke Høiland-Jørgensen 			err = -EINVAL;
33704a1e7c0cSToke Høiland-Jørgensen 			goto out_put_prog;
33714a1e7c0cSToke Høiland-Jørgensen 		}
33724a1e7c0cSToke Høiland-Jørgensen 
33734a1e7c0cSToke Høiland-Jørgensen 		tgt_prog = bpf_prog_get(tgt_prog_fd);
33744a1e7c0cSToke Høiland-Jørgensen 		if (IS_ERR(tgt_prog)) {
33754a1e7c0cSToke Høiland-Jørgensen 			err = PTR_ERR(tgt_prog);
33764a1e7c0cSToke Høiland-Jørgensen 			tgt_prog = NULL;
33774a1e7c0cSToke Høiland-Jørgensen 			goto out_put_prog;
33784a1e7c0cSToke Høiland-Jørgensen 		}
33794a1e7c0cSToke Høiland-Jørgensen 
338022dc4a0fSAndrii Nakryiko 		key = bpf_trampoline_compute_key(tgt_prog, NULL, btf_id);
33814a1e7c0cSToke Høiland-Jørgensen 	}
33824a1e7c0cSToke Høiland-Jørgensen 
338370ed506cSAndrii Nakryiko 	link = kzalloc(sizeof(*link), GFP_USER);
338470ed506cSAndrii Nakryiko 	if (!link) {
338570ed506cSAndrii Nakryiko 		err = -ENOMEM;
3386fec56f58SAlexei Starovoitov 		goto out_put_prog;
3387fec56f58SAlexei Starovoitov 	}
3388f7e0beafSKui-Feng Lee 	bpf_link_init(&link->link.link, BPF_LINK_TYPE_TRACING,
3389f2e10bffSAndrii Nakryiko 		      &bpf_tracing_link_lops, prog);
3390f2e10bffSAndrii Nakryiko 	link->attach_type = prog->expected_attach_type;
33912fcc8241SKui-Feng Lee 	link->link.cookie = bpf_cookie;
3392fec56f58SAlexei Starovoitov 
33933aac1eadSToke Høiland-Jørgensen 	mutex_lock(&prog->aux->dst_mutex);
3394babf3164SAndrii Nakryiko 
33954a1e7c0cSToke Høiland-Jørgensen 	/* There are a few possible cases here:
33964a1e7c0cSToke Høiland-Jørgensen 	 *
33974a1e7c0cSToke Høiland-Jørgensen 	 * - if prog->aux->dst_trampoline is set, the program was just loaded
33984a1e7c0cSToke Høiland-Jørgensen 	 *   and not yet attached to anything, so we can use the values stored
33994a1e7c0cSToke Høiland-Jørgensen 	 *   in prog->aux
34004a1e7c0cSToke Høiland-Jørgensen 	 *
34014a1e7c0cSToke Høiland-Jørgensen 	 * - if prog->aux->dst_trampoline is NULL, the program has already been
34024a1e7c0cSToke Høiland-Jørgensen          *   attached to a target and its initial target was cleared (below)
34034a1e7c0cSToke Høiland-Jørgensen 	 *
34044a1e7c0cSToke Høiland-Jørgensen 	 * - if tgt_prog != NULL, the caller specified tgt_prog_fd +
34054a1e7c0cSToke Høiland-Jørgensen 	 *   target_btf_id using the link_create API.
34064a1e7c0cSToke Høiland-Jørgensen 	 *
34074a1e7c0cSToke Høiland-Jørgensen 	 * - if tgt_prog == NULL when this function was called using the old
34084a1e7c0cSToke Høiland-Jørgensen 	 *   raw_tracepoint_open API, and we need a target from prog->aux
34094a1e7c0cSToke Høiland-Jørgensen 	 *
3410f3a95075SJiri Olsa 	 * - if prog->aux->dst_trampoline and tgt_prog is NULL, the program
3411f3a95075SJiri Olsa 	 *   was detached and is going for re-attachment.
3412715d82baSJiri Olsa 	 *
3413715d82baSJiri Olsa 	 * - if prog->aux->dst_trampoline is NULL and tgt_prog and prog->aux->attach_btf
3414715d82baSJiri Olsa 	 *   are NULL, then program was already attached and user did not provide
3415715d82baSJiri Olsa 	 *   tgt_prog_fd so we have no way to find out or create trampoline
34164a1e7c0cSToke Høiland-Jørgensen 	 */
34174a1e7c0cSToke Høiland-Jørgensen 	if (!prog->aux->dst_trampoline && !tgt_prog) {
3418f3a95075SJiri Olsa 		/*
3419f3a95075SJiri Olsa 		 * Allow re-attach for TRACING and LSM programs. If it's
3420f3a95075SJiri Olsa 		 * currently linked, bpf_trampoline_link_prog will fail.
3421f3a95075SJiri Olsa 		 * EXT programs need to specify tgt_prog_fd, so they
3422f3a95075SJiri Olsa 		 * re-attach in separate code path.
3423f3a95075SJiri Olsa 		 */
3424f3a95075SJiri Olsa 		if (prog->type != BPF_PROG_TYPE_TRACING &&
3425f3a95075SJiri Olsa 		    prog->type != BPF_PROG_TYPE_LSM) {
3426f3a95075SJiri Olsa 			err = -EINVAL;
34273aac1eadSToke Høiland-Jørgensen 			goto out_unlock;
34283aac1eadSToke Høiland-Jørgensen 		}
3429715d82baSJiri Olsa 		/* We can allow re-attach only if we have valid attach_btf. */
3430715d82baSJiri Olsa 		if (!prog->aux->attach_btf) {
3431715d82baSJiri Olsa 			err = -EINVAL;
3432715d82baSJiri Olsa 			goto out_unlock;
3433715d82baSJiri Olsa 		}
3434f3a95075SJiri Olsa 		btf_id = prog->aux->attach_btf_id;
3435f3a95075SJiri Olsa 		key = bpf_trampoline_compute_key(NULL, prog->aux->attach_btf, btf_id);
3436f3a95075SJiri Olsa 	}
34374a1e7c0cSToke Høiland-Jørgensen 
34384a1e7c0cSToke Høiland-Jørgensen 	if (!prog->aux->dst_trampoline ||
34394a1e7c0cSToke Høiland-Jørgensen 	    (key && key != prog->aux->dst_trampoline->key)) {
34404a1e7c0cSToke Høiland-Jørgensen 		/* If there is no saved target, or the specified target is
34414a1e7c0cSToke Høiland-Jørgensen 		 * different from the destination specified at load time, we
34424a1e7c0cSToke Høiland-Jørgensen 		 * need a new trampoline and a check for compatibility
34434a1e7c0cSToke Høiland-Jørgensen 		 */
34444a1e7c0cSToke Høiland-Jørgensen 		struct bpf_attach_target_info tgt_info = {};
34454a1e7c0cSToke Høiland-Jørgensen 
34464a1e7c0cSToke Høiland-Jørgensen 		err = bpf_check_attach_target(NULL, prog, tgt_prog, btf_id,
34474a1e7c0cSToke Høiland-Jørgensen 					      &tgt_info);
34484a1e7c0cSToke Høiland-Jørgensen 		if (err)
34494a1e7c0cSToke Høiland-Jørgensen 			goto out_unlock;
34504a1e7c0cSToke Høiland-Jørgensen 
345131bf1dbcSViktor Malik 		if (tgt_info.tgt_mod) {
345231bf1dbcSViktor Malik 			module_put(prog->aux->mod);
345331bf1dbcSViktor Malik 			prog->aux->mod = tgt_info.tgt_mod;
345431bf1dbcSViktor Malik 		}
345531bf1dbcSViktor Malik 
34564a1e7c0cSToke Høiland-Jørgensen 		tr = bpf_trampoline_get(key, &tgt_info);
34574a1e7c0cSToke Høiland-Jørgensen 		if (!tr) {
34584a1e7c0cSToke Høiland-Jørgensen 			err = -ENOMEM;
34594a1e7c0cSToke Høiland-Jørgensen 			goto out_unlock;
34604a1e7c0cSToke Høiland-Jørgensen 		}
34614a1e7c0cSToke Høiland-Jørgensen 	} else {
34624a1e7c0cSToke Høiland-Jørgensen 		/* The caller didn't specify a target, or the target was the
34634a1e7c0cSToke Høiland-Jørgensen 		 * same as the destination supplied during program load. This
34644a1e7c0cSToke Høiland-Jørgensen 		 * means we can reuse the trampoline and reference from program
34654a1e7c0cSToke Høiland-Jørgensen 		 * load time, and there is no need to allocate a new one. This
34664a1e7c0cSToke Høiland-Jørgensen 		 * can only happen once for any program, as the saved values in
34674a1e7c0cSToke Høiland-Jørgensen 		 * prog->aux are cleared below.
34684a1e7c0cSToke Høiland-Jørgensen 		 */
34693aac1eadSToke Høiland-Jørgensen 		tr = prog->aux->dst_trampoline;
34703aac1eadSToke Høiland-Jørgensen 		tgt_prog = prog->aux->dst_prog;
34714a1e7c0cSToke Høiland-Jørgensen 	}
34723aac1eadSToke Høiland-Jørgensen 
3473f7e0beafSKui-Feng Lee 	err = bpf_link_prime(&link->link.link, &link_primer);
34743aac1eadSToke Høiland-Jørgensen 	if (err)
34753aac1eadSToke Høiland-Jørgensen 		goto out_unlock;
34763aac1eadSToke Høiland-Jørgensen 
3477f7e0beafSKui-Feng Lee 	err = bpf_trampoline_link_prog(&link->link, tr);
3478babf3164SAndrii Nakryiko 	if (err) {
3479a3b80e10SAndrii Nakryiko 		bpf_link_cleanup(&link_primer);
34803aac1eadSToke Høiland-Jørgensen 		link = NULL;
34813aac1eadSToke Høiland-Jørgensen 		goto out_unlock;
3482babf3164SAndrii Nakryiko 	}
3483babf3164SAndrii Nakryiko 
34843aac1eadSToke Høiland-Jørgensen 	link->tgt_prog = tgt_prog;
34853aac1eadSToke Høiland-Jørgensen 	link->trampoline = tr;
34863aac1eadSToke Høiland-Jørgensen 
34874a1e7c0cSToke Høiland-Jørgensen 	/* Always clear the trampoline and target prog from prog->aux to make
34884a1e7c0cSToke Høiland-Jørgensen 	 * sure the original attach destination is not kept alive after a
34894a1e7c0cSToke Høiland-Jørgensen 	 * program is (re-)attached to another target.
34904a1e7c0cSToke Høiland-Jørgensen 	 */
34914a1e7c0cSToke Høiland-Jørgensen 	if (prog->aux->dst_prog &&
34924a1e7c0cSToke Høiland-Jørgensen 	    (tgt_prog_fd || tr != prog->aux->dst_trampoline))
34934a1e7c0cSToke Høiland-Jørgensen 		/* got extra prog ref from syscall, or attaching to different prog */
34944a1e7c0cSToke Høiland-Jørgensen 		bpf_prog_put(prog->aux->dst_prog);
34954a1e7c0cSToke Høiland-Jørgensen 	if (prog->aux->dst_trampoline && tr != prog->aux->dst_trampoline)
34964a1e7c0cSToke Høiland-Jørgensen 		/* we allocated a new trampoline, so free the old one */
34974a1e7c0cSToke Høiland-Jørgensen 		bpf_trampoline_put(prog->aux->dst_trampoline);
34984a1e7c0cSToke Høiland-Jørgensen 
34993aac1eadSToke Høiland-Jørgensen 	prog->aux->dst_prog = NULL;
35003aac1eadSToke Høiland-Jørgensen 	prog->aux->dst_trampoline = NULL;
35013aac1eadSToke Høiland-Jørgensen 	mutex_unlock(&prog->aux->dst_mutex);
35023aac1eadSToke Høiland-Jørgensen 
3503a3b80e10SAndrii Nakryiko 	return bpf_link_settle(&link_primer);
35043aac1eadSToke Høiland-Jørgensen out_unlock:
35054a1e7c0cSToke Høiland-Jørgensen 	if (tr && tr != prog->aux->dst_trampoline)
35064a1e7c0cSToke Høiland-Jørgensen 		bpf_trampoline_put(tr);
35073aac1eadSToke Høiland-Jørgensen 	mutex_unlock(&prog->aux->dst_mutex);
35083aac1eadSToke Høiland-Jørgensen 	kfree(link);
3509fec56f58SAlexei Starovoitov out_put_prog:
35104a1e7c0cSToke Høiland-Jørgensen 	if (tgt_prog_fd && tgt_prog)
35114a1e7c0cSToke Høiland-Jørgensen 		bpf_prog_put(tgt_prog);
3512fec56f58SAlexei Starovoitov 	return err;
3513fec56f58SAlexei Starovoitov }
3514fec56f58SAlexei Starovoitov 
351570ed506cSAndrii Nakryiko static void bpf_raw_tp_link_release(struct bpf_link *link)
3516c4f6699dSAlexei Starovoitov {
351770ed506cSAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp =
351870ed506cSAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3519c4f6699dSAlexei Starovoitov 
3520d4dfc570SAndrii Nakryiko 	bpf_probe_unregister(raw_tp->btp, raw_tp);
3521a38d1107SMatt Mullins 	bpf_put_raw_tracepoint(raw_tp->btp);
3522babf3164SAndrii Nakryiko }
3523babf3164SAndrii Nakryiko 
3524babf3164SAndrii Nakryiko static void bpf_raw_tp_link_dealloc(struct bpf_link *link)
3525babf3164SAndrii Nakryiko {
3526babf3164SAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp =
3527babf3164SAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3528babf3164SAndrii Nakryiko 
3529c4f6699dSAlexei Starovoitov 	kfree(raw_tp);
3530c4f6699dSAlexei Starovoitov }
3531c4f6699dSAlexei Starovoitov 
3532f2e10bffSAndrii Nakryiko static void bpf_raw_tp_link_show_fdinfo(const struct bpf_link *link,
3533f2e10bffSAndrii Nakryiko 					struct seq_file *seq)
3534f2e10bffSAndrii Nakryiko {
3535f2e10bffSAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp_link =
3536f2e10bffSAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3537f2e10bffSAndrii Nakryiko 
3538f2e10bffSAndrii Nakryiko 	seq_printf(seq,
3539f2e10bffSAndrii Nakryiko 		   "tp_name:\t%s\n",
3540f2e10bffSAndrii Nakryiko 		   raw_tp_link->btp->tp->name);
3541f2e10bffSAndrii Nakryiko }
3542f2e10bffSAndrii Nakryiko 
354357d48537SYafang Shao static int bpf_copy_to_user(char __user *ubuf, const char *buf, u32 ulen,
354457d48537SYafang Shao 			    u32 len)
354557d48537SYafang Shao {
354657d48537SYafang Shao 	if (ulen >= len + 1) {
354757d48537SYafang Shao 		if (copy_to_user(ubuf, buf, len + 1))
354857d48537SYafang Shao 			return -EFAULT;
354957d48537SYafang Shao 	} else {
355057d48537SYafang Shao 		char zero = '\0';
355157d48537SYafang Shao 
355257d48537SYafang Shao 		if (copy_to_user(ubuf, buf, ulen - 1))
355357d48537SYafang Shao 			return -EFAULT;
355457d48537SYafang Shao 		if (put_user(zero, ubuf + ulen - 1))
355557d48537SYafang Shao 			return -EFAULT;
355657d48537SYafang Shao 		return -ENOSPC;
355757d48537SYafang Shao 	}
355857d48537SYafang Shao 
355957d48537SYafang Shao 	return 0;
356057d48537SYafang Shao }
356157d48537SYafang Shao 
3562f2e10bffSAndrii Nakryiko static int bpf_raw_tp_link_fill_link_info(const struct bpf_link *link,
3563f2e10bffSAndrii Nakryiko 					  struct bpf_link_info *info)
3564f2e10bffSAndrii Nakryiko {
3565f2e10bffSAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp_link =
3566f2e10bffSAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3567f2e10bffSAndrii Nakryiko 	char __user *ubuf = u64_to_user_ptr(info->raw_tracepoint.tp_name);
3568f2e10bffSAndrii Nakryiko 	const char *tp_name = raw_tp_link->btp->tp->name;
3569f2e10bffSAndrii Nakryiko 	u32 ulen = info->raw_tracepoint.tp_name_len;
3570f2e10bffSAndrii Nakryiko 	size_t tp_len = strlen(tp_name);
3571f2e10bffSAndrii Nakryiko 
3572b474959dSYonghong Song 	if (!ulen ^ !ubuf)
3573f2e10bffSAndrii Nakryiko 		return -EINVAL;
3574f2e10bffSAndrii Nakryiko 
3575f2e10bffSAndrii Nakryiko 	info->raw_tracepoint.tp_name_len = tp_len + 1;
3576f2e10bffSAndrii Nakryiko 
3577f2e10bffSAndrii Nakryiko 	if (!ubuf)
3578f2e10bffSAndrii Nakryiko 		return 0;
3579f2e10bffSAndrii Nakryiko 
358057d48537SYafang Shao 	return bpf_copy_to_user(ubuf, tp_name, ulen, tp_len);
3581f2e10bffSAndrii Nakryiko }
3582f2e10bffSAndrii Nakryiko 
3583a3b80e10SAndrii Nakryiko static const struct bpf_link_ops bpf_raw_tp_link_lops = {
358470ed506cSAndrii Nakryiko 	.release = bpf_raw_tp_link_release,
35851a80dbcbSAndrii Nakryiko 	.dealloc_deferred = bpf_raw_tp_link_dealloc,
3586f2e10bffSAndrii Nakryiko 	.show_fdinfo = bpf_raw_tp_link_show_fdinfo,
3587f2e10bffSAndrii Nakryiko 	.fill_link_info = bpf_raw_tp_link_fill_link_info,
3588c4f6699dSAlexei Starovoitov };
3589c4f6699dSAlexei Starovoitov 
3590b89fbfbbSAndrii Nakryiko #ifdef CONFIG_PERF_EVENTS
3591b89fbfbbSAndrii Nakryiko struct bpf_perf_link {
3592b89fbfbbSAndrii Nakryiko 	struct bpf_link link;
3593b89fbfbbSAndrii Nakryiko 	struct file *perf_file;
3594b89fbfbbSAndrii Nakryiko };
3595b89fbfbbSAndrii Nakryiko 
3596b89fbfbbSAndrii Nakryiko static void bpf_perf_link_release(struct bpf_link *link)
3597b89fbfbbSAndrii Nakryiko {
3598b89fbfbbSAndrii Nakryiko 	struct bpf_perf_link *perf_link = container_of(link, struct bpf_perf_link, link);
3599b89fbfbbSAndrii Nakryiko 	struct perf_event *event = perf_link->perf_file->private_data;
3600b89fbfbbSAndrii Nakryiko 
3601b89fbfbbSAndrii Nakryiko 	perf_event_free_bpf_prog(event);
3602b89fbfbbSAndrii Nakryiko 	fput(perf_link->perf_file);
3603b89fbfbbSAndrii Nakryiko }
3604b89fbfbbSAndrii Nakryiko 
3605b89fbfbbSAndrii Nakryiko static void bpf_perf_link_dealloc(struct bpf_link *link)
3606b89fbfbbSAndrii Nakryiko {
3607b89fbfbbSAndrii Nakryiko 	struct bpf_perf_link *perf_link = container_of(link, struct bpf_perf_link, link);
3608b89fbfbbSAndrii Nakryiko 
3609b89fbfbbSAndrii Nakryiko 	kfree(perf_link);
3610b89fbfbbSAndrii Nakryiko }
3611b89fbfbbSAndrii Nakryiko 
36121b715e1bSYafang Shao static int bpf_perf_link_fill_common(const struct perf_event *event,
36131b715e1bSYafang Shao 				     char __user *uname, u32 ulen,
36141b715e1bSYafang Shao 				     u64 *probe_offset, u64 *probe_addr,
36153acf8aceSJiri Olsa 				     u32 *fd_type, unsigned long *missed)
36161b715e1bSYafang Shao {
36171b715e1bSYafang Shao 	const char *buf;
36181b715e1bSYafang Shao 	u32 prog_id;
36191b715e1bSYafang Shao 	size_t len;
36201b715e1bSYafang Shao 	int err;
36211b715e1bSYafang Shao 
36221b715e1bSYafang Shao 	if (!ulen ^ !uname)
36231b715e1bSYafang Shao 		return -EINVAL;
36241b715e1bSYafang Shao 
36251b715e1bSYafang Shao 	err = bpf_get_perf_event_info(event, &prog_id, fd_type, &buf,
36263acf8aceSJiri Olsa 				      probe_offset, probe_addr, missed);
36271b715e1bSYafang Shao 	if (err)
36281b715e1bSYafang Shao 		return err;
36290aa35162SYafang Shao 	if (!uname)
36300aa35162SYafang Shao 		return 0;
36311b715e1bSYafang Shao 	if (buf) {
36321b715e1bSYafang Shao 		len = strlen(buf);
36331b715e1bSYafang Shao 		err = bpf_copy_to_user(uname, buf, ulen, len);
36341b715e1bSYafang Shao 		if (err)
36351b715e1bSYafang Shao 			return err;
36361b715e1bSYafang Shao 	} else {
36371b715e1bSYafang Shao 		char zero = '\0';
36381b715e1bSYafang Shao 
36391b715e1bSYafang Shao 		if (put_user(zero, uname))
36401b715e1bSYafang Shao 			return -EFAULT;
36411b715e1bSYafang Shao 	}
36421b715e1bSYafang Shao 	return 0;
36431b715e1bSYafang Shao }
36441b715e1bSYafang Shao 
36451b715e1bSYafang Shao #ifdef CONFIG_KPROBE_EVENTS
36461b715e1bSYafang Shao static int bpf_perf_link_fill_kprobe(const struct perf_event *event,
36471b715e1bSYafang Shao 				     struct bpf_link_info *info)
36481b715e1bSYafang Shao {
36493acf8aceSJiri Olsa 	unsigned long missed;
36501b715e1bSYafang Shao 	char __user *uname;
36511b715e1bSYafang Shao 	u64 addr, offset;
36521b715e1bSYafang Shao 	u32 ulen, type;
36531b715e1bSYafang Shao 	int err;
36541b715e1bSYafang Shao 
36551b715e1bSYafang Shao 	uname = u64_to_user_ptr(info->perf_event.kprobe.func_name);
36561b715e1bSYafang Shao 	ulen = info->perf_event.kprobe.name_len;
36571b715e1bSYafang Shao 	err = bpf_perf_link_fill_common(event, uname, ulen, &offset, &addr,
36583acf8aceSJiri Olsa 					&type, &missed);
36591b715e1bSYafang Shao 	if (err)
36601b715e1bSYafang Shao 		return err;
36611b715e1bSYafang Shao 	if (type == BPF_FD_TYPE_KRETPROBE)
36621b715e1bSYafang Shao 		info->perf_event.type = BPF_PERF_EVENT_KRETPROBE;
36631b715e1bSYafang Shao 	else
36641b715e1bSYafang Shao 		info->perf_event.type = BPF_PERF_EVENT_KPROBE;
36651b715e1bSYafang Shao 
36661b715e1bSYafang Shao 	info->perf_event.kprobe.offset = offset;
36673acf8aceSJiri Olsa 	info->perf_event.kprobe.missed = missed;
36681b715e1bSYafang Shao 	if (!kallsyms_show_value(current_cred()))
36691b715e1bSYafang Shao 		addr = 0;
36701b715e1bSYafang Shao 	info->perf_event.kprobe.addr = addr;
3671d5c16492SJiri Olsa 	info->perf_event.kprobe.cookie = event->bpf_cookie;
36721b715e1bSYafang Shao 	return 0;
36731b715e1bSYafang Shao }
36741b715e1bSYafang Shao #endif
36751b715e1bSYafang Shao 
36761b715e1bSYafang Shao #ifdef CONFIG_UPROBE_EVENTS
36771b715e1bSYafang Shao static int bpf_perf_link_fill_uprobe(const struct perf_event *event,
36781b715e1bSYafang Shao 				     struct bpf_link_info *info)
36791b715e1bSYafang Shao {
36801b715e1bSYafang Shao 	char __user *uname;
36811b715e1bSYafang Shao 	u64 addr, offset;
36821b715e1bSYafang Shao 	u32 ulen, type;
36831b715e1bSYafang Shao 	int err;
36841b715e1bSYafang Shao 
36851b715e1bSYafang Shao 	uname = u64_to_user_ptr(info->perf_event.uprobe.file_name);
36861b715e1bSYafang Shao 	ulen = info->perf_event.uprobe.name_len;
36871b715e1bSYafang Shao 	err = bpf_perf_link_fill_common(event, uname, ulen, &offset, &addr,
36883acf8aceSJiri Olsa 					&type, NULL);
36891b715e1bSYafang Shao 	if (err)
36901b715e1bSYafang Shao 		return err;
36911b715e1bSYafang Shao 
36921b715e1bSYafang Shao 	if (type == BPF_FD_TYPE_URETPROBE)
36931b715e1bSYafang Shao 		info->perf_event.type = BPF_PERF_EVENT_URETPROBE;
36941b715e1bSYafang Shao 	else
36951b715e1bSYafang Shao 		info->perf_event.type = BPF_PERF_EVENT_UPROBE;
36961b715e1bSYafang Shao 	info->perf_event.uprobe.offset = offset;
3697d5c16492SJiri Olsa 	info->perf_event.uprobe.cookie = event->bpf_cookie;
36981b715e1bSYafang Shao 	return 0;
36991b715e1bSYafang Shao }
37001b715e1bSYafang Shao #endif
37011b715e1bSYafang Shao 
37021b715e1bSYafang Shao static int bpf_perf_link_fill_probe(const struct perf_event *event,
37031b715e1bSYafang Shao 				    struct bpf_link_info *info)
37041b715e1bSYafang Shao {
37051b715e1bSYafang Shao #ifdef CONFIG_KPROBE_EVENTS
37061b715e1bSYafang Shao 	if (event->tp_event->flags & TRACE_EVENT_FL_KPROBE)
37071b715e1bSYafang Shao 		return bpf_perf_link_fill_kprobe(event, info);
37081b715e1bSYafang Shao #endif
37091b715e1bSYafang Shao #ifdef CONFIG_UPROBE_EVENTS
37101b715e1bSYafang Shao 	if (event->tp_event->flags & TRACE_EVENT_FL_UPROBE)
37111b715e1bSYafang Shao 		return bpf_perf_link_fill_uprobe(event, info);
37121b715e1bSYafang Shao #endif
37131b715e1bSYafang Shao 	return -EOPNOTSUPP;
37141b715e1bSYafang Shao }
37151b715e1bSYafang Shao 
37161b715e1bSYafang Shao static int bpf_perf_link_fill_tracepoint(const struct perf_event *event,
37171b715e1bSYafang Shao 					 struct bpf_link_info *info)
37181b715e1bSYafang Shao {
37191b715e1bSYafang Shao 	char __user *uname;
37201b715e1bSYafang Shao 	u32 ulen;
37211b715e1bSYafang Shao 
37221b715e1bSYafang Shao 	uname = u64_to_user_ptr(info->perf_event.tracepoint.tp_name);
37231b715e1bSYafang Shao 	ulen = info->perf_event.tracepoint.name_len;
37241b715e1bSYafang Shao 	info->perf_event.type = BPF_PERF_EVENT_TRACEPOINT;
3725d5c16492SJiri Olsa 	info->perf_event.tracepoint.cookie = event->bpf_cookie;
37263acf8aceSJiri Olsa 	return bpf_perf_link_fill_common(event, uname, ulen, NULL, NULL, NULL, NULL);
37271b715e1bSYafang Shao }
37281b715e1bSYafang Shao 
37291b715e1bSYafang Shao static int bpf_perf_link_fill_perf_event(const struct perf_event *event,
37301b715e1bSYafang Shao 					 struct bpf_link_info *info)
37311b715e1bSYafang Shao {
37321b715e1bSYafang Shao 	info->perf_event.event.type = event->attr.type;
37331b715e1bSYafang Shao 	info->perf_event.event.config = event->attr.config;
3734d5c16492SJiri Olsa 	info->perf_event.event.cookie = event->bpf_cookie;
37351b715e1bSYafang Shao 	info->perf_event.type = BPF_PERF_EVENT_EVENT;
37361b715e1bSYafang Shao 	return 0;
37371b715e1bSYafang Shao }
37381b715e1bSYafang Shao 
37391b715e1bSYafang Shao static int bpf_perf_link_fill_link_info(const struct bpf_link *link,
37401b715e1bSYafang Shao 					struct bpf_link_info *info)
37411b715e1bSYafang Shao {
37421b715e1bSYafang Shao 	struct bpf_perf_link *perf_link;
37431b715e1bSYafang Shao 	const struct perf_event *event;
37441b715e1bSYafang Shao 
37451b715e1bSYafang Shao 	perf_link = container_of(link, struct bpf_perf_link, link);
37461b715e1bSYafang Shao 	event = perf_get_event(perf_link->perf_file);
37471b715e1bSYafang Shao 	if (IS_ERR(event))
37481b715e1bSYafang Shao 		return PTR_ERR(event);
37491b715e1bSYafang Shao 
37501b715e1bSYafang Shao 	switch (event->prog->type) {
37511b715e1bSYafang Shao 	case BPF_PROG_TYPE_PERF_EVENT:
37521b715e1bSYafang Shao 		return bpf_perf_link_fill_perf_event(event, info);
37531b715e1bSYafang Shao 	case BPF_PROG_TYPE_TRACEPOINT:
37541b715e1bSYafang Shao 		return bpf_perf_link_fill_tracepoint(event, info);
37551b715e1bSYafang Shao 	case BPF_PROG_TYPE_KPROBE:
37561b715e1bSYafang Shao 		return bpf_perf_link_fill_probe(event, info);
37571b715e1bSYafang Shao 	default:
37581b715e1bSYafang Shao 		return -EOPNOTSUPP;
37591b715e1bSYafang Shao 	}
37601b715e1bSYafang Shao }
37611b715e1bSYafang Shao 
3762b89fbfbbSAndrii Nakryiko static const struct bpf_link_ops bpf_perf_link_lops = {
3763b89fbfbbSAndrii Nakryiko 	.release = bpf_perf_link_release,
3764b89fbfbbSAndrii Nakryiko 	.dealloc = bpf_perf_link_dealloc,
37651b715e1bSYafang Shao 	.fill_link_info = bpf_perf_link_fill_link_info,
3766b89fbfbbSAndrii Nakryiko };
3767b89fbfbbSAndrii Nakryiko 
3768b89fbfbbSAndrii Nakryiko static int bpf_perf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
3769b89fbfbbSAndrii Nakryiko {
3770b89fbfbbSAndrii Nakryiko 	struct bpf_link_primer link_primer;
3771b89fbfbbSAndrii Nakryiko 	struct bpf_perf_link *link;
3772b89fbfbbSAndrii Nakryiko 	struct perf_event *event;
3773b89fbfbbSAndrii Nakryiko 	struct file *perf_file;
3774b89fbfbbSAndrii Nakryiko 	int err;
3775b89fbfbbSAndrii Nakryiko 
3776b89fbfbbSAndrii Nakryiko 	if (attr->link_create.flags)
3777b89fbfbbSAndrii Nakryiko 		return -EINVAL;
3778b89fbfbbSAndrii Nakryiko 
3779b89fbfbbSAndrii Nakryiko 	perf_file = perf_event_get(attr->link_create.target_fd);
3780b89fbfbbSAndrii Nakryiko 	if (IS_ERR(perf_file))
3781b89fbfbbSAndrii Nakryiko 		return PTR_ERR(perf_file);
3782b89fbfbbSAndrii Nakryiko 
3783b89fbfbbSAndrii Nakryiko 	link = kzalloc(sizeof(*link), GFP_USER);
3784b89fbfbbSAndrii Nakryiko 	if (!link) {
3785b89fbfbbSAndrii Nakryiko 		err = -ENOMEM;
3786b89fbfbbSAndrii Nakryiko 		goto out_put_file;
3787b89fbfbbSAndrii Nakryiko 	}
3788b89fbfbbSAndrii Nakryiko 	bpf_link_init(&link->link, BPF_LINK_TYPE_PERF_EVENT, &bpf_perf_link_lops, prog);
3789b89fbfbbSAndrii Nakryiko 	link->perf_file = perf_file;
3790b89fbfbbSAndrii Nakryiko 
3791b89fbfbbSAndrii Nakryiko 	err = bpf_link_prime(&link->link, &link_primer);
3792b89fbfbbSAndrii Nakryiko 	if (err) {
3793b89fbfbbSAndrii Nakryiko 		kfree(link);
3794b89fbfbbSAndrii Nakryiko 		goto out_put_file;
3795b89fbfbbSAndrii Nakryiko 	}
3796b89fbfbbSAndrii Nakryiko 
3797b89fbfbbSAndrii Nakryiko 	event = perf_file->private_data;
379882e6b1eeSAndrii Nakryiko 	err = perf_event_set_bpf_prog(event, prog, attr->link_create.perf_event.bpf_cookie);
3799b89fbfbbSAndrii Nakryiko 	if (err) {
3800b89fbfbbSAndrii Nakryiko 		bpf_link_cleanup(&link_primer);
3801b89fbfbbSAndrii Nakryiko 		goto out_put_file;
3802b89fbfbbSAndrii Nakryiko 	}
3803b89fbfbbSAndrii Nakryiko 	/* perf_event_set_bpf_prog() doesn't take its own refcnt on prog */
3804b89fbfbbSAndrii Nakryiko 	bpf_prog_inc(prog);
3805b89fbfbbSAndrii Nakryiko 
3806b89fbfbbSAndrii Nakryiko 	return bpf_link_settle(&link_primer);
3807b89fbfbbSAndrii Nakryiko 
3808b89fbfbbSAndrii Nakryiko out_put_file:
3809b89fbfbbSAndrii Nakryiko 	fput(perf_file);
3810b89fbfbbSAndrii Nakryiko 	return err;
3811b89fbfbbSAndrii Nakryiko }
38120dcac272SJiri Olsa #else
38130dcac272SJiri Olsa static int bpf_perf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
38140dcac272SJiri Olsa {
38150dcac272SJiri Olsa 	return -EOPNOTSUPP;
38160dcac272SJiri Olsa }
3817b89fbfbbSAndrii Nakryiko #endif /* CONFIG_PERF_EVENTS */
3818b89fbfbbSAndrii Nakryiko 
3819df86ca0dSAndrii Nakryiko static int bpf_raw_tp_link_attach(struct bpf_prog *prog,
382068ca5d4eSAndrii Nakryiko 				  const char __user *user_tp_name, u64 cookie)
3821c4f6699dSAlexei Starovoitov {
3822a3b80e10SAndrii Nakryiko 	struct bpf_link_primer link_primer;
3823babf3164SAndrii Nakryiko 	struct bpf_raw_tp_link *link;
3824c4f6699dSAlexei Starovoitov 	struct bpf_raw_event_map *btp;
3825ac4414b5SAlexei Starovoitov 	const char *tp_name;
3826ac4414b5SAlexei Starovoitov 	char buf[128];
3827a3b80e10SAndrii Nakryiko 	int err;
3828c4f6699dSAlexei Starovoitov 
38299e4e01dfSKP Singh 	switch (prog->type) {
38309e4e01dfSKP Singh 	case BPF_PROG_TYPE_TRACING:
38319e4e01dfSKP Singh 	case BPF_PROG_TYPE_EXT:
38329e4e01dfSKP Singh 	case BPF_PROG_TYPE_LSM:
3833df86ca0dSAndrii Nakryiko 		if (user_tp_name)
3834fec56f58SAlexei Starovoitov 			/* The attach point for this category of programs
3835fec56f58SAlexei Starovoitov 			 * should be specified via btf_id during program load.
3836ac4414b5SAlexei Starovoitov 			 */
3837df86ca0dSAndrii Nakryiko 			return -EINVAL;
38389e4e01dfSKP Singh 		if (prog->type == BPF_PROG_TYPE_TRACING &&
38399e4e01dfSKP Singh 		    prog->expected_attach_type == BPF_TRACE_RAW_TP) {
384038207291SMartin KaFai Lau 			tp_name = prog->aux->attach_func_name;
38419e4e01dfSKP Singh 			break;
38429e4e01dfSKP Singh 		}
38432fcc8241SKui-Feng Lee 		return bpf_tracing_prog_attach(prog, 0, 0, 0);
38449e4e01dfSKP Singh 	case BPF_PROG_TYPE_RAW_TRACEPOINT:
38459e4e01dfSKP Singh 	case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
3846df86ca0dSAndrii Nakryiko 		if (strncpy_from_user(buf, user_tp_name, sizeof(buf) - 1) < 0)
3847df86ca0dSAndrii Nakryiko 			return -EFAULT;
3848ac4414b5SAlexei Starovoitov 		buf[sizeof(buf) - 1] = 0;
3849ac4414b5SAlexei Starovoitov 		tp_name = buf;
38509e4e01dfSKP Singh 		break;
38519e4e01dfSKP Singh 	default:
3852df86ca0dSAndrii Nakryiko 		return -EINVAL;
3853ac4414b5SAlexei Starovoitov 	}
3854c4f6699dSAlexei Starovoitov 
3855a38d1107SMatt Mullins 	btp = bpf_get_raw_tracepoint(tp_name);
3856df86ca0dSAndrii Nakryiko 	if (!btp)
3857df86ca0dSAndrii Nakryiko 		return -ENOENT;
3858c4f6699dSAlexei Starovoitov 
3859babf3164SAndrii Nakryiko 	link = kzalloc(sizeof(*link), GFP_USER);
3860babf3164SAndrii Nakryiko 	if (!link) {
3861a38d1107SMatt Mullins 		err = -ENOMEM;
3862a38d1107SMatt Mullins 		goto out_put_btp;
3863a38d1107SMatt Mullins 	}
3864f2e10bffSAndrii Nakryiko 	bpf_link_init(&link->link, BPF_LINK_TYPE_RAW_TRACEPOINT,
3865f2e10bffSAndrii Nakryiko 		      &bpf_raw_tp_link_lops, prog);
3866babf3164SAndrii Nakryiko 	link->btp = btp;
386768ca5d4eSAndrii Nakryiko 	link->cookie = cookie;
3868c4f6699dSAlexei Starovoitov 
3869a3b80e10SAndrii Nakryiko 	err = bpf_link_prime(&link->link, &link_primer);
3870a3b80e10SAndrii Nakryiko 	if (err) {
3871babf3164SAndrii Nakryiko 		kfree(link);
3872babf3164SAndrii Nakryiko 		goto out_put_btp;
3873c4f6699dSAlexei Starovoitov 	}
3874babf3164SAndrii Nakryiko 
3875d4dfc570SAndrii Nakryiko 	err = bpf_probe_register(link->btp, link);
3876babf3164SAndrii Nakryiko 	if (err) {
3877a3b80e10SAndrii Nakryiko 		bpf_link_cleanup(&link_primer);
3878babf3164SAndrii Nakryiko 		goto out_put_btp;
3879babf3164SAndrii Nakryiko 	}
3880babf3164SAndrii Nakryiko 
3881a3b80e10SAndrii Nakryiko 	return bpf_link_settle(&link_primer);
3882c4f6699dSAlexei Starovoitov 
3883a38d1107SMatt Mullins out_put_btp:
3884a38d1107SMatt Mullins 	bpf_put_raw_tracepoint(btp);
3885c4f6699dSAlexei Starovoitov 	return err;
3886c4f6699dSAlexei Starovoitov }
3887c4f6699dSAlexei Starovoitov 
388868ca5d4eSAndrii Nakryiko #define BPF_RAW_TRACEPOINT_OPEN_LAST_FIELD raw_tracepoint.cookie
3889df86ca0dSAndrii Nakryiko 
3890df86ca0dSAndrii Nakryiko static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
3891df86ca0dSAndrii Nakryiko {
3892df86ca0dSAndrii Nakryiko 	struct bpf_prog *prog;
389368ca5d4eSAndrii Nakryiko 	void __user *tp_name;
389468ca5d4eSAndrii Nakryiko 	__u64 cookie;
3895df86ca0dSAndrii Nakryiko 	int fd;
3896df86ca0dSAndrii Nakryiko 
3897df86ca0dSAndrii Nakryiko 	if (CHECK_ATTR(BPF_RAW_TRACEPOINT_OPEN))
3898df86ca0dSAndrii Nakryiko 		return -EINVAL;
3899df86ca0dSAndrii Nakryiko 
3900df86ca0dSAndrii Nakryiko 	prog = bpf_prog_get(attr->raw_tracepoint.prog_fd);
3901df86ca0dSAndrii Nakryiko 	if (IS_ERR(prog))
3902df86ca0dSAndrii Nakryiko 		return PTR_ERR(prog);
3903df86ca0dSAndrii Nakryiko 
390468ca5d4eSAndrii Nakryiko 	tp_name = u64_to_user_ptr(attr->raw_tracepoint.name);
390568ca5d4eSAndrii Nakryiko 	cookie = attr->raw_tracepoint.cookie;
390668ca5d4eSAndrii Nakryiko 	fd = bpf_raw_tp_link_attach(prog, tp_name, cookie);
3907df86ca0dSAndrii Nakryiko 	if (fd < 0)
3908df86ca0dSAndrii Nakryiko 		bpf_prog_put(prog);
3909df86ca0dSAndrii Nakryiko 	return fd;
3910df86ca0dSAndrii Nakryiko }
3911df86ca0dSAndrii Nakryiko 
3912e28784e3SAndrii Nakryiko static enum bpf_prog_type
3913e28784e3SAndrii Nakryiko attach_type_to_prog_type(enum bpf_attach_type attach_type)
3914e28784e3SAndrii Nakryiko {
3915e28784e3SAndrii Nakryiko 	switch (attach_type) {
3916e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET_INGRESS:
3917e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET_EGRESS:
3918e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SKB;
3919e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET_SOCK_CREATE:
3920f5836749SStanislav Fomichev 	case BPF_CGROUP_INET_SOCK_RELEASE:
3921e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET4_POST_BIND:
3922e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET6_POST_BIND:
3923e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SOCK;
3924e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET4_BIND:
3925e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET6_BIND:
3926e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET4_CONNECT:
3927e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET6_CONNECT:
3928859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_CONNECT:
39291b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETPEERNAME:
39301b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETPEERNAME:
3931859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_GETPEERNAME:
39321b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETSOCKNAME:
39331b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETSOCKNAME:
3934859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_GETSOCKNAME:
3935e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP4_SENDMSG:
3936e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP6_SENDMSG:
3937859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_SENDMSG:
3938e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP4_RECVMSG:
3939e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP6_RECVMSG:
3940859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_RECVMSG:
3941e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
3942e28784e3SAndrii Nakryiko 	case BPF_CGROUP_SOCK_OPS:
3943e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_SOCK_OPS;
3944e28784e3SAndrii Nakryiko 	case BPF_CGROUP_DEVICE:
3945e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_DEVICE;
3946e28784e3SAndrii Nakryiko 	case BPF_SK_MSG_VERDICT:
3947e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_SK_MSG;
3948e28784e3SAndrii Nakryiko 	case BPF_SK_SKB_STREAM_PARSER:
3949e28784e3SAndrii Nakryiko 	case BPF_SK_SKB_STREAM_VERDICT:
3950a7ba4558SCong Wang 	case BPF_SK_SKB_VERDICT:
3951e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_SK_SKB;
3952e28784e3SAndrii Nakryiko 	case BPF_LIRC_MODE2:
3953e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_LIRC_MODE2;
3954e28784e3SAndrii Nakryiko 	case BPF_FLOW_DISSECTOR:
3955e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_FLOW_DISSECTOR;
3956e28784e3SAndrii Nakryiko 	case BPF_CGROUP_SYSCTL:
3957e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SYSCTL;
3958e28784e3SAndrii Nakryiko 	case BPF_CGROUP_GETSOCKOPT:
3959e28784e3SAndrii Nakryiko 	case BPF_CGROUP_SETSOCKOPT:
3960e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SOCKOPT;
3961de4e05caSYonghong Song 	case BPF_TRACE_ITER:
3962df86ca0dSAndrii Nakryiko 	case BPF_TRACE_RAW_TP:
3963df86ca0dSAndrii Nakryiko 	case BPF_TRACE_FENTRY:
3964df86ca0dSAndrii Nakryiko 	case BPF_TRACE_FEXIT:
3965df86ca0dSAndrii Nakryiko 	case BPF_MODIFY_RETURN:
3966de4e05caSYonghong Song 		return BPF_PROG_TYPE_TRACING;
3967df86ca0dSAndrii Nakryiko 	case BPF_LSM_MAC:
3968df86ca0dSAndrii Nakryiko 		return BPF_PROG_TYPE_LSM;
3969e9ddbb77SJakub Sitnicki 	case BPF_SK_LOOKUP:
3970e9ddbb77SJakub Sitnicki 		return BPF_PROG_TYPE_SK_LOOKUP;
3971aa8d3a71SAndrii Nakryiko 	case BPF_XDP:
3972aa8d3a71SAndrii Nakryiko 		return BPF_PROG_TYPE_XDP;
397369fd337aSStanislav Fomichev 	case BPF_LSM_CGROUP:
397469fd337aSStanislav Fomichev 		return BPF_PROG_TYPE_LSM;
3975e420bed0SDaniel Borkmann 	case BPF_TCX_INGRESS:
3976e420bed0SDaniel Borkmann 	case BPF_TCX_EGRESS:
397735dfaad7SDaniel Borkmann 	case BPF_NETKIT_PRIMARY:
397835dfaad7SDaniel Borkmann 	case BPF_NETKIT_PEER:
3979e420bed0SDaniel Borkmann 		return BPF_PROG_TYPE_SCHED_CLS;
3980e28784e3SAndrii Nakryiko 	default:
3981e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_UNSPEC;
3982e28784e3SAndrii Nakryiko 	}
3983e28784e3SAndrii Nakryiko }
3984e28784e3SAndrii Nakryiko 
39853505cb9fSJiri Olsa static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog,
39863505cb9fSJiri Olsa 					     enum bpf_attach_type attach_type)
39873505cb9fSJiri Olsa {
39883505cb9fSJiri Olsa 	enum bpf_prog_type ptype;
39893505cb9fSJiri Olsa 
39903505cb9fSJiri Olsa 	switch (prog->type) {
39913505cb9fSJiri Olsa 	case BPF_PROG_TYPE_CGROUP_SOCK:
39923505cb9fSJiri Olsa 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
39933505cb9fSJiri Olsa 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
39943505cb9fSJiri Olsa 	case BPF_PROG_TYPE_SK_LOOKUP:
39953505cb9fSJiri Olsa 		return attach_type == prog->expected_attach_type ? 0 : -EINVAL;
39963505cb9fSJiri Olsa 	case BPF_PROG_TYPE_CGROUP_SKB:
3997caf8f28eSAndrii Nakryiko 		if (!bpf_token_capable(prog->aux->token, CAP_NET_ADMIN))
39983505cb9fSJiri Olsa 			/* cg-skb progs can be loaded by unpriv user.
39993505cb9fSJiri Olsa 			 * check permissions at attach time.
40003505cb9fSJiri Olsa 			 */
40013505cb9fSJiri Olsa 			return -EPERM;
4002543576ecSStanislav Fomichev 
4003543576ecSStanislav Fomichev 		ptype = attach_type_to_prog_type(attach_type);
4004543576ecSStanislav Fomichev 		if (prog->type != ptype)
4005543576ecSStanislav Fomichev 			return -EINVAL;
4006543576ecSStanislav Fomichev 
40073505cb9fSJiri Olsa 		return prog->enforce_expected_attach_type &&
40083505cb9fSJiri Olsa 			prog->expected_attach_type != attach_type ?
40093505cb9fSJiri Olsa 			-EINVAL : 0;
40103505cb9fSJiri Olsa 	case BPF_PROG_TYPE_EXT:
40113505cb9fSJiri Olsa 		return 0;
40123505cb9fSJiri Olsa 	case BPF_PROG_TYPE_NETFILTER:
40133505cb9fSJiri Olsa 		if (attach_type != BPF_NETFILTER)
40143505cb9fSJiri Olsa 			return -EINVAL;
40153505cb9fSJiri Olsa 		return 0;
40163505cb9fSJiri Olsa 	case BPF_PROG_TYPE_PERF_EVENT:
40173505cb9fSJiri Olsa 	case BPF_PROG_TYPE_TRACEPOINT:
40183505cb9fSJiri Olsa 		if (attach_type != BPF_PERF_EVENT)
40193505cb9fSJiri Olsa 			return -EINVAL;
40203505cb9fSJiri Olsa 		return 0;
40213505cb9fSJiri Olsa 	case BPF_PROG_TYPE_KPROBE:
40223505cb9fSJiri Olsa 		if (prog->expected_attach_type == BPF_TRACE_KPROBE_MULTI &&
40233505cb9fSJiri Olsa 		    attach_type != BPF_TRACE_KPROBE_MULTI)
40243505cb9fSJiri Olsa 			return -EINVAL;
4025535a3692SJiri Olsa 		if (prog->expected_attach_type == BPF_TRACE_KPROBE_SESSION &&
4026535a3692SJiri Olsa 		    attach_type != BPF_TRACE_KPROBE_SESSION)
4027535a3692SJiri Olsa 			return -EINVAL;
402889ae89f5SJiri Olsa 		if (prog->expected_attach_type == BPF_TRACE_UPROBE_MULTI &&
402989ae89f5SJiri Olsa 		    attach_type != BPF_TRACE_UPROBE_MULTI)
403089ae89f5SJiri Olsa 			return -EINVAL;
40313505cb9fSJiri Olsa 		if (attach_type != BPF_PERF_EVENT &&
403289ae89f5SJiri Olsa 		    attach_type != BPF_TRACE_KPROBE_MULTI &&
4033535a3692SJiri Olsa 		    attach_type != BPF_TRACE_KPROBE_SESSION &&
403489ae89f5SJiri Olsa 		    attach_type != BPF_TRACE_UPROBE_MULTI)
40353505cb9fSJiri Olsa 			return -EINVAL;
40363505cb9fSJiri Olsa 		return 0;
40373505cb9fSJiri Olsa 	case BPF_PROG_TYPE_SCHED_CLS:
40383505cb9fSJiri Olsa 		if (attach_type != BPF_TCX_INGRESS &&
403935dfaad7SDaniel Borkmann 		    attach_type != BPF_TCX_EGRESS &&
404035dfaad7SDaniel Borkmann 		    attach_type != BPF_NETKIT_PRIMARY &&
404135dfaad7SDaniel Borkmann 		    attach_type != BPF_NETKIT_PEER)
40423505cb9fSJiri Olsa 			return -EINVAL;
40433505cb9fSJiri Olsa 		return 0;
40443505cb9fSJiri Olsa 	default:
40453505cb9fSJiri Olsa 		ptype = attach_type_to_prog_type(attach_type);
40463505cb9fSJiri Olsa 		if (ptype == BPF_PROG_TYPE_UNSPEC || ptype != prog->type)
40473505cb9fSJiri Olsa 			return -EINVAL;
40483505cb9fSJiri Olsa 		return 0;
40493505cb9fSJiri Olsa 	}
40503505cb9fSJiri Olsa }
40513505cb9fSJiri Olsa 
4052e420bed0SDaniel Borkmann #define BPF_PROG_ATTACH_LAST_FIELD expected_revision
4053174a79ffSJohn Fastabend 
4054e420bed0SDaniel Borkmann #define BPF_F_ATTACH_MASK_BASE	\
4055e420bed0SDaniel Borkmann 	(BPF_F_ALLOW_OVERRIDE |	\
4056e420bed0SDaniel Borkmann 	 BPF_F_ALLOW_MULTI |	\
4057e420bed0SDaniel Borkmann 	 BPF_F_REPLACE)
4058e420bed0SDaniel Borkmann 
4059e420bed0SDaniel Borkmann #define BPF_F_ATTACH_MASK_MPROG	\
4060e420bed0SDaniel Borkmann 	(BPF_F_REPLACE |	\
4061e420bed0SDaniel Borkmann 	 BPF_F_BEFORE |		\
4062e420bed0SDaniel Borkmann 	 BPF_F_AFTER |		\
4063e420bed0SDaniel Borkmann 	 BPF_F_ID |		\
4064e420bed0SDaniel Borkmann 	 BPF_F_LINK)
4065324bda9eSAlexei Starovoitov 
4066f4324551SDaniel Mack static int bpf_prog_attach(const union bpf_attr *attr)
4067f4324551SDaniel Mack {
40687f677633SAlexei Starovoitov 	enum bpf_prog_type ptype;
4069f4324551SDaniel Mack 	struct bpf_prog *prog;
40707f677633SAlexei Starovoitov 	int ret;
4071f4324551SDaniel Mack 
4072f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_ATTACH))
4073f4324551SDaniel Mack 		return -EINVAL;
4074f4324551SDaniel Mack 
4075e28784e3SAndrii Nakryiko 	ptype = attach_type_to_prog_type(attr->attach_type);
4076e28784e3SAndrii Nakryiko 	if (ptype == BPF_PROG_TYPE_UNSPEC)
4077b2cd1257SDavid Ahern 		return -EINVAL;
4078ba62d611SLorenz Bauer 	if (bpf_mprog_supported(ptype)) {
4079ba62d611SLorenz Bauer 		if (attr->attach_flags & ~BPF_F_ATTACH_MASK_MPROG)
4080e420bed0SDaniel Borkmann 			return -EINVAL;
4081ba62d611SLorenz Bauer 	} else {
4082ba62d611SLorenz Bauer 		if (attr->attach_flags & ~BPF_F_ATTACH_MASK_BASE)
4083ba62d611SLorenz Bauer 			return -EINVAL;
4084ba62d611SLorenz Bauer 		if (attr->relative_fd ||
4085ba62d611SLorenz Bauer 		    attr->expected_revision)
4086ba62d611SLorenz Bauer 			return -EINVAL;
4087ba62d611SLorenz Bauer 	}
4088b2cd1257SDavid Ahern 
4089b2cd1257SDavid Ahern 	prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
4090f4324551SDaniel Mack 	if (IS_ERR(prog))
4091f4324551SDaniel Mack 		return PTR_ERR(prog);
4092f4324551SDaniel Mack 
40935e43f899SAndrey Ignatov 	if (bpf_prog_attach_check_attach_type(prog, attr->attach_type)) {
40945e43f899SAndrey Ignatov 		bpf_prog_put(prog);
40955e43f899SAndrey Ignatov 		return -EINVAL;
40965e43f899SAndrey Ignatov 	}
40975e43f899SAndrey Ignatov 
4098fdb5c453SSean Young 	switch (ptype) {
4099fdb5c453SSean Young 	case BPF_PROG_TYPE_SK_SKB:
4100fdb5c453SSean Young 	case BPF_PROG_TYPE_SK_MSG:
4101604326b4SDaniel Borkmann 		ret = sock_map_get_from_fd(attr, prog);
4102fdb5c453SSean Young 		break;
4103fdb5c453SSean Young 	case BPF_PROG_TYPE_LIRC_MODE2:
4104fdb5c453SSean Young 		ret = lirc_prog_attach(attr, prog);
4105fdb5c453SSean Young 		break;
4106d58e468bSPetar Penkov 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
4107a3fd7ceeSJakub Sitnicki 		ret = netns_bpf_prog_attach(attr, prog);
4108d58e468bSPetar Penkov 		break;
4109e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_DEVICE:
4110e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SKB:
4111e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK:
4112e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
4113e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
4114e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
4115e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SOCK_OPS:
411669fd337aSStanislav Fomichev 	case BPF_PROG_TYPE_LSM:
411769fd337aSStanislav Fomichev 		if (ptype == BPF_PROG_TYPE_LSM &&
411869fd337aSStanislav Fomichev 		    prog->expected_attach_type != BPF_LSM_CGROUP)
4119e89f3edfSMilan Landaverde 			ret = -EINVAL;
4120e89f3edfSMilan Landaverde 		else
4121fdb5c453SSean Young 			ret = cgroup_bpf_prog_attach(attr, ptype, prog);
4122e28784e3SAndrii Nakryiko 		break;
4123e420bed0SDaniel Borkmann 	case BPF_PROG_TYPE_SCHED_CLS:
412435dfaad7SDaniel Borkmann 		if (attr->attach_type == BPF_TCX_INGRESS ||
412535dfaad7SDaniel Borkmann 		    attr->attach_type == BPF_TCX_EGRESS)
4126e420bed0SDaniel Borkmann 			ret = tcx_prog_attach(attr, prog);
412735dfaad7SDaniel Borkmann 		else
412835dfaad7SDaniel Borkmann 			ret = netkit_prog_attach(attr, prog);
4129e420bed0SDaniel Borkmann 		break;
4130e28784e3SAndrii Nakryiko 	default:
4131e28784e3SAndrii Nakryiko 		ret = -EINVAL;
4132f4324551SDaniel Mack 	}
4133f4324551SDaniel Mack 
41347f677633SAlexei Starovoitov 	if (ret)
41357f677633SAlexei Starovoitov 		bpf_prog_put(prog);
41367f677633SAlexei Starovoitov 	return ret;
4137f4324551SDaniel Mack }
4138f4324551SDaniel Mack 
4139e420bed0SDaniel Borkmann #define BPF_PROG_DETACH_LAST_FIELD expected_revision
4140f4324551SDaniel Mack 
4141f4324551SDaniel Mack static int bpf_prog_detach(const union bpf_attr *attr)
4142f4324551SDaniel Mack {
4143e420bed0SDaniel Borkmann 	struct bpf_prog *prog = NULL;
4144324bda9eSAlexei Starovoitov 	enum bpf_prog_type ptype;
4145e420bed0SDaniel Borkmann 	int ret;
4146f4324551SDaniel Mack 
4147f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_DETACH))
4148f4324551SDaniel Mack 		return -EINVAL;
4149f4324551SDaniel Mack 
4150e28784e3SAndrii Nakryiko 	ptype = attach_type_to_prog_type(attr->attach_type);
4151e420bed0SDaniel Borkmann 	if (bpf_mprog_supported(ptype)) {
4152e420bed0SDaniel Borkmann 		if (ptype == BPF_PROG_TYPE_UNSPEC)
4153e420bed0SDaniel Borkmann 			return -EINVAL;
4154e420bed0SDaniel Borkmann 		if (attr->attach_flags & ~BPF_F_ATTACH_MASK_MPROG)
4155e420bed0SDaniel Borkmann 			return -EINVAL;
4156e420bed0SDaniel Borkmann 		if (attr->attach_bpf_fd) {
4157e420bed0SDaniel Borkmann 			prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
4158e420bed0SDaniel Borkmann 			if (IS_ERR(prog))
4159e420bed0SDaniel Borkmann 				return PTR_ERR(prog);
4160e420bed0SDaniel Borkmann 		}
4161ba62d611SLorenz Bauer 	} else if (attr->attach_flags ||
4162ba62d611SLorenz Bauer 		   attr->relative_fd ||
4163ba62d611SLorenz Bauer 		   attr->expected_revision) {
4164ba62d611SLorenz Bauer 		return -EINVAL;
4165e420bed0SDaniel Borkmann 	}
4166e28784e3SAndrii Nakryiko 
4167e28784e3SAndrii Nakryiko 	switch (ptype) {
4168e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SK_MSG:
4169e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SK_SKB:
4170e420bed0SDaniel Borkmann 		ret = sock_map_prog_detach(attr, ptype);
4171e420bed0SDaniel Borkmann 		break;
4172e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_LIRC_MODE2:
4173e420bed0SDaniel Borkmann 		ret = lirc_prog_detach(attr);
4174e420bed0SDaniel Borkmann 		break;
4175e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
4176e420bed0SDaniel Borkmann 		ret = netns_bpf_prog_detach(attr, ptype);
4177e420bed0SDaniel Borkmann 		break;
4178e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_DEVICE:
4179e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SKB:
4180e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK:
4181e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
4182e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
4183e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
4184e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SOCK_OPS:
418569fd337aSStanislav Fomichev 	case BPF_PROG_TYPE_LSM:
4186e420bed0SDaniel Borkmann 		ret = cgroup_bpf_prog_detach(attr, ptype);
4187e420bed0SDaniel Borkmann 		break;
4188e420bed0SDaniel Borkmann 	case BPF_PROG_TYPE_SCHED_CLS:
418935dfaad7SDaniel Borkmann 		if (attr->attach_type == BPF_TCX_INGRESS ||
419035dfaad7SDaniel Borkmann 		    attr->attach_type == BPF_TCX_EGRESS)
4191e420bed0SDaniel Borkmann 			ret = tcx_prog_detach(attr, prog);
419235dfaad7SDaniel Borkmann 		else
419335dfaad7SDaniel Borkmann 			ret = netkit_prog_detach(attr, prog);
4194e420bed0SDaniel Borkmann 		break;
4195f4324551SDaniel Mack 	default:
4196e420bed0SDaniel Borkmann 		ret = -EINVAL;
4197f4324551SDaniel Mack 	}
419840304b2aSLawrence Brakmo 
4199e420bed0SDaniel Borkmann 	if (prog)
4200e420bed0SDaniel Borkmann 		bpf_prog_put(prog);
4201e420bed0SDaniel Borkmann 	return ret;
4202e420bed0SDaniel Borkmann }
4203e420bed0SDaniel Borkmann 
4204a4fe7838SDaniel Borkmann #define BPF_PROG_QUERY_LAST_FIELD query.revision
4205468e2f64SAlexei Starovoitov 
4206468e2f64SAlexei Starovoitov static int bpf_prog_query(const union bpf_attr *attr,
4207468e2f64SAlexei Starovoitov 			  union bpf_attr __user *uattr)
4208468e2f64SAlexei Starovoitov {
4209ed1ad5a7SAndrii Nakryiko 	if (!bpf_net_capable())
4210468e2f64SAlexei Starovoitov 		return -EPERM;
4211468e2f64SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_QUERY))
4212468e2f64SAlexei Starovoitov 		return -EINVAL;
4213468e2f64SAlexei Starovoitov 	if (attr->query.query_flags & ~BPF_F_QUERY_EFFECTIVE)
4214468e2f64SAlexei Starovoitov 		return -EINVAL;
4215468e2f64SAlexei Starovoitov 
4216468e2f64SAlexei Starovoitov 	switch (attr->query.attach_type) {
4217468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_INGRESS:
4218468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_EGRESS:
4219468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_SOCK_CREATE:
4220f5836749SStanislav Fomichev 	case BPF_CGROUP_INET_SOCK_RELEASE:
42214fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET4_BIND:
42224fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET6_BIND:
4223aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET4_POST_BIND:
4224aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET6_POST_BIND:
4225d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET4_CONNECT:
4226d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET6_CONNECT:
4227859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_CONNECT:
42281b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETPEERNAME:
42291b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETPEERNAME:
4230859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_GETPEERNAME:
42311b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETSOCKNAME:
42321b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETSOCKNAME:
4233859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_GETSOCKNAME:
42341cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP4_SENDMSG:
42351cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP6_SENDMSG:
4236859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_SENDMSG:
4237983695faSDaniel Borkmann 	case BPF_CGROUP_UDP4_RECVMSG:
4238983695faSDaniel Borkmann 	case BPF_CGROUP_UDP6_RECVMSG:
4239859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_RECVMSG:
4240468e2f64SAlexei Starovoitov 	case BPF_CGROUP_SOCK_OPS:
4241ebc614f6SRoman Gushchin 	case BPF_CGROUP_DEVICE:
42427b146cebSAndrey Ignatov 	case BPF_CGROUP_SYSCTL:
42430d01da6aSStanislav Fomichev 	case BPF_CGROUP_GETSOCKOPT:
42440d01da6aSStanislav Fomichev 	case BPF_CGROUP_SETSOCKOPT:
4245b79c9fc9SStanislav Fomichev 	case BPF_LSM_CGROUP:
4246e28784e3SAndrii Nakryiko 		return cgroup_bpf_prog_query(attr, uattr);
4247f4364dcfSSean Young 	case BPF_LIRC_MODE2:
4248f4364dcfSSean Young 		return lirc_prog_query(attr, uattr);
4249118c8e9aSStanislav Fomichev 	case BPF_FLOW_DISSECTOR:
4250e9ddbb77SJakub Sitnicki 	case BPF_SK_LOOKUP:
4251a3fd7ceeSJakub Sitnicki 		return netns_bpf_prog_query(attr, uattr);
4252748cd572SDi Zhu 	case BPF_SK_SKB_STREAM_PARSER:
4253748cd572SDi Zhu 	case BPF_SK_SKB_STREAM_VERDICT:
4254748cd572SDi Zhu 	case BPF_SK_MSG_VERDICT:
4255748cd572SDi Zhu 	case BPF_SK_SKB_VERDICT:
4256748cd572SDi Zhu 		return sock_map_bpf_prog_query(attr, uattr);
4257e420bed0SDaniel Borkmann 	case BPF_TCX_INGRESS:
4258e420bed0SDaniel Borkmann 	case BPF_TCX_EGRESS:
4259e420bed0SDaniel Borkmann 		return tcx_prog_query(attr, uattr);
426035dfaad7SDaniel Borkmann 	case BPF_NETKIT_PRIMARY:
426135dfaad7SDaniel Borkmann 	case BPF_NETKIT_PEER:
426235dfaad7SDaniel Borkmann 		return netkit_prog_query(attr, uattr);
4263468e2f64SAlexei Starovoitov 	default:
4264468e2f64SAlexei Starovoitov 		return -EINVAL;
4265468e2f64SAlexei Starovoitov 	}
4266468e2f64SAlexei Starovoitov }
4267f4324551SDaniel Mack 
4268b530e9e1SToke Høiland-Jørgensen #define BPF_PROG_TEST_RUN_LAST_FIELD test.batch_size
42691cf1cae9SAlexei Starovoitov 
42701cf1cae9SAlexei Starovoitov static int bpf_prog_test_run(const union bpf_attr *attr,
42711cf1cae9SAlexei Starovoitov 			     union bpf_attr __user *uattr)
42721cf1cae9SAlexei Starovoitov {
42731cf1cae9SAlexei Starovoitov 	struct bpf_prog *prog;
42741cf1cae9SAlexei Starovoitov 	int ret = -ENOTSUPP;
42751cf1cae9SAlexei Starovoitov 
42761cf1cae9SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_TEST_RUN))
42771cf1cae9SAlexei Starovoitov 		return -EINVAL;
42781cf1cae9SAlexei Starovoitov 
4279b0b9395dSStanislav Fomichev 	if ((attr->test.ctx_size_in && !attr->test.ctx_in) ||
4280b0b9395dSStanislav Fomichev 	    (!attr->test.ctx_size_in && attr->test.ctx_in))
4281b0b9395dSStanislav Fomichev 		return -EINVAL;
4282b0b9395dSStanislav Fomichev 
4283b0b9395dSStanislav Fomichev 	if ((attr->test.ctx_size_out && !attr->test.ctx_out) ||
4284b0b9395dSStanislav Fomichev 	    (!attr->test.ctx_size_out && attr->test.ctx_out))
4285b0b9395dSStanislav Fomichev 		return -EINVAL;
4286b0b9395dSStanislav Fomichev 
42871cf1cae9SAlexei Starovoitov 	prog = bpf_prog_get(attr->test.prog_fd);
42881cf1cae9SAlexei Starovoitov 	if (IS_ERR(prog))
42891cf1cae9SAlexei Starovoitov 		return PTR_ERR(prog);
42901cf1cae9SAlexei Starovoitov 
42911cf1cae9SAlexei Starovoitov 	if (prog->aux->ops->test_run)
42921cf1cae9SAlexei Starovoitov 		ret = prog->aux->ops->test_run(prog, attr, uattr);
42931cf1cae9SAlexei Starovoitov 
42941cf1cae9SAlexei Starovoitov 	bpf_prog_put(prog);
42951cf1cae9SAlexei Starovoitov 	return ret;
42961cf1cae9SAlexei Starovoitov }
42971cf1cae9SAlexei Starovoitov 
429834ad5580SMartin KaFai Lau #define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id
429934ad5580SMartin KaFai Lau 
430034ad5580SMartin KaFai Lau static int bpf_obj_get_next_id(const union bpf_attr *attr,
430134ad5580SMartin KaFai Lau 			       union bpf_attr __user *uattr,
430234ad5580SMartin KaFai Lau 			       struct idr *idr,
430334ad5580SMartin KaFai Lau 			       spinlock_t *lock)
430434ad5580SMartin KaFai Lau {
430534ad5580SMartin KaFai Lau 	u32 next_id = attr->start_id;
430634ad5580SMartin KaFai Lau 	int err = 0;
430734ad5580SMartin KaFai Lau 
430834ad5580SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX)
430934ad5580SMartin KaFai Lau 		return -EINVAL;
431034ad5580SMartin KaFai Lau 
431134ad5580SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
431234ad5580SMartin KaFai Lau 		return -EPERM;
431334ad5580SMartin KaFai Lau 
431434ad5580SMartin KaFai Lau 	next_id++;
431534ad5580SMartin KaFai Lau 	spin_lock_bh(lock);
431634ad5580SMartin KaFai Lau 	if (!idr_get_next(idr, &next_id))
431734ad5580SMartin KaFai Lau 		err = -ENOENT;
431834ad5580SMartin KaFai Lau 	spin_unlock_bh(lock);
431934ad5580SMartin KaFai Lau 
432034ad5580SMartin KaFai Lau 	if (!err)
432134ad5580SMartin KaFai Lau 		err = put_user(next_id, &uattr->next_id);
432234ad5580SMartin KaFai Lau 
432334ad5580SMartin KaFai Lau 	return err;
432434ad5580SMartin KaFai Lau }
432534ad5580SMartin KaFai Lau 
43266086d29dSYonghong Song struct bpf_map *bpf_map_get_curr_or_next(u32 *id)
43276086d29dSYonghong Song {
43286086d29dSYonghong Song 	struct bpf_map *map;
43296086d29dSYonghong Song 
43306086d29dSYonghong Song 	spin_lock_bh(&map_idr_lock);
43316086d29dSYonghong Song again:
43326086d29dSYonghong Song 	map = idr_get_next(&map_idr, id);
43336086d29dSYonghong Song 	if (map) {
43346086d29dSYonghong Song 		map = __bpf_map_inc_not_zero(map, false);
43356086d29dSYonghong Song 		if (IS_ERR(map)) {
43366086d29dSYonghong Song 			(*id)++;
43376086d29dSYonghong Song 			goto again;
43386086d29dSYonghong Song 		}
43396086d29dSYonghong Song 	}
43406086d29dSYonghong Song 	spin_unlock_bh(&map_idr_lock);
43416086d29dSYonghong Song 
43426086d29dSYonghong Song 	return map;
43436086d29dSYonghong Song }
43446086d29dSYonghong Song 
4345a228a64fSAlexei Starovoitov struct bpf_prog *bpf_prog_get_curr_or_next(u32 *id)
4346a228a64fSAlexei Starovoitov {
4347a228a64fSAlexei Starovoitov 	struct bpf_prog *prog;
4348a228a64fSAlexei Starovoitov 
4349a228a64fSAlexei Starovoitov 	spin_lock_bh(&prog_idr_lock);
4350a228a64fSAlexei Starovoitov again:
4351a228a64fSAlexei Starovoitov 	prog = idr_get_next(&prog_idr, id);
4352a228a64fSAlexei Starovoitov 	if (prog) {
4353a228a64fSAlexei Starovoitov 		prog = bpf_prog_inc_not_zero(prog);
4354a228a64fSAlexei Starovoitov 		if (IS_ERR(prog)) {
4355a228a64fSAlexei Starovoitov 			(*id)++;
4356a228a64fSAlexei Starovoitov 			goto again;
4357a228a64fSAlexei Starovoitov 		}
4358a228a64fSAlexei Starovoitov 	}
4359a228a64fSAlexei Starovoitov 	spin_unlock_bh(&prog_idr_lock);
4360a228a64fSAlexei Starovoitov 
4361a228a64fSAlexei Starovoitov 	return prog;
4362a228a64fSAlexei Starovoitov }
4363a228a64fSAlexei Starovoitov 
4364b16d9aa4SMartin KaFai Lau #define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id
4365b16d9aa4SMartin KaFai Lau 
43667e6897f9SBjörn Töpel struct bpf_prog *bpf_prog_by_id(u32 id)
43677e6897f9SBjörn Töpel {
43687e6897f9SBjörn Töpel 	struct bpf_prog *prog;
43697e6897f9SBjörn Töpel 
43707e6897f9SBjörn Töpel 	if (!id)
43717e6897f9SBjörn Töpel 		return ERR_PTR(-ENOENT);
43727e6897f9SBjörn Töpel 
43737e6897f9SBjörn Töpel 	spin_lock_bh(&prog_idr_lock);
43747e6897f9SBjörn Töpel 	prog = idr_find(&prog_idr, id);
43757e6897f9SBjörn Töpel 	if (prog)
43767e6897f9SBjörn Töpel 		prog = bpf_prog_inc_not_zero(prog);
43777e6897f9SBjörn Töpel 	else
43787e6897f9SBjörn Töpel 		prog = ERR_PTR(-ENOENT);
43797e6897f9SBjörn Töpel 	spin_unlock_bh(&prog_idr_lock);
43807e6897f9SBjörn Töpel 	return prog;
43817e6897f9SBjörn Töpel }
43827e6897f9SBjörn Töpel 
4383b16d9aa4SMartin KaFai Lau static int bpf_prog_get_fd_by_id(const union bpf_attr *attr)
4384b16d9aa4SMartin KaFai Lau {
4385b16d9aa4SMartin KaFai Lau 	struct bpf_prog *prog;
4386b16d9aa4SMartin KaFai Lau 	u32 id = attr->prog_id;
4387b16d9aa4SMartin KaFai Lau 	int fd;
4388b16d9aa4SMartin KaFai Lau 
4389b16d9aa4SMartin KaFai Lau 	if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID))
4390b16d9aa4SMartin KaFai Lau 		return -EINVAL;
4391b16d9aa4SMartin KaFai Lau 
4392b16d9aa4SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
4393b16d9aa4SMartin KaFai Lau 		return -EPERM;
4394b16d9aa4SMartin KaFai Lau 
43957e6897f9SBjörn Töpel 	prog = bpf_prog_by_id(id);
4396b16d9aa4SMartin KaFai Lau 	if (IS_ERR(prog))
4397b16d9aa4SMartin KaFai Lau 		return PTR_ERR(prog);
4398b16d9aa4SMartin KaFai Lau 
4399b16d9aa4SMartin KaFai Lau 	fd = bpf_prog_new_fd(prog);
4400b16d9aa4SMartin KaFai Lau 	if (fd < 0)
4401b16d9aa4SMartin KaFai Lau 		bpf_prog_put(prog);
4402b16d9aa4SMartin KaFai Lau 
4403b16d9aa4SMartin KaFai Lau 	return fd;
4404b16d9aa4SMartin KaFai Lau }
4405b16d9aa4SMartin KaFai Lau 
44066e71b04aSChenbo Feng #define BPF_MAP_GET_FD_BY_ID_LAST_FIELD open_flags
4407bd5f5f4eSMartin KaFai Lau 
4408bd5f5f4eSMartin KaFai Lau static int bpf_map_get_fd_by_id(const union bpf_attr *attr)
4409bd5f5f4eSMartin KaFai Lau {
4410bd5f5f4eSMartin KaFai Lau 	struct bpf_map *map;
4411bd5f5f4eSMartin KaFai Lau 	u32 id = attr->map_id;
44126e71b04aSChenbo Feng 	int f_flags;
4413bd5f5f4eSMartin KaFai Lau 	int fd;
4414bd5f5f4eSMartin KaFai Lau 
44156e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_MAP_GET_FD_BY_ID) ||
44166e71b04aSChenbo Feng 	    attr->open_flags & ~BPF_OBJ_FLAG_MASK)
4417bd5f5f4eSMartin KaFai Lau 		return -EINVAL;
4418bd5f5f4eSMartin KaFai Lau 
4419bd5f5f4eSMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
4420bd5f5f4eSMartin KaFai Lau 		return -EPERM;
4421bd5f5f4eSMartin KaFai Lau 
44226e71b04aSChenbo Feng 	f_flags = bpf_get_file_flag(attr->open_flags);
44236e71b04aSChenbo Feng 	if (f_flags < 0)
44246e71b04aSChenbo Feng 		return f_flags;
44256e71b04aSChenbo Feng 
4426bd5f5f4eSMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
4427bd5f5f4eSMartin KaFai Lau 	map = idr_find(&map_idr, id);
4428bd5f5f4eSMartin KaFai Lau 	if (map)
4429b0e4701cSStanislav Fomichev 		map = __bpf_map_inc_not_zero(map, true);
4430bd5f5f4eSMartin KaFai Lau 	else
4431bd5f5f4eSMartin KaFai Lau 		map = ERR_PTR(-ENOENT);
4432bd5f5f4eSMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
4433bd5f5f4eSMartin KaFai Lau 
4434bd5f5f4eSMartin KaFai Lau 	if (IS_ERR(map))
4435bd5f5f4eSMartin KaFai Lau 		return PTR_ERR(map);
4436bd5f5f4eSMartin KaFai Lau 
44376e71b04aSChenbo Feng 	fd = bpf_map_new_fd(map, f_flags);
4438bd5f5f4eSMartin KaFai Lau 	if (fd < 0)
4439781e6282SPeng Sun 		bpf_map_put_with_uref(map);
4440bd5f5f4eSMartin KaFai Lau 
4441bd5f5f4eSMartin KaFai Lau 	return fd;
4442bd5f5f4eSMartin KaFai Lau }
4443bd5f5f4eSMartin KaFai Lau 
44447105e828SDaniel Borkmann static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog,
4445d8eca5bbSDaniel Borkmann 					      unsigned long addr, u32 *off,
4446d8eca5bbSDaniel Borkmann 					      u32 *type)
44477105e828SDaniel Borkmann {
4448d8eca5bbSDaniel Borkmann 	const struct bpf_map *map;
44497105e828SDaniel Borkmann 	int i;
44507105e828SDaniel Borkmann 
4451984fe94fSYiFei Zhu 	mutex_lock(&prog->aux->used_maps_mutex);
4452d8eca5bbSDaniel Borkmann 	for (i = 0, *off = 0; i < prog->aux->used_map_cnt; i++) {
4453d8eca5bbSDaniel Borkmann 		map = prog->aux->used_maps[i];
4454d8eca5bbSDaniel Borkmann 		if (map == (void *)addr) {
4455d8eca5bbSDaniel Borkmann 			*type = BPF_PSEUDO_MAP_FD;
4456984fe94fSYiFei Zhu 			goto out;
4457d8eca5bbSDaniel Borkmann 		}
4458d8eca5bbSDaniel Borkmann 		if (!map->ops->map_direct_value_meta)
4459d8eca5bbSDaniel Borkmann 			continue;
4460d8eca5bbSDaniel Borkmann 		if (!map->ops->map_direct_value_meta(map, addr, off)) {
4461d8eca5bbSDaniel Borkmann 			*type = BPF_PSEUDO_MAP_VALUE;
4462984fe94fSYiFei Zhu 			goto out;
4463d8eca5bbSDaniel Borkmann 		}
4464d8eca5bbSDaniel Borkmann 	}
4465984fe94fSYiFei Zhu 	map = NULL;
4466d8eca5bbSDaniel Borkmann 
4467984fe94fSYiFei Zhu out:
4468984fe94fSYiFei Zhu 	mutex_unlock(&prog->aux->used_maps_mutex);
4469984fe94fSYiFei Zhu 	return map;
44707105e828SDaniel Borkmann }
44717105e828SDaniel Borkmann 
447263960260SKees Cook static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog,
447363960260SKees Cook 					      const struct cred *f_cred)
44747105e828SDaniel Borkmann {
44757105e828SDaniel Borkmann 	const struct bpf_map *map;
44767105e828SDaniel Borkmann 	struct bpf_insn *insns;
4477d8eca5bbSDaniel Borkmann 	u32 off, type;
44787105e828SDaniel Borkmann 	u64 imm;
447929fcb05bSAndrii Nakryiko 	u8 code;
44807105e828SDaniel Borkmann 	int i;
44817105e828SDaniel Borkmann 
44827105e828SDaniel Borkmann 	insns = kmemdup(prog->insnsi, bpf_prog_insn_size(prog),
44837105e828SDaniel Borkmann 			GFP_USER);
44847105e828SDaniel Borkmann 	if (!insns)
44857105e828SDaniel Borkmann 		return insns;
44867105e828SDaniel Borkmann 
44877105e828SDaniel Borkmann 	for (i = 0; i < prog->len; i++) {
448829fcb05bSAndrii Nakryiko 		code = insns[i].code;
448929fcb05bSAndrii Nakryiko 
449029fcb05bSAndrii Nakryiko 		if (code == (BPF_JMP | BPF_TAIL_CALL)) {
44917105e828SDaniel Borkmann 			insns[i].code = BPF_JMP | BPF_CALL;
44927105e828SDaniel Borkmann 			insns[i].imm = BPF_FUNC_tail_call;
44937105e828SDaniel Borkmann 			/* fall-through */
44947105e828SDaniel Borkmann 		}
449529fcb05bSAndrii Nakryiko 		if (code == (BPF_JMP | BPF_CALL) ||
449629fcb05bSAndrii Nakryiko 		    code == (BPF_JMP | BPF_CALL_ARGS)) {
449729fcb05bSAndrii Nakryiko 			if (code == (BPF_JMP | BPF_CALL_ARGS))
44987105e828SDaniel Borkmann 				insns[i].code = BPF_JMP | BPF_CALL;
449963960260SKees Cook 			if (!bpf_dump_raw_ok(f_cred))
45007105e828SDaniel Borkmann 				insns[i].imm = 0;
45017105e828SDaniel Borkmann 			continue;
45027105e828SDaniel Borkmann 		}
450329fcb05bSAndrii Nakryiko 		if (BPF_CLASS(code) == BPF_LDX && BPF_MODE(code) == BPF_PROBE_MEM) {
450429fcb05bSAndrii Nakryiko 			insns[i].code = BPF_LDX | BPF_SIZE(code) | BPF_MEM;
450529fcb05bSAndrii Nakryiko 			continue;
450629fcb05bSAndrii Nakryiko 		}
45077105e828SDaniel Borkmann 
45086082b6c3SAlexei Starovoitov 		if ((BPF_CLASS(code) == BPF_LDX || BPF_CLASS(code) == BPF_STX ||
45096082b6c3SAlexei Starovoitov 		     BPF_CLASS(code) == BPF_ST) && BPF_MODE(code) == BPF_PROBE_MEM32) {
45106082b6c3SAlexei Starovoitov 			insns[i].code = BPF_CLASS(code) | BPF_SIZE(code) | BPF_MEM;
45116082b6c3SAlexei Starovoitov 			continue;
45126082b6c3SAlexei Starovoitov 		}
45136082b6c3SAlexei Starovoitov 
451429fcb05bSAndrii Nakryiko 		if (code != (BPF_LD | BPF_IMM | BPF_DW))
45157105e828SDaniel Borkmann 			continue;
45167105e828SDaniel Borkmann 
45177105e828SDaniel Borkmann 		imm = ((u64)insns[i + 1].imm << 32) | (u32)insns[i].imm;
4518d8eca5bbSDaniel Borkmann 		map = bpf_map_from_imm(prog, imm, &off, &type);
45197105e828SDaniel Borkmann 		if (map) {
4520d8eca5bbSDaniel Borkmann 			insns[i].src_reg = type;
45217105e828SDaniel Borkmann 			insns[i].imm = map->id;
4522d8eca5bbSDaniel Borkmann 			insns[i + 1].imm = off;
45237105e828SDaniel Borkmann 			continue;
45247105e828SDaniel Borkmann 		}
45257105e828SDaniel Borkmann 	}
45267105e828SDaniel Borkmann 
45277105e828SDaniel Borkmann 	return insns;
45287105e828SDaniel Borkmann }
45297105e828SDaniel Borkmann 
4530c454a46bSMartin KaFai Lau static int set_info_rec_size(struct bpf_prog_info *info)
4531c454a46bSMartin KaFai Lau {
4532c454a46bSMartin KaFai Lau 	/*
4533c454a46bSMartin KaFai Lau 	 * Ensure info.*_rec_size is the same as kernel expected size
4534c454a46bSMartin KaFai Lau 	 *
4535c454a46bSMartin KaFai Lau 	 * or
4536c454a46bSMartin KaFai Lau 	 *
4537c454a46bSMartin KaFai Lau 	 * Only allow zero *_rec_size if both _rec_size and _cnt are
4538c454a46bSMartin KaFai Lau 	 * zero.  In this case, the kernel will set the expected
4539c454a46bSMartin KaFai Lau 	 * _rec_size back to the info.
4540c454a46bSMartin KaFai Lau 	 */
4541c454a46bSMartin KaFai Lau 
454211d8b82dSYonghong Song 	if ((info->nr_func_info || info->func_info_rec_size) &&
4543c454a46bSMartin KaFai Lau 	    info->func_info_rec_size != sizeof(struct bpf_func_info))
4544c454a46bSMartin KaFai Lau 		return -EINVAL;
4545c454a46bSMartin KaFai Lau 
454611d8b82dSYonghong Song 	if ((info->nr_line_info || info->line_info_rec_size) &&
4547c454a46bSMartin KaFai Lau 	    info->line_info_rec_size != sizeof(struct bpf_line_info))
4548c454a46bSMartin KaFai Lau 		return -EINVAL;
4549c454a46bSMartin KaFai Lau 
455011d8b82dSYonghong Song 	if ((info->nr_jited_line_info || info->jited_line_info_rec_size) &&
4551c454a46bSMartin KaFai Lau 	    info->jited_line_info_rec_size != sizeof(__u64))
4552c454a46bSMartin KaFai Lau 		return -EINVAL;
4553c454a46bSMartin KaFai Lau 
4554c454a46bSMartin KaFai Lau 	info->func_info_rec_size = sizeof(struct bpf_func_info);
4555c454a46bSMartin KaFai Lau 	info->line_info_rec_size = sizeof(struct bpf_line_info);
4556c454a46bSMartin KaFai Lau 	info->jited_line_info_rec_size = sizeof(__u64);
4557c454a46bSMartin KaFai Lau 
4558c454a46bSMartin KaFai Lau 	return 0;
4559c454a46bSMartin KaFai Lau }
4560c454a46bSMartin KaFai Lau 
456163960260SKees Cook static int bpf_prog_get_info_by_fd(struct file *file,
456263960260SKees Cook 				   struct bpf_prog *prog,
45631e270976SMartin KaFai Lau 				   const union bpf_attr *attr,
45641e270976SMartin KaFai Lau 				   union bpf_attr __user *uattr)
45651e270976SMartin KaFai Lau {
45661e270976SMartin KaFai Lau 	struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info);
45676644aabbSStanislav Fomichev 	struct btf *attach_btf = bpf_prog_get_target_btf(prog);
45685c6f2588SGreg Kroah-Hartman 	struct bpf_prog_info info;
45691e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
457061a0abaeSEric Dumazet 	struct bpf_prog_kstats stats;
45711e270976SMartin KaFai Lau 	char __user *uinsns;
45721e270976SMartin KaFai Lau 	u32 ulen;
45731e270976SMartin KaFai Lau 	int err;
45741e270976SMartin KaFai Lau 
4575af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len);
45761e270976SMartin KaFai Lau 	if (err)
45771e270976SMartin KaFai Lau 		return err;
45781e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
45791e270976SMartin KaFai Lau 
45805c6f2588SGreg Kroah-Hartman 	memset(&info, 0, sizeof(info));
45811e270976SMartin KaFai Lau 	if (copy_from_user(&info, uinfo, info_len))
458289b09689SDaniel Borkmann 		return -EFAULT;
45831e270976SMartin KaFai Lau 
45841e270976SMartin KaFai Lau 	info.type = prog->type;
45851e270976SMartin KaFai Lau 	info.id = prog->aux->id;
4586cb4d2b3fSMartin KaFai Lau 	info.load_time = prog->aux->load_time;
4587cb4d2b3fSMartin KaFai Lau 	info.created_by_uid = from_kuid_munged(current_user_ns(),
4588cb4d2b3fSMartin KaFai Lau 					       prog->aux->user->uid);
4589b85fab0eSJiri Olsa 	info.gpl_compatible = prog->gpl_compatible;
45901e270976SMartin KaFai Lau 
45911e270976SMartin KaFai Lau 	memcpy(info.tag, prog->tag, sizeof(prog->tag));
4592cb4d2b3fSMartin KaFai Lau 	memcpy(info.name, prog->aux->name, sizeof(prog->aux->name));
4593cb4d2b3fSMartin KaFai Lau 
4594984fe94fSYiFei Zhu 	mutex_lock(&prog->aux->used_maps_mutex);
4595cb4d2b3fSMartin KaFai Lau 	ulen = info.nr_map_ids;
4596cb4d2b3fSMartin KaFai Lau 	info.nr_map_ids = prog->aux->used_map_cnt;
4597cb4d2b3fSMartin KaFai Lau 	ulen = min_t(u32, info.nr_map_ids, ulen);
4598cb4d2b3fSMartin KaFai Lau 	if (ulen) {
4599721e08daSMartin KaFai Lau 		u32 __user *user_map_ids = u64_to_user_ptr(info.map_ids);
4600cb4d2b3fSMartin KaFai Lau 		u32 i;
4601cb4d2b3fSMartin KaFai Lau 
4602cb4d2b3fSMartin KaFai Lau 		for (i = 0; i < ulen; i++)
4603cb4d2b3fSMartin KaFai Lau 			if (put_user(prog->aux->used_maps[i]->id,
4604984fe94fSYiFei Zhu 				     &user_map_ids[i])) {
4605984fe94fSYiFei Zhu 				mutex_unlock(&prog->aux->used_maps_mutex);
4606cb4d2b3fSMartin KaFai Lau 				return -EFAULT;
4607cb4d2b3fSMartin KaFai Lau 			}
4608984fe94fSYiFei Zhu 	}
4609984fe94fSYiFei Zhu 	mutex_unlock(&prog->aux->used_maps_mutex);
46101e270976SMartin KaFai Lau 
4611c454a46bSMartin KaFai Lau 	err = set_info_rec_size(&info);
4612c454a46bSMartin KaFai Lau 	if (err)
4613c454a46bSMartin KaFai Lau 		return err;
46147337224fSMartin KaFai Lau 
46155f8f8b93SAlexei Starovoitov 	bpf_prog_get_stats(prog, &stats);
46165f8f8b93SAlexei Starovoitov 	info.run_time_ns = stats.nsecs;
46175f8f8b93SAlexei Starovoitov 	info.run_cnt = stats.cnt;
46189ed9e9baSAlexei Starovoitov 	info.recursion_misses = stats.misses;
46195f8f8b93SAlexei Starovoitov 
4620aba64c7dSDave Marchevsky 	info.verified_insns = prog->aux->verified_insns;
4621aba64c7dSDave Marchevsky 
46222c78ee89SAlexei Starovoitov 	if (!bpf_capable()) {
46231e270976SMartin KaFai Lau 		info.jited_prog_len = 0;
46241e270976SMartin KaFai Lau 		info.xlated_prog_len = 0;
4625dbecd738SSandipan Das 		info.nr_jited_ksyms = 0;
462628c2fae7SDaniel Borkmann 		info.nr_jited_func_lens = 0;
462711d8b82dSYonghong Song 		info.nr_func_info = 0;
462811d8b82dSYonghong Song 		info.nr_line_info = 0;
462911d8b82dSYonghong Song 		info.nr_jited_line_info = 0;
46301e270976SMartin KaFai Lau 		goto done;
46311e270976SMartin KaFai Lau 	}
46321e270976SMartin KaFai Lau 
46331e270976SMartin KaFai Lau 	ulen = info.xlated_prog_len;
46349975a54bSDaniel Borkmann 	info.xlated_prog_len = bpf_prog_insn_size(prog);
46351e270976SMartin KaFai Lau 	if (info.xlated_prog_len && ulen) {
46367105e828SDaniel Borkmann 		struct bpf_insn *insns_sanitized;
46377105e828SDaniel Borkmann 		bool fault;
46387105e828SDaniel Borkmann 
463963960260SKees Cook 		if (prog->blinded && !bpf_dump_raw_ok(file->f_cred)) {
46407105e828SDaniel Borkmann 			info.xlated_prog_insns = 0;
46417105e828SDaniel Borkmann 			goto done;
46427105e828SDaniel Borkmann 		}
464363960260SKees Cook 		insns_sanitized = bpf_insn_prepare_dump(prog, file->f_cred);
46447105e828SDaniel Borkmann 		if (!insns_sanitized)
46457105e828SDaniel Borkmann 			return -ENOMEM;
46461e270976SMartin KaFai Lau 		uinsns = u64_to_user_ptr(info.xlated_prog_insns);
46471e270976SMartin KaFai Lau 		ulen = min_t(u32, info.xlated_prog_len, ulen);
46487105e828SDaniel Borkmann 		fault = copy_to_user(uinsns, insns_sanitized, ulen);
46497105e828SDaniel Borkmann 		kfree(insns_sanitized);
46507105e828SDaniel Borkmann 		if (fault)
46511e270976SMartin KaFai Lau 			return -EFAULT;
46521e270976SMartin KaFai Lau 	}
46531e270976SMartin KaFai Lau 
46549d03ebc7SStanislav Fomichev 	if (bpf_prog_is_offloaded(prog->aux)) {
4655675fc275SJakub Kicinski 		err = bpf_prog_offload_info_fill(&info, prog);
4656675fc275SJakub Kicinski 		if (err)
4657675fc275SJakub Kicinski 			return err;
4658fcfb126dSJiong Wang 		goto done;
4659fcfb126dSJiong Wang 	}
4660fcfb126dSJiong Wang 
4661fcfb126dSJiong Wang 	/* NOTE: the following code is supposed to be skipped for offload.
4662fcfb126dSJiong Wang 	 * bpf_prog_offload_info_fill() is the place to fill similar fields
4663fcfb126dSJiong Wang 	 * for offload.
4664fcfb126dSJiong Wang 	 */
4665fcfb126dSJiong Wang 	ulen = info.jited_prog_len;
46664d56a76eSSandipan Das 	if (prog->aux->func_cnt) {
46674d56a76eSSandipan Das 		u32 i;
46684d56a76eSSandipan Das 
46694d56a76eSSandipan Das 		info.jited_prog_len = 0;
46704d56a76eSSandipan Das 		for (i = 0; i < prog->aux->func_cnt; i++)
46714d56a76eSSandipan Das 			info.jited_prog_len += prog->aux->func[i]->jited_len;
46724d56a76eSSandipan Das 	} else {
4673fcfb126dSJiong Wang 		info.jited_prog_len = prog->jited_len;
46744d56a76eSSandipan Das 	}
46754d56a76eSSandipan Das 
4676fcfb126dSJiong Wang 	if (info.jited_prog_len && ulen) {
467763960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
4678fcfb126dSJiong Wang 			uinsns = u64_to_user_ptr(info.jited_prog_insns);
4679fcfb126dSJiong Wang 			ulen = min_t(u32, info.jited_prog_len, ulen);
46804d56a76eSSandipan Das 
46814d56a76eSSandipan Das 			/* for multi-function programs, copy the JITed
46824d56a76eSSandipan Das 			 * instructions for all the functions
46834d56a76eSSandipan Das 			 */
46844d56a76eSSandipan Das 			if (prog->aux->func_cnt) {
46854d56a76eSSandipan Das 				u32 len, free, i;
46864d56a76eSSandipan Das 				u8 *img;
46874d56a76eSSandipan Das 
46884d56a76eSSandipan Das 				free = ulen;
46894d56a76eSSandipan Das 				for (i = 0; i < prog->aux->func_cnt; i++) {
46904d56a76eSSandipan Das 					len = prog->aux->func[i]->jited_len;
46914d56a76eSSandipan Das 					len = min_t(u32, len, free);
46924d56a76eSSandipan Das 					img = (u8 *) prog->aux->func[i]->bpf_func;
46934d56a76eSSandipan Das 					if (copy_to_user(uinsns, img, len))
46944d56a76eSSandipan Das 						return -EFAULT;
46954d56a76eSSandipan Das 					uinsns += len;
46964d56a76eSSandipan Das 					free -= len;
46974d56a76eSSandipan Das 					if (!free)
46984d56a76eSSandipan Das 						break;
46994d56a76eSSandipan Das 				}
47004d56a76eSSandipan Das 			} else {
4701fcfb126dSJiong Wang 				if (copy_to_user(uinsns, prog->bpf_func, ulen))
4702fcfb126dSJiong Wang 					return -EFAULT;
47034d56a76eSSandipan Das 			}
4704fcfb126dSJiong Wang 		} else {
4705fcfb126dSJiong Wang 			info.jited_prog_insns = 0;
4706fcfb126dSJiong Wang 		}
4707675fc275SJakub Kicinski 	}
4708675fc275SJakub Kicinski 
4709dbecd738SSandipan Das 	ulen = info.nr_jited_ksyms;
4710ff1889fcSSong Liu 	info.nr_jited_ksyms = prog->aux->func_cnt ? : 1;
47117a5725ddSSong Liu 	if (ulen) {
471263960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
4713ff1889fcSSong Liu 			unsigned long ksym_addr;
4714dbecd738SSandipan Das 			u64 __user *user_ksyms;
4715dbecd738SSandipan Das 			u32 i;
4716dbecd738SSandipan Das 
4717dbecd738SSandipan Das 			/* copy the address of the kernel symbol
4718dbecd738SSandipan Das 			 * corresponding to each function
4719dbecd738SSandipan Das 			 */
4720dbecd738SSandipan Das 			ulen = min_t(u32, info.nr_jited_ksyms, ulen);
4721dbecd738SSandipan Das 			user_ksyms = u64_to_user_ptr(info.jited_ksyms);
4722ff1889fcSSong Liu 			if (prog->aux->func_cnt) {
4723dbecd738SSandipan Das 				for (i = 0; i < ulen; i++) {
4724ff1889fcSSong Liu 					ksym_addr = (unsigned long)
4725ff1889fcSSong Liu 						prog->aux->func[i]->bpf_func;
4726ff1889fcSSong Liu 					if (put_user((u64) ksym_addr,
4727ff1889fcSSong Liu 						     &user_ksyms[i]))
4728ff1889fcSSong Liu 						return -EFAULT;
4729ff1889fcSSong Liu 				}
4730ff1889fcSSong Liu 			} else {
4731ff1889fcSSong Liu 				ksym_addr = (unsigned long) prog->bpf_func;
4732ff1889fcSSong Liu 				if (put_user((u64) ksym_addr, &user_ksyms[0]))
4733dbecd738SSandipan Das 					return -EFAULT;
4734dbecd738SSandipan Das 			}
4735dbecd738SSandipan Das 		} else {
4736dbecd738SSandipan Das 			info.jited_ksyms = 0;
4737dbecd738SSandipan Das 		}
4738dbecd738SSandipan Das 	}
4739dbecd738SSandipan Das 
4740815581c1SSandipan Das 	ulen = info.nr_jited_func_lens;
4741ff1889fcSSong Liu 	info.nr_jited_func_lens = prog->aux->func_cnt ? : 1;
47427a5725ddSSong Liu 	if (ulen) {
474363960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
4744815581c1SSandipan Das 			u32 __user *user_lens;
4745815581c1SSandipan Das 			u32 func_len, i;
4746815581c1SSandipan Das 
4747815581c1SSandipan Das 			/* copy the JITed image lengths for each function */
4748815581c1SSandipan Das 			ulen = min_t(u32, info.nr_jited_func_lens, ulen);
4749815581c1SSandipan Das 			user_lens = u64_to_user_ptr(info.jited_func_lens);
4750ff1889fcSSong Liu 			if (prog->aux->func_cnt) {
4751815581c1SSandipan Das 				for (i = 0; i < ulen; i++) {
4752ff1889fcSSong Liu 					func_len =
4753ff1889fcSSong Liu 						prog->aux->func[i]->jited_len;
4754815581c1SSandipan Das 					if (put_user(func_len, &user_lens[i]))
4755815581c1SSandipan Das 						return -EFAULT;
4756815581c1SSandipan Das 				}
4757815581c1SSandipan Das 			} else {
4758ff1889fcSSong Liu 				func_len = prog->jited_len;
4759ff1889fcSSong Liu 				if (put_user(func_len, &user_lens[0]))
4760ff1889fcSSong Liu 					return -EFAULT;
4761ff1889fcSSong Liu 			}
4762ff1889fcSSong Liu 		} else {
4763815581c1SSandipan Das 			info.jited_func_lens = 0;
4764815581c1SSandipan Das 		}
4765815581c1SSandipan Das 	}
4766815581c1SSandipan Das 
47677337224fSMartin KaFai Lau 	if (prog->aux->btf)
476822dc4a0fSAndrii Nakryiko 		info.btf_id = btf_obj_id(prog->aux->btf);
4769b79c9fc9SStanislav Fomichev 	info.attach_btf_id = prog->aux->attach_btf_id;
47706644aabbSStanislav Fomichev 	if (attach_btf)
47716644aabbSStanislav Fomichev 		info.attach_btf_obj_id = btf_obj_id(attach_btf);
4772838e9690SYonghong Song 
477311d8b82dSYonghong Song 	ulen = info.nr_func_info;
477411d8b82dSYonghong Song 	info.nr_func_info = prog->aux->func_info_cnt;
477511d8b82dSYonghong Song 	if (info.nr_func_info && ulen) {
4776838e9690SYonghong Song 		char __user *user_finfo;
4777838e9690SYonghong Song 
4778838e9690SYonghong Song 		user_finfo = u64_to_user_ptr(info.func_info);
477911d8b82dSYonghong Song 		ulen = min_t(u32, info.nr_func_info, ulen);
4780ba64e7d8SYonghong Song 		if (copy_to_user(user_finfo, prog->aux->func_info,
47817337224fSMartin KaFai Lau 				 info.func_info_rec_size * ulen))
4782838e9690SYonghong Song 			return -EFAULT;
4783838e9690SYonghong Song 	}
4784838e9690SYonghong Song 
478511d8b82dSYonghong Song 	ulen = info.nr_line_info;
478611d8b82dSYonghong Song 	info.nr_line_info = prog->aux->nr_linfo;
478711d8b82dSYonghong Song 	if (info.nr_line_info && ulen) {
4788c454a46bSMartin KaFai Lau 		__u8 __user *user_linfo;
4789c454a46bSMartin KaFai Lau 
4790c454a46bSMartin KaFai Lau 		user_linfo = u64_to_user_ptr(info.line_info);
479111d8b82dSYonghong Song 		ulen = min_t(u32, info.nr_line_info, ulen);
4792c454a46bSMartin KaFai Lau 		if (copy_to_user(user_linfo, prog->aux->linfo,
4793c454a46bSMartin KaFai Lau 				 info.line_info_rec_size * ulen))
4794c454a46bSMartin KaFai Lau 			return -EFAULT;
4795c454a46bSMartin KaFai Lau 	}
4796c454a46bSMartin KaFai Lau 
479711d8b82dSYonghong Song 	ulen = info.nr_jited_line_info;
4798c454a46bSMartin KaFai Lau 	if (prog->aux->jited_linfo)
479911d8b82dSYonghong Song 		info.nr_jited_line_info = prog->aux->nr_linfo;
4800c454a46bSMartin KaFai Lau 	else
480111d8b82dSYonghong Song 		info.nr_jited_line_info = 0;
480211d8b82dSYonghong Song 	if (info.nr_jited_line_info && ulen) {
480363960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
48042cd00852SPu Lehui 			unsigned long line_addr;
4805c454a46bSMartin KaFai Lau 			__u64 __user *user_linfo;
4806c454a46bSMartin KaFai Lau 			u32 i;
4807c454a46bSMartin KaFai Lau 
4808c454a46bSMartin KaFai Lau 			user_linfo = u64_to_user_ptr(info.jited_line_info);
480911d8b82dSYonghong Song 			ulen = min_t(u32, info.nr_jited_line_info, ulen);
4810c454a46bSMartin KaFai Lau 			for (i = 0; i < ulen; i++) {
48112cd00852SPu Lehui 				line_addr = (unsigned long)prog->aux->jited_linfo[i];
48122cd00852SPu Lehui 				if (put_user((__u64)line_addr, &user_linfo[i]))
4813c454a46bSMartin KaFai Lau 					return -EFAULT;
4814c454a46bSMartin KaFai Lau 			}
4815c454a46bSMartin KaFai Lau 		} else {
4816c454a46bSMartin KaFai Lau 			info.jited_line_info = 0;
4817c454a46bSMartin KaFai Lau 		}
4818c454a46bSMartin KaFai Lau 	}
4819c454a46bSMartin KaFai Lau 
4820c872bdb3SSong Liu 	ulen = info.nr_prog_tags;
4821c872bdb3SSong Liu 	info.nr_prog_tags = prog->aux->func_cnt ? : 1;
4822c872bdb3SSong Liu 	if (ulen) {
4823c872bdb3SSong Liu 		__u8 __user (*user_prog_tags)[BPF_TAG_SIZE];
4824c872bdb3SSong Liu 		u32 i;
4825c872bdb3SSong Liu 
4826c872bdb3SSong Liu 		user_prog_tags = u64_to_user_ptr(info.prog_tags);
4827c872bdb3SSong Liu 		ulen = min_t(u32, info.nr_prog_tags, ulen);
4828c872bdb3SSong Liu 		if (prog->aux->func_cnt) {
4829c872bdb3SSong Liu 			for (i = 0; i < ulen; i++) {
4830c872bdb3SSong Liu 				if (copy_to_user(user_prog_tags[i],
4831c872bdb3SSong Liu 						 prog->aux->func[i]->tag,
4832c872bdb3SSong Liu 						 BPF_TAG_SIZE))
4833c872bdb3SSong Liu 					return -EFAULT;
4834c872bdb3SSong Liu 			}
4835c872bdb3SSong Liu 		} else {
4836c872bdb3SSong Liu 			if (copy_to_user(user_prog_tags[0],
4837c872bdb3SSong Liu 					 prog->tag, BPF_TAG_SIZE))
4838c872bdb3SSong Liu 				return -EFAULT;
4839c872bdb3SSong Liu 		}
4840c872bdb3SSong Liu 	}
4841c872bdb3SSong Liu 
48421e270976SMartin KaFai Lau done:
48431e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
48441e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
48451e270976SMartin KaFai Lau 		return -EFAULT;
48461e270976SMartin KaFai Lau 
48471e270976SMartin KaFai Lau 	return 0;
48481e270976SMartin KaFai Lau }
48491e270976SMartin KaFai Lau 
485063960260SKees Cook static int bpf_map_get_info_by_fd(struct file *file,
485163960260SKees Cook 				  struct bpf_map *map,
48521e270976SMartin KaFai Lau 				  const union bpf_attr *attr,
48531e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
48541e270976SMartin KaFai Lau {
48551e270976SMartin KaFai Lau 	struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info);
48565c6f2588SGreg Kroah-Hartman 	struct bpf_map_info info;
48571e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
48581e270976SMartin KaFai Lau 	int err;
48591e270976SMartin KaFai Lau 
4860af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len);
48611e270976SMartin KaFai Lau 	if (err)
48621e270976SMartin KaFai Lau 		return err;
48631e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
48641e270976SMartin KaFai Lau 
48655c6f2588SGreg Kroah-Hartman 	memset(&info, 0, sizeof(info));
48661e270976SMartin KaFai Lau 	info.type = map->map_type;
48671e270976SMartin KaFai Lau 	info.id = map->id;
48681e270976SMartin KaFai Lau 	info.key_size = map->key_size;
48691e270976SMartin KaFai Lau 	info.value_size = map->value_size;
48701e270976SMartin KaFai Lau 	info.max_entries = map->max_entries;
48711e270976SMartin KaFai Lau 	info.map_flags = map->map_flags;
48729330986cSJoanne Koong 	info.map_extra = map->map_extra;
4873ad5b177bSMartin KaFai Lau 	memcpy(info.name, map->name, sizeof(map->name));
48741e270976SMartin KaFai Lau 
487578958fcaSMartin KaFai Lau 	if (map->btf) {
487622dc4a0fSAndrii Nakryiko 		info.btf_id = btf_obj_id(map->btf);
48779b2cf328SMartin KaFai Lau 		info.btf_key_type_id = map->btf_key_type_id;
48789b2cf328SMartin KaFai Lau 		info.btf_value_type_id = map->btf_value_type_id;
487978958fcaSMartin KaFai Lau 	}
488085d33df3SMartin KaFai Lau 	info.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id;
48811338b933SKui-Feng Lee 	if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS)
48821338b933SKui-Feng Lee 		bpf_map_struct_ops_info_fill(&info, map);
488378958fcaSMartin KaFai Lau 
48849d03ebc7SStanislav Fomichev 	if (bpf_map_is_offloaded(map)) {
488552775b33SJakub Kicinski 		err = bpf_map_offload_info_fill(&info, map);
488652775b33SJakub Kicinski 		if (err)
488752775b33SJakub Kicinski 			return err;
488852775b33SJakub Kicinski 	}
488952775b33SJakub Kicinski 
48901e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
48911e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
48921e270976SMartin KaFai Lau 		return -EFAULT;
48931e270976SMartin KaFai Lau 
48941e270976SMartin KaFai Lau 	return 0;
48951e270976SMartin KaFai Lau }
48961e270976SMartin KaFai Lau 
489763960260SKees Cook static int bpf_btf_get_info_by_fd(struct file *file,
489863960260SKees Cook 				  struct btf *btf,
489962dab84cSMartin KaFai Lau 				  const union bpf_attr *attr,
490062dab84cSMartin KaFai Lau 				  union bpf_attr __user *uattr)
490162dab84cSMartin KaFai Lau {
490262dab84cSMartin KaFai Lau 	struct bpf_btf_info __user *uinfo = u64_to_user_ptr(attr->info.info);
490362dab84cSMartin KaFai Lau 	u32 info_len = attr->info.info_len;
490462dab84cSMartin KaFai Lau 	int err;
490562dab84cSMartin KaFai Lau 
4906af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(*uinfo), info_len);
490762dab84cSMartin KaFai Lau 	if (err)
490862dab84cSMartin KaFai Lau 		return err;
490962dab84cSMartin KaFai Lau 
491062dab84cSMartin KaFai Lau 	return btf_get_info_by_fd(btf, attr, uattr);
491162dab84cSMartin KaFai Lau }
491262dab84cSMartin KaFai Lau 
491363960260SKees Cook static int bpf_link_get_info_by_fd(struct file *file,
491463960260SKees Cook 				  struct bpf_link *link,
4915f2e10bffSAndrii Nakryiko 				  const union bpf_attr *attr,
4916f2e10bffSAndrii Nakryiko 				  union bpf_attr __user *uattr)
4917f2e10bffSAndrii Nakryiko {
4918f2e10bffSAndrii Nakryiko 	struct bpf_link_info __user *uinfo = u64_to_user_ptr(attr->info.info);
4919f2e10bffSAndrii Nakryiko 	struct bpf_link_info info;
4920f2e10bffSAndrii Nakryiko 	u32 info_len = attr->info.info_len;
4921f2e10bffSAndrii Nakryiko 	int err;
4922f2e10bffSAndrii Nakryiko 
4923af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len);
4924f2e10bffSAndrii Nakryiko 	if (err)
4925f2e10bffSAndrii Nakryiko 		return err;
4926f2e10bffSAndrii Nakryiko 	info_len = min_t(u32, sizeof(info), info_len);
4927f2e10bffSAndrii Nakryiko 
4928f2e10bffSAndrii Nakryiko 	memset(&info, 0, sizeof(info));
4929f2e10bffSAndrii Nakryiko 	if (copy_from_user(&info, uinfo, info_len))
4930f2e10bffSAndrii Nakryiko 		return -EFAULT;
4931f2e10bffSAndrii Nakryiko 
4932f2e10bffSAndrii Nakryiko 	info.type = link->type;
4933f2e10bffSAndrii Nakryiko 	info.id = link->id;
493468b04864SKui-Feng Lee 	if (link->prog)
4935f2e10bffSAndrii Nakryiko 		info.prog_id = link->prog->aux->id;
4936f2e10bffSAndrii Nakryiko 
4937f2e10bffSAndrii Nakryiko 	if (link->ops->fill_link_info) {
4938f2e10bffSAndrii Nakryiko 		err = link->ops->fill_link_info(link, &info);
4939f2e10bffSAndrii Nakryiko 		if (err)
4940f2e10bffSAndrii Nakryiko 			return err;
4941f2e10bffSAndrii Nakryiko 	}
4942f2e10bffSAndrii Nakryiko 
4943f2e10bffSAndrii Nakryiko 	if (copy_to_user(uinfo, &info, info_len) ||
4944f2e10bffSAndrii Nakryiko 	    put_user(info_len, &uattr->info.info_len))
4945f2e10bffSAndrii Nakryiko 		return -EFAULT;
4946f2e10bffSAndrii Nakryiko 
4947f2e10bffSAndrii Nakryiko 	return 0;
4948f2e10bffSAndrii Nakryiko }
4949f2e10bffSAndrii Nakryiko 
4950f2e10bffSAndrii Nakryiko 
49511e270976SMartin KaFai Lau #define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info
49521e270976SMartin KaFai Lau 
49531e270976SMartin KaFai Lau static int bpf_obj_get_info_by_fd(const union bpf_attr *attr,
49541e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
49551e270976SMartin KaFai Lau {
49561e270976SMartin KaFai Lau 	int ufd = attr->info.bpf_fd;
49571e270976SMartin KaFai Lau 	struct fd f;
49581e270976SMartin KaFai Lau 	int err;
49591e270976SMartin KaFai Lau 
49601e270976SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD))
49611e270976SMartin KaFai Lau 		return -EINVAL;
49621e270976SMartin KaFai Lau 
49631e270976SMartin KaFai Lau 	f = fdget(ufd);
49641e270976SMartin KaFai Lau 	if (!f.file)
49651e270976SMartin KaFai Lau 		return -EBADFD;
49661e270976SMartin KaFai Lau 
49671e270976SMartin KaFai Lau 	if (f.file->f_op == &bpf_prog_fops)
496863960260SKees Cook 		err = bpf_prog_get_info_by_fd(f.file, f.file->private_data, attr,
49691e270976SMartin KaFai Lau 					      uattr);
49701e270976SMartin KaFai Lau 	else if (f.file->f_op == &bpf_map_fops)
497163960260SKees Cook 		err = bpf_map_get_info_by_fd(f.file, f.file->private_data, attr,
49721e270976SMartin KaFai Lau 					     uattr);
497360197cfbSMartin KaFai Lau 	else if (f.file->f_op == &btf_fops)
497463960260SKees Cook 		err = bpf_btf_get_info_by_fd(f.file, f.file->private_data, attr, uattr);
4975f2e10bffSAndrii Nakryiko 	else if (f.file->f_op == &bpf_link_fops)
497663960260SKees Cook 		err = bpf_link_get_info_by_fd(f.file, f.file->private_data,
4977f2e10bffSAndrii Nakryiko 					      attr, uattr);
49781e270976SMartin KaFai Lau 	else
49791e270976SMartin KaFai Lau 		err = -EINVAL;
49801e270976SMartin KaFai Lau 
49811e270976SMartin KaFai Lau 	fdput(f);
49821e270976SMartin KaFai Lau 	return err;
49831e270976SMartin KaFai Lau }
49841e270976SMartin KaFai Lau 
49859ea7c4bfSAndrii Nakryiko #define BPF_BTF_LOAD_LAST_FIELD btf_token_fd
4986f56a653cSMartin KaFai Lau 
498747a71c1fSAndrii Nakryiko static int bpf_btf_load(const union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_size)
4988f56a653cSMartin KaFai Lau {
49899ea7c4bfSAndrii Nakryiko 	struct bpf_token *token = NULL;
49909ea7c4bfSAndrii Nakryiko 
4991f56a653cSMartin KaFai Lau 	if (CHECK_ATTR(BPF_BTF_LOAD))
4992f56a653cSMartin KaFai Lau 		return -EINVAL;
4993f56a653cSMartin KaFai Lau 
49949ea7c4bfSAndrii Nakryiko 	if (attr->btf_flags & ~BPF_F_TOKEN_FD)
49959ea7c4bfSAndrii Nakryiko 		return -EINVAL;
49969ea7c4bfSAndrii Nakryiko 
49979ea7c4bfSAndrii Nakryiko 	if (attr->btf_flags & BPF_F_TOKEN_FD) {
49989ea7c4bfSAndrii Nakryiko 		token = bpf_token_get_from_fd(attr->btf_token_fd);
49999ea7c4bfSAndrii Nakryiko 		if (IS_ERR(token))
50009ea7c4bfSAndrii Nakryiko 			return PTR_ERR(token);
50019ea7c4bfSAndrii Nakryiko 		if (!bpf_token_allow_cmd(token, BPF_BTF_LOAD)) {
50029ea7c4bfSAndrii Nakryiko 			bpf_token_put(token);
50039ea7c4bfSAndrii Nakryiko 			token = NULL;
50049ea7c4bfSAndrii Nakryiko 		}
50059ea7c4bfSAndrii Nakryiko 	}
50069ea7c4bfSAndrii Nakryiko 
50079ea7c4bfSAndrii Nakryiko 	if (!bpf_token_capable(token, CAP_BPF)) {
50089ea7c4bfSAndrii Nakryiko 		bpf_token_put(token);
5009f56a653cSMartin KaFai Lau 		return -EPERM;
50109ea7c4bfSAndrii Nakryiko 	}
50119ea7c4bfSAndrii Nakryiko 
50129ea7c4bfSAndrii Nakryiko 	bpf_token_put(token);
5013f56a653cSMartin KaFai Lau 
501447a71c1fSAndrii Nakryiko 	return btf_new_fd(attr, uattr, uattr_size);
5015f56a653cSMartin KaFai Lau }
5016f56a653cSMartin KaFai Lau 
501778958fcaSMartin KaFai Lau #define BPF_BTF_GET_FD_BY_ID_LAST_FIELD btf_id
501878958fcaSMartin KaFai Lau 
501978958fcaSMartin KaFai Lau static int bpf_btf_get_fd_by_id(const union bpf_attr *attr)
502078958fcaSMartin KaFai Lau {
502178958fcaSMartin KaFai Lau 	if (CHECK_ATTR(BPF_BTF_GET_FD_BY_ID))
502278958fcaSMartin KaFai Lau 		return -EINVAL;
502378958fcaSMartin KaFai Lau 
502478958fcaSMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
502578958fcaSMartin KaFai Lau 		return -EPERM;
502678958fcaSMartin KaFai Lau 
502778958fcaSMartin KaFai Lau 	return btf_get_fd_by_id(attr->btf_id);
502878958fcaSMartin KaFai Lau }
502978958fcaSMartin KaFai Lau 
503041bdc4b4SYonghong Song static int bpf_task_fd_query_copy(const union bpf_attr *attr,
503141bdc4b4SYonghong Song 				    union bpf_attr __user *uattr,
503241bdc4b4SYonghong Song 				    u32 prog_id, u32 fd_type,
503341bdc4b4SYonghong Song 				    const char *buf, u64 probe_offset,
503441bdc4b4SYonghong Song 				    u64 probe_addr)
503541bdc4b4SYonghong Song {
503641bdc4b4SYonghong Song 	char __user *ubuf = u64_to_user_ptr(attr->task_fd_query.buf);
503741bdc4b4SYonghong Song 	u32 len = buf ? strlen(buf) : 0, input_len;
503841bdc4b4SYonghong Song 	int err = 0;
503941bdc4b4SYonghong Song 
504041bdc4b4SYonghong Song 	if (put_user(len, &uattr->task_fd_query.buf_len))
504141bdc4b4SYonghong Song 		return -EFAULT;
504241bdc4b4SYonghong Song 	input_len = attr->task_fd_query.buf_len;
504341bdc4b4SYonghong Song 	if (input_len && ubuf) {
504441bdc4b4SYonghong Song 		if (!len) {
504541bdc4b4SYonghong Song 			/* nothing to copy, just make ubuf NULL terminated */
504641bdc4b4SYonghong Song 			char zero = '\0';
504741bdc4b4SYonghong Song 
504841bdc4b4SYonghong Song 			if (put_user(zero, ubuf))
504941bdc4b4SYonghong Song 				return -EFAULT;
505041bdc4b4SYonghong Song 		} else if (input_len >= len + 1) {
505141bdc4b4SYonghong Song 			/* ubuf can hold the string with NULL terminator */
505241bdc4b4SYonghong Song 			if (copy_to_user(ubuf, buf, len + 1))
505341bdc4b4SYonghong Song 				return -EFAULT;
505441bdc4b4SYonghong Song 		} else {
505541bdc4b4SYonghong Song 			/* ubuf cannot hold the string with NULL terminator,
505641bdc4b4SYonghong Song 			 * do a partial copy with NULL terminator.
505741bdc4b4SYonghong Song 			 */
505841bdc4b4SYonghong Song 			char zero = '\0';
505941bdc4b4SYonghong Song 
506041bdc4b4SYonghong Song 			err = -ENOSPC;
506141bdc4b4SYonghong Song 			if (copy_to_user(ubuf, buf, input_len - 1))
506241bdc4b4SYonghong Song 				return -EFAULT;
506341bdc4b4SYonghong Song 			if (put_user(zero, ubuf + input_len - 1))
506441bdc4b4SYonghong Song 				return -EFAULT;
506541bdc4b4SYonghong Song 		}
506641bdc4b4SYonghong Song 	}
506741bdc4b4SYonghong Song 
506841bdc4b4SYonghong Song 	if (put_user(prog_id, &uattr->task_fd_query.prog_id) ||
506941bdc4b4SYonghong Song 	    put_user(fd_type, &uattr->task_fd_query.fd_type) ||
507041bdc4b4SYonghong Song 	    put_user(probe_offset, &uattr->task_fd_query.probe_offset) ||
507141bdc4b4SYonghong Song 	    put_user(probe_addr, &uattr->task_fd_query.probe_addr))
507241bdc4b4SYonghong Song 		return -EFAULT;
507341bdc4b4SYonghong Song 
507441bdc4b4SYonghong Song 	return err;
507541bdc4b4SYonghong Song }
507641bdc4b4SYonghong Song 
507741bdc4b4SYonghong Song #define BPF_TASK_FD_QUERY_LAST_FIELD task_fd_query.probe_addr
507841bdc4b4SYonghong Song 
507941bdc4b4SYonghong Song static int bpf_task_fd_query(const union bpf_attr *attr,
508041bdc4b4SYonghong Song 			     union bpf_attr __user *uattr)
508141bdc4b4SYonghong Song {
508241bdc4b4SYonghong Song 	pid_t pid = attr->task_fd_query.pid;
508341bdc4b4SYonghong Song 	u32 fd = attr->task_fd_query.fd;
508441bdc4b4SYonghong Song 	const struct perf_event *event;
508541bdc4b4SYonghong Song 	struct task_struct *task;
508641bdc4b4SYonghong Song 	struct file *file;
508741bdc4b4SYonghong Song 	int err;
508841bdc4b4SYonghong Song 
508941bdc4b4SYonghong Song 	if (CHECK_ATTR(BPF_TASK_FD_QUERY))
509041bdc4b4SYonghong Song 		return -EINVAL;
509141bdc4b4SYonghong Song 
509241bdc4b4SYonghong Song 	if (!capable(CAP_SYS_ADMIN))
509341bdc4b4SYonghong Song 		return -EPERM;
509441bdc4b4SYonghong Song 
509541bdc4b4SYonghong Song 	if (attr->task_fd_query.flags != 0)
509641bdc4b4SYonghong Song 		return -EINVAL;
509741bdc4b4SYonghong Song 
509883c10cc3SLee Jones 	rcu_read_lock();
509941bdc4b4SYonghong Song 	task = get_pid_task(find_vpid(pid), PIDTYPE_PID);
510083c10cc3SLee Jones 	rcu_read_unlock();
510141bdc4b4SYonghong Song 	if (!task)
510241bdc4b4SYonghong Song 		return -ENOENT;
510341bdc4b4SYonghong Song 
510441bdc4b4SYonghong Song 	err = 0;
5105b48845afSEric W. Biederman 	file = fget_task(task, fd);
5106b48845afSEric W. Biederman 	put_task_struct(task);
510741bdc4b4SYonghong Song 	if (!file)
5108b48845afSEric W. Biederman 		return -EBADF;
510941bdc4b4SYonghong Song 
511070ed506cSAndrii Nakryiko 	if (file->f_op == &bpf_link_fops) {
511170ed506cSAndrii Nakryiko 		struct bpf_link *link = file->private_data;
511270ed506cSAndrii Nakryiko 
5113a3b80e10SAndrii Nakryiko 		if (link->ops == &bpf_raw_tp_link_lops) {
511470ed506cSAndrii Nakryiko 			struct bpf_raw_tp_link *raw_tp =
511570ed506cSAndrii Nakryiko 				container_of(link, struct bpf_raw_tp_link, link);
511641bdc4b4SYonghong Song 			struct bpf_raw_event_map *btp = raw_tp->btp;
511741bdc4b4SYonghong Song 
511841bdc4b4SYonghong Song 			err = bpf_task_fd_query_copy(attr, uattr,
511970ed506cSAndrii Nakryiko 						     raw_tp->link.prog->aux->id,
512041bdc4b4SYonghong Song 						     BPF_FD_TYPE_RAW_TRACEPOINT,
512141bdc4b4SYonghong Song 						     btp->tp->name, 0, 0);
512241bdc4b4SYonghong Song 			goto put_file;
512341bdc4b4SYonghong Song 		}
512470ed506cSAndrii Nakryiko 		goto out_not_supp;
512570ed506cSAndrii Nakryiko 	}
512641bdc4b4SYonghong Song 
512741bdc4b4SYonghong Song 	event = perf_get_event(file);
512841bdc4b4SYonghong Song 	if (!IS_ERR(event)) {
512941bdc4b4SYonghong Song 		u64 probe_offset, probe_addr;
513041bdc4b4SYonghong Song 		u32 prog_id, fd_type;
513141bdc4b4SYonghong Song 		const char *buf;
513241bdc4b4SYonghong Song 
513341bdc4b4SYonghong Song 		err = bpf_get_perf_event_info(event, &prog_id, &fd_type,
513441bdc4b4SYonghong Song 					      &buf, &probe_offset,
51353acf8aceSJiri Olsa 					      &probe_addr, NULL);
513641bdc4b4SYonghong Song 		if (!err)
513741bdc4b4SYonghong Song 			err = bpf_task_fd_query_copy(attr, uattr, prog_id,
513841bdc4b4SYonghong Song 						     fd_type, buf,
513941bdc4b4SYonghong Song 						     probe_offset,
514041bdc4b4SYonghong Song 						     probe_addr);
514141bdc4b4SYonghong Song 		goto put_file;
514241bdc4b4SYonghong Song 	}
514341bdc4b4SYonghong Song 
514470ed506cSAndrii Nakryiko out_not_supp:
514541bdc4b4SYonghong Song 	err = -ENOTSUPP;
514641bdc4b4SYonghong Song put_file:
514741bdc4b4SYonghong Song 	fput(file);
514841bdc4b4SYonghong Song 	return err;
514941bdc4b4SYonghong Song }
515041bdc4b4SYonghong Song 
5151cb4d03abSBrian Vazquez #define BPF_MAP_BATCH_LAST_FIELD batch.flags
5152cb4d03abSBrian Vazquez 
51533af43ba4SHou Tao #define BPF_DO_BATCH(fn, ...)			\
5154cb4d03abSBrian Vazquez 	do {					\
5155cb4d03abSBrian Vazquez 		if (!fn) {			\
5156cb4d03abSBrian Vazquez 			err = -ENOTSUPP;	\
5157cb4d03abSBrian Vazquez 			goto err_put;		\
5158cb4d03abSBrian Vazquez 		}				\
51593af43ba4SHou Tao 		err = fn(__VA_ARGS__);		\
5160cb4d03abSBrian Vazquez 	} while (0)
5161cb4d03abSBrian Vazquez 
5162cb4d03abSBrian Vazquez static int bpf_map_do_batch(const union bpf_attr *attr,
5163cb4d03abSBrian Vazquez 			    union bpf_attr __user *uattr,
5164cb4d03abSBrian Vazquez 			    int cmd)
5165cb4d03abSBrian Vazquez {
5166353050beSDaniel Borkmann 	bool has_read  = cmd == BPF_MAP_LOOKUP_BATCH ||
5167353050beSDaniel Borkmann 			 cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH;
5168353050beSDaniel Borkmann 	bool has_write = cmd != BPF_MAP_LOOKUP_BATCH;
5169cb4d03abSBrian Vazquez 	struct bpf_map *map;
5170cb4d03abSBrian Vazquez 	int err, ufd;
5171cb4d03abSBrian Vazquez 	struct fd f;
5172cb4d03abSBrian Vazquez 
5173cb4d03abSBrian Vazquez 	if (CHECK_ATTR(BPF_MAP_BATCH))
5174cb4d03abSBrian Vazquez 		return -EINVAL;
5175cb4d03abSBrian Vazquez 
5176cb4d03abSBrian Vazquez 	ufd = attr->batch.map_fd;
5177cb4d03abSBrian Vazquez 	f = fdget(ufd);
5178cb4d03abSBrian Vazquez 	map = __bpf_map_get(f);
5179cb4d03abSBrian Vazquez 	if (IS_ERR(map))
5180cb4d03abSBrian Vazquez 		return PTR_ERR(map);
5181353050beSDaniel Borkmann 	if (has_write)
5182353050beSDaniel Borkmann 		bpf_map_write_active_inc(map);
5183353050beSDaniel Borkmann 	if (has_read && !(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
5184cb4d03abSBrian Vazquez 		err = -EPERM;
5185cb4d03abSBrian Vazquez 		goto err_put;
5186cb4d03abSBrian Vazquez 	}
5187353050beSDaniel Borkmann 	if (has_write && !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
5188cb4d03abSBrian Vazquez 		err = -EPERM;
5189cb4d03abSBrian Vazquez 		goto err_put;
5190cb4d03abSBrian Vazquez 	}
5191cb4d03abSBrian Vazquez 
5192cb4d03abSBrian Vazquez 	if (cmd == BPF_MAP_LOOKUP_BATCH)
51933af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_lookup_batch, map, attr, uattr);
519405799638SYonghong Song 	else if (cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH)
51953af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_lookup_and_delete_batch, map, attr, uattr);
5196aa2e93b8SBrian Vazquez 	else if (cmd == BPF_MAP_UPDATE_BATCH)
51973af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_update_batch, map, f.file, attr, uattr);
5198aa2e93b8SBrian Vazquez 	else
51993af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_delete_batch, map, attr, uattr);
5200cb4d03abSBrian Vazquez err_put:
520101277258SHou Tao 	if (has_write) {
520201277258SHou Tao 		maybe_wait_bpf_programs(map);
5203353050beSDaniel Borkmann 		bpf_map_write_active_dec(map);
520401277258SHou Tao 	}
5205cb4d03abSBrian Vazquez 	fdput(f);
5206cb4d03abSBrian Vazquez 	return err;
5207cb4d03abSBrian Vazquez }
5208cb4d03abSBrian Vazquez 
5209b733eeadSJiri Olsa #define BPF_LINK_CREATE_LAST_FIELD link_create.uprobe_multi.pid
5210af2ac3e1SAlexei Starovoitov static int link_create(union bpf_attr *attr, bpfptr_t uattr)
5211af6eea57SAndrii Nakryiko {
5212af6eea57SAndrii Nakryiko 	struct bpf_prog *prog;
5213af6eea57SAndrii Nakryiko 	int ret;
5214af6eea57SAndrii Nakryiko 
5215af6eea57SAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_CREATE))
5216af6eea57SAndrii Nakryiko 		return -EINVAL;
5217af6eea57SAndrii Nakryiko 
521868b04864SKui-Feng Lee 	if (attr->link_create.attach_type == BPF_STRUCT_OPS)
521968b04864SKui-Feng Lee 		return bpf_struct_ops_link_create(attr);
522068b04864SKui-Feng Lee 
52214a1e7c0cSToke Høiland-Jørgensen 	prog = bpf_prog_get(attr->link_create.prog_fd);
5222af6eea57SAndrii Nakryiko 	if (IS_ERR(prog))
5223af6eea57SAndrii Nakryiko 		return PTR_ERR(prog);
5224af6eea57SAndrii Nakryiko 
5225af6eea57SAndrii Nakryiko 	ret = bpf_prog_attach_check_attach_type(prog,
5226af6eea57SAndrii Nakryiko 						attr->link_create.attach_type);
5227af6eea57SAndrii Nakryiko 	if (ret)
52284a1e7c0cSToke Høiland-Jørgensen 		goto out;
52294a1e7c0cSToke Høiland-Jørgensen 
5230b89fbfbbSAndrii Nakryiko 	switch (prog->type) {
5231af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SKB:
5232af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK:
5233af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
5234af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_SOCK_OPS:
5235af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_DEVICE:
5236af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
5237af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
5238af6eea57SAndrii Nakryiko 		ret = cgroup_bpf_link_attach(attr, prog);
5239af6eea57SAndrii Nakryiko 		break;
5240df86ca0dSAndrii Nakryiko 	case BPF_PROG_TYPE_EXT:
5241df86ca0dSAndrii Nakryiko 		ret = bpf_tracing_prog_attach(prog,
5242df86ca0dSAndrii Nakryiko 					      attr->link_create.target_fd,
52432fcc8241SKui-Feng Lee 					      attr->link_create.target_btf_id,
52442fcc8241SKui-Feng Lee 					      attr->link_create.tracing.cookie);
5245df86ca0dSAndrii Nakryiko 		break;
5246df86ca0dSAndrii Nakryiko 	case BPF_PROG_TYPE_LSM:
5247de4e05caSYonghong Song 	case BPF_PROG_TYPE_TRACING:
5248df86ca0dSAndrii Nakryiko 		if (attr->link_create.attach_type != prog->expected_attach_type) {
5249df86ca0dSAndrii Nakryiko 			ret = -EINVAL;
5250df86ca0dSAndrii Nakryiko 			goto out;
5251df86ca0dSAndrii Nakryiko 		}
5252df86ca0dSAndrii Nakryiko 		if (prog->expected_attach_type == BPF_TRACE_RAW_TP)
525368ca5d4eSAndrii Nakryiko 			ret = bpf_raw_tp_link_attach(prog, NULL, attr->link_create.tracing.cookie);
5254df86ca0dSAndrii Nakryiko 		else if (prog->expected_attach_type == BPF_TRACE_ITER)
5255df86ca0dSAndrii Nakryiko 			ret = bpf_iter_link_attach(attr, uattr, prog);
525669fd337aSStanislav Fomichev 		else if (prog->expected_attach_type == BPF_LSM_CGROUP)
525769fd337aSStanislav Fomichev 			ret = cgroup_bpf_link_attach(attr, prog);
5258df86ca0dSAndrii Nakryiko 		else
5259df86ca0dSAndrii Nakryiko 			ret = bpf_tracing_prog_attach(prog,
5260df86ca0dSAndrii Nakryiko 						      attr->link_create.target_fd,
52612fcc8241SKui-Feng Lee 						      attr->link_create.target_btf_id,
52622fcc8241SKui-Feng Lee 						      attr->link_create.tracing.cookie);
5263de4e05caSYonghong Song 		break;
52647f045a49SJakub Sitnicki 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
5265e9ddbb77SJakub Sitnicki 	case BPF_PROG_TYPE_SK_LOOKUP:
52667f045a49SJakub Sitnicki 		ret = netns_bpf_link_create(attr, prog);
52677f045a49SJakub Sitnicki 		break;
5268699c23f0SYonghong Song 	case BPF_PROG_TYPE_SK_MSG:
5269699c23f0SYonghong Song 	case BPF_PROG_TYPE_SK_SKB:
5270699c23f0SYonghong Song 		ret = sock_map_link_create(attr, prog);
5271699c23f0SYonghong Song 		break;
5272310ad797SAndrii Nakryiko #ifdef CONFIG_NET
5273aa8d3a71SAndrii Nakryiko 	case BPF_PROG_TYPE_XDP:
5274aa8d3a71SAndrii Nakryiko 		ret = bpf_xdp_link_attach(attr, prog);
5275aa8d3a71SAndrii Nakryiko 		break;
5276e420bed0SDaniel Borkmann 	case BPF_PROG_TYPE_SCHED_CLS:
527735dfaad7SDaniel Borkmann 		if (attr->link_create.attach_type == BPF_TCX_INGRESS ||
527835dfaad7SDaniel Borkmann 		    attr->link_create.attach_type == BPF_TCX_EGRESS)
5279e420bed0SDaniel Borkmann 			ret = tcx_link_attach(attr, prog);
528035dfaad7SDaniel Borkmann 		else
528135dfaad7SDaniel Borkmann 			ret = netkit_link_attach(attr, prog);
5282e420bed0SDaniel Borkmann 		break;
528384601d6eSFlorian Westphal 	case BPF_PROG_TYPE_NETFILTER:
528484601d6eSFlorian Westphal 		ret = bpf_nf_link_attach(attr, prog);
528584601d6eSFlorian Westphal 		break;
5286310ad797SAndrii Nakryiko #endif
5287b89fbfbbSAndrii Nakryiko 	case BPF_PROG_TYPE_PERF_EVENT:
5288b89fbfbbSAndrii Nakryiko 	case BPF_PROG_TYPE_TRACEPOINT:
5289b89fbfbbSAndrii Nakryiko 		ret = bpf_perf_link_attach(attr, prog);
5290b89fbfbbSAndrii Nakryiko 		break;
52910dcac272SJiri Olsa 	case BPF_PROG_TYPE_KPROBE:
52920dcac272SJiri Olsa 		if (attr->link_create.attach_type == BPF_PERF_EVENT)
52930dcac272SJiri Olsa 			ret = bpf_perf_link_attach(attr, prog);
5294535a3692SJiri Olsa 		else if (attr->link_create.attach_type == BPF_TRACE_KPROBE_MULTI ||
5295535a3692SJiri Olsa 			 attr->link_create.attach_type == BPF_TRACE_KPROBE_SESSION)
52960dcac272SJiri Olsa 			ret = bpf_kprobe_multi_link_attach(attr, prog);
529789ae89f5SJiri Olsa 		else if (attr->link_create.attach_type == BPF_TRACE_UPROBE_MULTI)
529889ae89f5SJiri Olsa 			ret = bpf_uprobe_multi_link_attach(attr, prog);
52990dcac272SJiri Olsa 		break;
5300af6eea57SAndrii Nakryiko 	default:
5301af6eea57SAndrii Nakryiko 		ret = -EINVAL;
5302af6eea57SAndrii Nakryiko 	}
5303af6eea57SAndrii Nakryiko 
53044a1e7c0cSToke Høiland-Jørgensen out:
5305af6eea57SAndrii Nakryiko 	if (ret < 0)
5306af6eea57SAndrii Nakryiko 		bpf_prog_put(prog);
5307af6eea57SAndrii Nakryiko 	return ret;
5308af6eea57SAndrii Nakryiko }
5309af6eea57SAndrii Nakryiko 
5310aef56f2eSKui-Feng Lee static int link_update_map(struct bpf_link *link, union bpf_attr *attr)
5311aef56f2eSKui-Feng Lee {
5312aef56f2eSKui-Feng Lee 	struct bpf_map *new_map, *old_map = NULL;
5313aef56f2eSKui-Feng Lee 	int ret;
5314aef56f2eSKui-Feng Lee 
5315aef56f2eSKui-Feng Lee 	new_map = bpf_map_get(attr->link_update.new_map_fd);
5316aef56f2eSKui-Feng Lee 	if (IS_ERR(new_map))
531755fbae05SMartin KaFai Lau 		return PTR_ERR(new_map);
5318aef56f2eSKui-Feng Lee 
5319aef56f2eSKui-Feng Lee 	if (attr->link_update.flags & BPF_F_REPLACE) {
5320aef56f2eSKui-Feng Lee 		old_map = bpf_map_get(attr->link_update.old_map_fd);
5321aef56f2eSKui-Feng Lee 		if (IS_ERR(old_map)) {
532255fbae05SMartin KaFai Lau 			ret = PTR_ERR(old_map);
5323aef56f2eSKui-Feng Lee 			goto out_put;
5324aef56f2eSKui-Feng Lee 		}
5325aef56f2eSKui-Feng Lee 	} else if (attr->link_update.old_map_fd) {
5326aef56f2eSKui-Feng Lee 		ret = -EINVAL;
5327aef56f2eSKui-Feng Lee 		goto out_put;
5328aef56f2eSKui-Feng Lee 	}
5329aef56f2eSKui-Feng Lee 
5330aef56f2eSKui-Feng Lee 	ret = link->ops->update_map(link, new_map, old_map);
5331aef56f2eSKui-Feng Lee 
5332aef56f2eSKui-Feng Lee 	if (old_map)
5333aef56f2eSKui-Feng Lee 		bpf_map_put(old_map);
5334aef56f2eSKui-Feng Lee out_put:
5335aef56f2eSKui-Feng Lee 	bpf_map_put(new_map);
5336aef56f2eSKui-Feng Lee 	return ret;
5337aef56f2eSKui-Feng Lee }
5338aef56f2eSKui-Feng Lee 
53390c991ebcSAndrii Nakryiko #define BPF_LINK_UPDATE_LAST_FIELD link_update.old_prog_fd
53400c991ebcSAndrii Nakryiko 
53410c991ebcSAndrii Nakryiko static int link_update(union bpf_attr *attr)
53420c991ebcSAndrii Nakryiko {
53430c991ebcSAndrii Nakryiko 	struct bpf_prog *old_prog = NULL, *new_prog;
53440c991ebcSAndrii Nakryiko 	struct bpf_link *link;
53450c991ebcSAndrii Nakryiko 	u32 flags;
53460c991ebcSAndrii Nakryiko 	int ret;
53470c991ebcSAndrii Nakryiko 
53480c991ebcSAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_UPDATE))
53490c991ebcSAndrii Nakryiko 		return -EINVAL;
53500c991ebcSAndrii Nakryiko 
53510c991ebcSAndrii Nakryiko 	flags = attr->link_update.flags;
53520c991ebcSAndrii Nakryiko 	if (flags & ~BPF_F_REPLACE)
53530c991ebcSAndrii Nakryiko 		return -EINVAL;
53540c991ebcSAndrii Nakryiko 
53550c991ebcSAndrii Nakryiko 	link = bpf_link_get_from_fd(attr->link_update.link_fd);
53560c991ebcSAndrii Nakryiko 	if (IS_ERR(link))
53570c991ebcSAndrii Nakryiko 		return PTR_ERR(link);
53580c991ebcSAndrii Nakryiko 
5359aef56f2eSKui-Feng Lee 	if (link->ops->update_map) {
5360aef56f2eSKui-Feng Lee 		ret = link_update_map(link, attr);
5361aef56f2eSKui-Feng Lee 		goto out_put_link;
5362aef56f2eSKui-Feng Lee 	}
5363aef56f2eSKui-Feng Lee 
53640c991ebcSAndrii Nakryiko 	new_prog = bpf_prog_get(attr->link_update.new_prog_fd);
53654adb7a4aSAndrii Nakryiko 	if (IS_ERR(new_prog)) {
53664adb7a4aSAndrii Nakryiko 		ret = PTR_ERR(new_prog);
53674adb7a4aSAndrii Nakryiko 		goto out_put_link;
53684adb7a4aSAndrii Nakryiko 	}
53690c991ebcSAndrii Nakryiko 
53700c991ebcSAndrii Nakryiko 	if (flags & BPF_F_REPLACE) {
53710c991ebcSAndrii Nakryiko 		old_prog = bpf_prog_get(attr->link_update.old_prog_fd);
53720c991ebcSAndrii Nakryiko 		if (IS_ERR(old_prog)) {
53730c991ebcSAndrii Nakryiko 			ret = PTR_ERR(old_prog);
53740c991ebcSAndrii Nakryiko 			old_prog = NULL;
53750c991ebcSAndrii Nakryiko 			goto out_put_progs;
53760c991ebcSAndrii Nakryiko 		}
53774adb7a4aSAndrii Nakryiko 	} else if (attr->link_update.old_prog_fd) {
53784adb7a4aSAndrii Nakryiko 		ret = -EINVAL;
53794adb7a4aSAndrii Nakryiko 		goto out_put_progs;
53800c991ebcSAndrii Nakryiko 	}
53810c991ebcSAndrii Nakryiko 
5382f9d04127SAndrii Nakryiko 	if (link->ops->update_prog)
5383f9d04127SAndrii Nakryiko 		ret = link->ops->update_prog(link, new_prog, old_prog);
5384f9d04127SAndrii Nakryiko 	else
53850c991ebcSAndrii Nakryiko 		ret = -EINVAL;
53860c991ebcSAndrii Nakryiko 
53870c991ebcSAndrii Nakryiko out_put_progs:
53880c991ebcSAndrii Nakryiko 	if (old_prog)
53890c991ebcSAndrii Nakryiko 		bpf_prog_put(old_prog);
53900c991ebcSAndrii Nakryiko 	if (ret)
53910c991ebcSAndrii Nakryiko 		bpf_prog_put(new_prog);
53924adb7a4aSAndrii Nakryiko out_put_link:
5393ab5d47bdSSebastian Andrzej Siewior 	bpf_link_put_direct(link);
53940c991ebcSAndrii Nakryiko 	return ret;
53950c991ebcSAndrii Nakryiko }
53960c991ebcSAndrii Nakryiko 
539773b11c2aSAndrii Nakryiko #define BPF_LINK_DETACH_LAST_FIELD link_detach.link_fd
539873b11c2aSAndrii Nakryiko 
539973b11c2aSAndrii Nakryiko static int link_detach(union bpf_attr *attr)
540073b11c2aSAndrii Nakryiko {
540173b11c2aSAndrii Nakryiko 	struct bpf_link *link;
540273b11c2aSAndrii Nakryiko 	int ret;
540373b11c2aSAndrii Nakryiko 
540473b11c2aSAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_DETACH))
540573b11c2aSAndrii Nakryiko 		return -EINVAL;
540673b11c2aSAndrii Nakryiko 
540773b11c2aSAndrii Nakryiko 	link = bpf_link_get_from_fd(attr->link_detach.link_fd);
540873b11c2aSAndrii Nakryiko 	if (IS_ERR(link))
540973b11c2aSAndrii Nakryiko 		return PTR_ERR(link);
541073b11c2aSAndrii Nakryiko 
541173b11c2aSAndrii Nakryiko 	if (link->ops->detach)
541273b11c2aSAndrii Nakryiko 		ret = link->ops->detach(link);
541373b11c2aSAndrii Nakryiko 	else
541473b11c2aSAndrii Nakryiko 		ret = -EOPNOTSUPP;
541573b11c2aSAndrii Nakryiko 
5416ab5d47bdSSebastian Andrzej Siewior 	bpf_link_put_direct(link);
541773b11c2aSAndrii Nakryiko 	return ret;
541873b11c2aSAndrii Nakryiko }
541973b11c2aSAndrii Nakryiko 
5420005142b8SAlexei Starovoitov static struct bpf_link *bpf_link_inc_not_zero(struct bpf_link *link)
54212d602c8cSAndrii Nakryiko {
5422005142b8SAlexei Starovoitov 	return atomic64_fetch_add_unless(&link->refcnt, 1, 0) ? link : ERR_PTR(-ENOENT);
5423005142b8SAlexei Starovoitov }
5424005142b8SAlexei Starovoitov 
5425005142b8SAlexei Starovoitov struct bpf_link *bpf_link_by_id(u32 id)
5426005142b8SAlexei Starovoitov {
5427005142b8SAlexei Starovoitov 	struct bpf_link *link;
5428005142b8SAlexei Starovoitov 
5429005142b8SAlexei Starovoitov 	if (!id)
5430005142b8SAlexei Starovoitov 		return ERR_PTR(-ENOENT);
5431005142b8SAlexei Starovoitov 
5432005142b8SAlexei Starovoitov 	spin_lock_bh(&link_idr_lock);
5433005142b8SAlexei Starovoitov 	/* before link is "settled", ID is 0, pretend it doesn't exist yet */
5434005142b8SAlexei Starovoitov 	link = idr_find(&link_idr, id);
5435005142b8SAlexei Starovoitov 	if (link) {
5436005142b8SAlexei Starovoitov 		if (link->id)
5437005142b8SAlexei Starovoitov 			link = bpf_link_inc_not_zero(link);
5438005142b8SAlexei Starovoitov 		else
5439005142b8SAlexei Starovoitov 			link = ERR_PTR(-EAGAIN);
5440005142b8SAlexei Starovoitov 	} else {
5441005142b8SAlexei Starovoitov 		link = ERR_PTR(-ENOENT);
5442005142b8SAlexei Starovoitov 	}
5443005142b8SAlexei Starovoitov 	spin_unlock_bh(&link_idr_lock);
5444005142b8SAlexei Starovoitov 	return link;
54452d602c8cSAndrii Nakryiko }
54462d602c8cSAndrii Nakryiko 
54479f883612SDmitrii Dolgov struct bpf_link *bpf_link_get_curr_or_next(u32 *id)
54489f883612SDmitrii Dolgov {
54499f883612SDmitrii Dolgov 	struct bpf_link *link;
54509f883612SDmitrii Dolgov 
54519f883612SDmitrii Dolgov 	spin_lock_bh(&link_idr_lock);
54529f883612SDmitrii Dolgov again:
54539f883612SDmitrii Dolgov 	link = idr_get_next(&link_idr, id);
54549f883612SDmitrii Dolgov 	if (link) {
54559f883612SDmitrii Dolgov 		link = bpf_link_inc_not_zero(link);
54569f883612SDmitrii Dolgov 		if (IS_ERR(link)) {
54579f883612SDmitrii Dolgov 			(*id)++;
54589f883612SDmitrii Dolgov 			goto again;
54599f883612SDmitrii Dolgov 		}
54609f883612SDmitrii Dolgov 	}
54619f883612SDmitrii Dolgov 	spin_unlock_bh(&link_idr_lock);
54629f883612SDmitrii Dolgov 
54639f883612SDmitrii Dolgov 	return link;
54649f883612SDmitrii Dolgov }
54659f883612SDmitrii Dolgov 
54662d602c8cSAndrii Nakryiko #define BPF_LINK_GET_FD_BY_ID_LAST_FIELD link_id
54672d602c8cSAndrii Nakryiko 
54682d602c8cSAndrii Nakryiko static int bpf_link_get_fd_by_id(const union bpf_attr *attr)
54692d602c8cSAndrii Nakryiko {
54702d602c8cSAndrii Nakryiko 	struct bpf_link *link;
54712d602c8cSAndrii Nakryiko 	u32 id = attr->link_id;
5472005142b8SAlexei Starovoitov 	int fd;
54732d602c8cSAndrii Nakryiko 
54742d602c8cSAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_GET_FD_BY_ID))
54752d602c8cSAndrii Nakryiko 		return -EINVAL;
54762d602c8cSAndrii Nakryiko 
54772d602c8cSAndrii Nakryiko 	if (!capable(CAP_SYS_ADMIN))
54782d602c8cSAndrii Nakryiko 		return -EPERM;
54792d602c8cSAndrii Nakryiko 
5480005142b8SAlexei Starovoitov 	link = bpf_link_by_id(id);
5481005142b8SAlexei Starovoitov 	if (IS_ERR(link))
5482005142b8SAlexei Starovoitov 		return PTR_ERR(link);
54832d602c8cSAndrii Nakryiko 
54842d602c8cSAndrii Nakryiko 	fd = bpf_link_new_fd(link);
54852d602c8cSAndrii Nakryiko 	if (fd < 0)
5486ab5d47bdSSebastian Andrzej Siewior 		bpf_link_put_direct(link);
54872d602c8cSAndrii Nakryiko 
54882d602c8cSAndrii Nakryiko 	return fd;
54892d602c8cSAndrii Nakryiko }
54902d602c8cSAndrii Nakryiko 
5491d46edd67SSong Liu DEFINE_MUTEX(bpf_stats_enabled_mutex);
5492d46edd67SSong Liu 
5493d46edd67SSong Liu static int bpf_stats_release(struct inode *inode, struct file *file)
5494d46edd67SSong Liu {
5495d46edd67SSong Liu 	mutex_lock(&bpf_stats_enabled_mutex);
5496d46edd67SSong Liu 	static_key_slow_dec(&bpf_stats_enabled_key.key);
5497d46edd67SSong Liu 	mutex_unlock(&bpf_stats_enabled_mutex);
5498d46edd67SSong Liu 	return 0;
5499d46edd67SSong Liu }
5500d46edd67SSong Liu 
5501d46edd67SSong Liu static const struct file_operations bpf_stats_fops = {
5502d46edd67SSong Liu 	.release = bpf_stats_release,
5503d46edd67SSong Liu };
5504d46edd67SSong Liu 
5505d46edd67SSong Liu static int bpf_enable_runtime_stats(void)
5506d46edd67SSong Liu {
5507d46edd67SSong Liu 	int fd;
5508d46edd67SSong Liu 
5509d46edd67SSong Liu 	mutex_lock(&bpf_stats_enabled_mutex);
5510d46edd67SSong Liu 
5511d46edd67SSong Liu 	/* Set a very high limit to avoid overflow */
5512d46edd67SSong Liu 	if (static_key_count(&bpf_stats_enabled_key.key) > INT_MAX / 2) {
5513d46edd67SSong Liu 		mutex_unlock(&bpf_stats_enabled_mutex);
5514d46edd67SSong Liu 		return -EBUSY;
5515d46edd67SSong Liu 	}
5516d46edd67SSong Liu 
5517d46edd67SSong Liu 	fd = anon_inode_getfd("bpf-stats", &bpf_stats_fops, NULL, O_CLOEXEC);
5518d46edd67SSong Liu 	if (fd >= 0)
5519d46edd67SSong Liu 		static_key_slow_inc(&bpf_stats_enabled_key.key);
5520d46edd67SSong Liu 
5521d46edd67SSong Liu 	mutex_unlock(&bpf_stats_enabled_mutex);
5522d46edd67SSong Liu 	return fd;
5523d46edd67SSong Liu }
5524d46edd67SSong Liu 
5525d46edd67SSong Liu #define BPF_ENABLE_STATS_LAST_FIELD enable_stats.type
5526d46edd67SSong Liu 
5527d46edd67SSong Liu static int bpf_enable_stats(union bpf_attr *attr)
5528d46edd67SSong Liu {
5529d46edd67SSong Liu 
5530d46edd67SSong Liu 	if (CHECK_ATTR(BPF_ENABLE_STATS))
5531d46edd67SSong Liu 		return -EINVAL;
5532d46edd67SSong Liu 
5533d46edd67SSong Liu 	if (!capable(CAP_SYS_ADMIN))
5534d46edd67SSong Liu 		return -EPERM;
5535d46edd67SSong Liu 
5536d46edd67SSong Liu 	switch (attr->enable_stats.type) {
5537d46edd67SSong Liu 	case BPF_STATS_RUN_TIME:
5538d46edd67SSong Liu 		return bpf_enable_runtime_stats();
5539d46edd67SSong Liu 	default:
5540d46edd67SSong Liu 		break;
5541d46edd67SSong Liu 	}
5542d46edd67SSong Liu 	return -EINVAL;
5543d46edd67SSong Liu }
5544d46edd67SSong Liu 
5545ac51d99bSYonghong Song #define BPF_ITER_CREATE_LAST_FIELD iter_create.flags
5546ac51d99bSYonghong Song 
5547ac51d99bSYonghong Song static int bpf_iter_create(union bpf_attr *attr)
5548ac51d99bSYonghong Song {
5549ac51d99bSYonghong Song 	struct bpf_link *link;
5550ac51d99bSYonghong Song 	int err;
5551ac51d99bSYonghong Song 
5552ac51d99bSYonghong Song 	if (CHECK_ATTR(BPF_ITER_CREATE))
5553ac51d99bSYonghong Song 		return -EINVAL;
5554ac51d99bSYonghong Song 
5555ac51d99bSYonghong Song 	if (attr->iter_create.flags)
5556ac51d99bSYonghong Song 		return -EINVAL;
5557ac51d99bSYonghong Song 
5558ac51d99bSYonghong Song 	link = bpf_link_get_from_fd(attr->iter_create.link_fd);
5559ac51d99bSYonghong Song 	if (IS_ERR(link))
5560ac51d99bSYonghong Song 		return PTR_ERR(link);
5561ac51d99bSYonghong Song 
5562ac51d99bSYonghong Song 	err = bpf_iter_new_fd(link);
5563ab5d47bdSSebastian Andrzej Siewior 	bpf_link_put_direct(link);
5564ac51d99bSYonghong Song 
5565ac51d99bSYonghong Song 	return err;
5566ac51d99bSYonghong Song }
5567ac51d99bSYonghong Song 
5568ef15314aSYiFei Zhu #define BPF_PROG_BIND_MAP_LAST_FIELD prog_bind_map.flags
5569ef15314aSYiFei Zhu 
5570ef15314aSYiFei Zhu static int bpf_prog_bind_map(union bpf_attr *attr)
5571ef15314aSYiFei Zhu {
5572ef15314aSYiFei Zhu 	struct bpf_prog *prog;
5573ef15314aSYiFei Zhu 	struct bpf_map *map;
5574ef15314aSYiFei Zhu 	struct bpf_map **used_maps_old, **used_maps_new;
5575ef15314aSYiFei Zhu 	int i, ret = 0;
5576ef15314aSYiFei Zhu 
5577ef15314aSYiFei Zhu 	if (CHECK_ATTR(BPF_PROG_BIND_MAP))
5578ef15314aSYiFei Zhu 		return -EINVAL;
5579ef15314aSYiFei Zhu 
5580ef15314aSYiFei Zhu 	if (attr->prog_bind_map.flags)
5581ef15314aSYiFei Zhu 		return -EINVAL;
5582ef15314aSYiFei Zhu 
5583ef15314aSYiFei Zhu 	prog = bpf_prog_get(attr->prog_bind_map.prog_fd);
5584ef15314aSYiFei Zhu 	if (IS_ERR(prog))
5585ef15314aSYiFei Zhu 		return PTR_ERR(prog);
5586ef15314aSYiFei Zhu 
5587ef15314aSYiFei Zhu 	map = bpf_map_get(attr->prog_bind_map.map_fd);
5588ef15314aSYiFei Zhu 	if (IS_ERR(map)) {
5589ef15314aSYiFei Zhu 		ret = PTR_ERR(map);
5590ef15314aSYiFei Zhu 		goto out_prog_put;
5591ef15314aSYiFei Zhu 	}
5592ef15314aSYiFei Zhu 
5593ef15314aSYiFei Zhu 	mutex_lock(&prog->aux->used_maps_mutex);
5594ef15314aSYiFei Zhu 
5595ef15314aSYiFei Zhu 	used_maps_old = prog->aux->used_maps;
5596ef15314aSYiFei Zhu 
5597ef15314aSYiFei Zhu 	for (i = 0; i < prog->aux->used_map_cnt; i++)
55981028ae40SStanislav Fomichev 		if (used_maps_old[i] == map) {
55991028ae40SStanislav Fomichev 			bpf_map_put(map);
5600ef15314aSYiFei Zhu 			goto out_unlock;
56011028ae40SStanislav Fomichev 		}
5602ef15314aSYiFei Zhu 
5603ef15314aSYiFei Zhu 	used_maps_new = kmalloc_array(prog->aux->used_map_cnt + 1,
5604ef15314aSYiFei Zhu 				      sizeof(used_maps_new[0]),
5605ef15314aSYiFei Zhu 				      GFP_KERNEL);
5606ef15314aSYiFei Zhu 	if (!used_maps_new) {
5607ef15314aSYiFei Zhu 		ret = -ENOMEM;
5608ef15314aSYiFei Zhu 		goto out_unlock;
5609ef15314aSYiFei Zhu 	}
5610ef15314aSYiFei Zhu 
5611af66bfd3SHou Tao 	/* The bpf program will not access the bpf map, but for the sake of
5612af66bfd3SHou Tao 	 * simplicity, increase sleepable_refcnt for sleepable program as well.
5613af66bfd3SHou Tao 	 */
561466c84731SAndrii Nakryiko 	if (prog->sleepable)
5615af66bfd3SHou Tao 		atomic64_inc(&map->sleepable_refcnt);
5616ef15314aSYiFei Zhu 	memcpy(used_maps_new, used_maps_old,
5617ef15314aSYiFei Zhu 	       sizeof(used_maps_old[0]) * prog->aux->used_map_cnt);
5618ef15314aSYiFei Zhu 	used_maps_new[prog->aux->used_map_cnt] = map;
5619ef15314aSYiFei Zhu 
5620ef15314aSYiFei Zhu 	prog->aux->used_map_cnt++;
5621ef15314aSYiFei Zhu 	prog->aux->used_maps = used_maps_new;
5622ef15314aSYiFei Zhu 
5623ef15314aSYiFei Zhu 	kfree(used_maps_old);
5624ef15314aSYiFei Zhu 
5625ef15314aSYiFei Zhu out_unlock:
5626ef15314aSYiFei Zhu 	mutex_unlock(&prog->aux->used_maps_mutex);
5627ef15314aSYiFei Zhu 
5628ef15314aSYiFei Zhu 	if (ret)
5629ef15314aSYiFei Zhu 		bpf_map_put(map);
5630ef15314aSYiFei Zhu out_prog_put:
5631ef15314aSYiFei Zhu 	bpf_prog_put(prog);
5632ef15314aSYiFei Zhu 	return ret;
5633ef15314aSYiFei Zhu }
5634ef15314aSYiFei Zhu 
563535f96de0SAndrii Nakryiko #define BPF_TOKEN_CREATE_LAST_FIELD token_create.bpffs_fd
563635f96de0SAndrii Nakryiko 
563735f96de0SAndrii Nakryiko static int token_create(union bpf_attr *attr)
563835f96de0SAndrii Nakryiko {
563935f96de0SAndrii Nakryiko 	if (CHECK_ATTR(BPF_TOKEN_CREATE))
564035f96de0SAndrii Nakryiko 		return -EINVAL;
564135f96de0SAndrii Nakryiko 
564235f96de0SAndrii Nakryiko 	/* no flags are supported yet */
564335f96de0SAndrii Nakryiko 	if (attr->token_create.flags)
564435f96de0SAndrii Nakryiko 		return -EINVAL;
564535f96de0SAndrii Nakryiko 
564635f96de0SAndrii Nakryiko 	return bpf_token_create(attr);
564735f96de0SAndrii Nakryiko }
564835f96de0SAndrii Nakryiko 
5649af2ac3e1SAlexei Starovoitov static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size)
565099c55f7dSAlexei Starovoitov {
56518096f229SGreg Kroah-Hartman 	union bpf_attr attr;
565299c55f7dSAlexei Starovoitov 	int err;
565399c55f7dSAlexei Starovoitov 
5654dcab51f1SMartin KaFai Lau 	err = bpf_check_uarg_tail_zero(uattr, sizeof(attr), size);
565599c55f7dSAlexei Starovoitov 	if (err)
565699c55f7dSAlexei Starovoitov 		return err;
56571e270976SMartin KaFai Lau 	size = min_t(u32, size, sizeof(attr));
565899c55f7dSAlexei Starovoitov 
565999c55f7dSAlexei Starovoitov 	/* copy attributes from user space, may be less than sizeof(bpf_attr) */
56608096f229SGreg Kroah-Hartman 	memset(&attr, 0, sizeof(attr));
5661af2ac3e1SAlexei Starovoitov 	if (copy_from_bpfptr(&attr, uattr, size) != 0)
566299c55f7dSAlexei Starovoitov 		return -EFAULT;
566399c55f7dSAlexei Starovoitov 
5664afdb09c7SChenbo Feng 	err = security_bpf(cmd, &attr, size);
5665afdb09c7SChenbo Feng 	if (err < 0)
5666afdb09c7SChenbo Feng 		return err;
5667afdb09c7SChenbo Feng 
566899c55f7dSAlexei Starovoitov 	switch (cmd) {
566999c55f7dSAlexei Starovoitov 	case BPF_MAP_CREATE:
567099c55f7dSAlexei Starovoitov 		err = map_create(&attr);
567199c55f7dSAlexei Starovoitov 		break;
5672db20fd2bSAlexei Starovoitov 	case BPF_MAP_LOOKUP_ELEM:
5673db20fd2bSAlexei Starovoitov 		err = map_lookup_elem(&attr);
5674db20fd2bSAlexei Starovoitov 		break;
5675db20fd2bSAlexei Starovoitov 	case BPF_MAP_UPDATE_ELEM:
5676af2ac3e1SAlexei Starovoitov 		err = map_update_elem(&attr, uattr);
5677db20fd2bSAlexei Starovoitov 		break;
5678db20fd2bSAlexei Starovoitov 	case BPF_MAP_DELETE_ELEM:
5679b88df697SBenjamin Tissoires 		err = map_delete_elem(&attr, uattr);
5680db20fd2bSAlexei Starovoitov 		break;
5681db20fd2bSAlexei Starovoitov 	case BPF_MAP_GET_NEXT_KEY:
5682db20fd2bSAlexei Starovoitov 		err = map_get_next_key(&attr);
5683db20fd2bSAlexei Starovoitov 		break;
568487df15deSDaniel Borkmann 	case BPF_MAP_FREEZE:
568587df15deSDaniel Borkmann 		err = map_freeze(&attr);
568687df15deSDaniel Borkmann 		break;
568709756af4SAlexei Starovoitov 	case BPF_PROG_LOAD:
568847a71c1fSAndrii Nakryiko 		err = bpf_prog_load(&attr, uattr, size);
568909756af4SAlexei Starovoitov 		break;
5690b2197755SDaniel Borkmann 	case BPF_OBJ_PIN:
5691b2197755SDaniel Borkmann 		err = bpf_obj_pin(&attr);
5692b2197755SDaniel Borkmann 		break;
5693b2197755SDaniel Borkmann 	case BPF_OBJ_GET:
5694b2197755SDaniel Borkmann 		err = bpf_obj_get(&attr);
5695b2197755SDaniel Borkmann 		break;
5696f4324551SDaniel Mack 	case BPF_PROG_ATTACH:
5697f4324551SDaniel Mack 		err = bpf_prog_attach(&attr);
5698f4324551SDaniel Mack 		break;
5699f4324551SDaniel Mack 	case BPF_PROG_DETACH:
5700f4324551SDaniel Mack 		err = bpf_prog_detach(&attr);
5701f4324551SDaniel Mack 		break;
5702468e2f64SAlexei Starovoitov 	case BPF_PROG_QUERY:
5703af2ac3e1SAlexei Starovoitov 		err = bpf_prog_query(&attr, uattr.user);
5704468e2f64SAlexei Starovoitov 		break;
57051cf1cae9SAlexei Starovoitov 	case BPF_PROG_TEST_RUN:
5706af2ac3e1SAlexei Starovoitov 		err = bpf_prog_test_run(&attr, uattr.user);
57071cf1cae9SAlexei Starovoitov 		break;
570834ad5580SMartin KaFai Lau 	case BPF_PROG_GET_NEXT_ID:
5709af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
571034ad5580SMartin KaFai Lau 					  &prog_idr, &prog_idr_lock);
571134ad5580SMartin KaFai Lau 		break;
571234ad5580SMartin KaFai Lau 	case BPF_MAP_GET_NEXT_ID:
5713af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
571434ad5580SMartin KaFai Lau 					  &map_idr, &map_idr_lock);
571534ad5580SMartin KaFai Lau 		break;
57161b9ed84eSQuentin Monnet 	case BPF_BTF_GET_NEXT_ID:
5717af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
57181b9ed84eSQuentin Monnet 					  &btf_idr, &btf_idr_lock);
57191b9ed84eSQuentin Monnet 		break;
5720b16d9aa4SMartin KaFai Lau 	case BPF_PROG_GET_FD_BY_ID:
5721b16d9aa4SMartin KaFai Lau 		err = bpf_prog_get_fd_by_id(&attr);
5722b16d9aa4SMartin KaFai Lau 		break;
5723bd5f5f4eSMartin KaFai Lau 	case BPF_MAP_GET_FD_BY_ID:
5724bd5f5f4eSMartin KaFai Lau 		err = bpf_map_get_fd_by_id(&attr);
5725bd5f5f4eSMartin KaFai Lau 		break;
57261e270976SMartin KaFai Lau 	case BPF_OBJ_GET_INFO_BY_FD:
5727af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_info_by_fd(&attr, uattr.user);
57281e270976SMartin KaFai Lau 		break;
5729c4f6699dSAlexei Starovoitov 	case BPF_RAW_TRACEPOINT_OPEN:
5730c4f6699dSAlexei Starovoitov 		err = bpf_raw_tracepoint_open(&attr);
5731c4f6699dSAlexei Starovoitov 		break;
5732f56a653cSMartin KaFai Lau 	case BPF_BTF_LOAD:
573347a71c1fSAndrii Nakryiko 		err = bpf_btf_load(&attr, uattr, size);
5734f56a653cSMartin KaFai Lau 		break;
573578958fcaSMartin KaFai Lau 	case BPF_BTF_GET_FD_BY_ID:
573678958fcaSMartin KaFai Lau 		err = bpf_btf_get_fd_by_id(&attr);
573778958fcaSMartin KaFai Lau 		break;
573841bdc4b4SYonghong Song 	case BPF_TASK_FD_QUERY:
5739af2ac3e1SAlexei Starovoitov 		err = bpf_task_fd_query(&attr, uattr.user);
574041bdc4b4SYonghong Song 		break;
5741bd513cd0SMauricio Vasquez B 	case BPF_MAP_LOOKUP_AND_DELETE_ELEM:
5742bd513cd0SMauricio Vasquez B 		err = map_lookup_and_delete_elem(&attr);
5743bd513cd0SMauricio Vasquez B 		break;
5744cb4d03abSBrian Vazquez 	case BPF_MAP_LOOKUP_BATCH:
5745af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_LOOKUP_BATCH);
5746cb4d03abSBrian Vazquez 		break;
574705799638SYonghong Song 	case BPF_MAP_LOOKUP_AND_DELETE_BATCH:
5748af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user,
574905799638SYonghong Song 				       BPF_MAP_LOOKUP_AND_DELETE_BATCH);
575005799638SYonghong Song 		break;
5751aa2e93b8SBrian Vazquez 	case BPF_MAP_UPDATE_BATCH:
5752af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_UPDATE_BATCH);
5753aa2e93b8SBrian Vazquez 		break;
5754aa2e93b8SBrian Vazquez 	case BPF_MAP_DELETE_BATCH:
5755af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_DELETE_BATCH);
5756aa2e93b8SBrian Vazquez 		break;
5757af6eea57SAndrii Nakryiko 	case BPF_LINK_CREATE:
5758af2ac3e1SAlexei Starovoitov 		err = link_create(&attr, uattr);
5759af6eea57SAndrii Nakryiko 		break;
57600c991ebcSAndrii Nakryiko 	case BPF_LINK_UPDATE:
57610c991ebcSAndrii Nakryiko 		err = link_update(&attr);
57620c991ebcSAndrii Nakryiko 		break;
57632d602c8cSAndrii Nakryiko 	case BPF_LINK_GET_FD_BY_ID:
57642d602c8cSAndrii Nakryiko 		err = bpf_link_get_fd_by_id(&attr);
57652d602c8cSAndrii Nakryiko 		break;
57662d602c8cSAndrii Nakryiko 	case BPF_LINK_GET_NEXT_ID:
5767af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
57682d602c8cSAndrii Nakryiko 					  &link_idr, &link_idr_lock);
57692d602c8cSAndrii Nakryiko 		break;
5770d46edd67SSong Liu 	case BPF_ENABLE_STATS:
5771d46edd67SSong Liu 		err = bpf_enable_stats(&attr);
5772d46edd67SSong Liu 		break;
5773ac51d99bSYonghong Song 	case BPF_ITER_CREATE:
5774ac51d99bSYonghong Song 		err = bpf_iter_create(&attr);
5775ac51d99bSYonghong Song 		break;
577673b11c2aSAndrii Nakryiko 	case BPF_LINK_DETACH:
577773b11c2aSAndrii Nakryiko 		err = link_detach(&attr);
577873b11c2aSAndrii Nakryiko 		break;
5779ef15314aSYiFei Zhu 	case BPF_PROG_BIND_MAP:
5780ef15314aSYiFei Zhu 		err = bpf_prog_bind_map(&attr);
5781ef15314aSYiFei Zhu 		break;
578235f96de0SAndrii Nakryiko 	case BPF_TOKEN_CREATE:
578335f96de0SAndrii Nakryiko 		err = token_create(&attr);
578435f96de0SAndrii Nakryiko 		break;
578599c55f7dSAlexei Starovoitov 	default:
578699c55f7dSAlexei Starovoitov 		err = -EINVAL;
578799c55f7dSAlexei Starovoitov 		break;
578899c55f7dSAlexei Starovoitov 	}
578999c55f7dSAlexei Starovoitov 
579099c55f7dSAlexei Starovoitov 	return err;
579199c55f7dSAlexei Starovoitov }
579279a7f8bdSAlexei Starovoitov 
5793af2ac3e1SAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
5794af2ac3e1SAlexei Starovoitov {
5795af2ac3e1SAlexei Starovoitov 	return __sys_bpf(cmd, USER_BPFPTR(uattr), size);
5796af2ac3e1SAlexei Starovoitov }
5797af2ac3e1SAlexei Starovoitov 
579879a7f8bdSAlexei Starovoitov static bool syscall_prog_is_valid_access(int off, int size,
579979a7f8bdSAlexei Starovoitov 					 enum bpf_access_type type,
580079a7f8bdSAlexei Starovoitov 					 const struct bpf_prog *prog,
580179a7f8bdSAlexei Starovoitov 					 struct bpf_insn_access_aux *info)
580279a7f8bdSAlexei Starovoitov {
580379a7f8bdSAlexei Starovoitov 	if (off < 0 || off >= U16_MAX)
580479a7f8bdSAlexei Starovoitov 		return false;
580579a7f8bdSAlexei Starovoitov 	if (off % size != 0)
580679a7f8bdSAlexei Starovoitov 		return false;
580779a7f8bdSAlexei Starovoitov 	return true;
580879a7f8bdSAlexei Starovoitov }
580979a7f8bdSAlexei Starovoitov 
5810b1d18a75SAlexei Starovoitov BPF_CALL_3(bpf_sys_bpf, int, cmd, union bpf_attr *, attr, u32, attr_size)
581179a7f8bdSAlexei Starovoitov {
5812af2ac3e1SAlexei Starovoitov 	switch (cmd) {
5813af2ac3e1SAlexei Starovoitov 	case BPF_MAP_CREATE:
5814b88df697SBenjamin Tissoires 	case BPF_MAP_DELETE_ELEM:
5815af2ac3e1SAlexei Starovoitov 	case BPF_MAP_UPDATE_ELEM:
5816af2ac3e1SAlexei Starovoitov 	case BPF_MAP_FREEZE:
5817b88df697SBenjamin Tissoires 	case BPF_MAP_GET_FD_BY_ID:
5818af2ac3e1SAlexei Starovoitov 	case BPF_PROG_LOAD:
5819c571bd75SAlexei Starovoitov 	case BPF_BTF_LOAD:
5820b1d18a75SAlexei Starovoitov 	case BPF_LINK_CREATE:
5821b1d18a75SAlexei Starovoitov 	case BPF_RAW_TRACEPOINT_OPEN:
5822af2ac3e1SAlexei Starovoitov 		break;
582386f44fceSAlexei Starovoitov 	default:
582486f44fceSAlexei Starovoitov 		return -EINVAL;
582586f44fceSAlexei Starovoitov 	}
582686f44fceSAlexei Starovoitov 	return __sys_bpf(cmd, KERNEL_BPFPTR(attr), attr_size);
582786f44fceSAlexei Starovoitov }
582886f44fceSAlexei Starovoitov 
58294e4588f1SAlexei Starovoitov 
58304e4588f1SAlexei Starovoitov /* To shut up -Wmissing-prototypes.
58314e4588f1SAlexei Starovoitov  * This function is used by the kernel light skeleton
58324e4588f1SAlexei Starovoitov  * to load bpf programs when modules are loaded or during kernel boot.
58334e4588f1SAlexei Starovoitov  * See tools/lib/bpf/skel_internal.h
58344e4588f1SAlexei Starovoitov  */
58354e4588f1SAlexei Starovoitov int kern_sys_bpf(int cmd, union bpf_attr *attr, unsigned int size);
58364e4588f1SAlexei Starovoitov 
583786f44fceSAlexei Starovoitov int kern_sys_bpf(int cmd, union bpf_attr *attr, unsigned int size)
583886f44fceSAlexei Starovoitov {
583986f44fceSAlexei Starovoitov 	struct bpf_prog * __maybe_unused prog;
584086f44fceSAlexei Starovoitov 	struct bpf_tramp_run_ctx __maybe_unused run_ctx;
584186f44fceSAlexei Starovoitov 
584286f44fceSAlexei Starovoitov 	switch (cmd) {
5843b1d18a75SAlexei Starovoitov #ifdef CONFIG_BPF_JIT /* __bpf_prog_enter_sleepable used by trampoline and JIT */
5844b1d18a75SAlexei Starovoitov 	case BPF_PROG_TEST_RUN:
5845b1d18a75SAlexei Starovoitov 		if (attr->test.data_in || attr->test.data_out ||
5846b1d18a75SAlexei Starovoitov 		    attr->test.ctx_out || attr->test.duration ||
5847b1d18a75SAlexei Starovoitov 		    attr->test.repeat || attr->test.flags)
5848b1d18a75SAlexei Starovoitov 			return -EINVAL;
5849b1d18a75SAlexei Starovoitov 
5850b1d18a75SAlexei Starovoitov 		prog = bpf_prog_get_type(attr->test.prog_fd, BPF_PROG_TYPE_SYSCALL);
5851b1d18a75SAlexei Starovoitov 		if (IS_ERR(prog))
5852b1d18a75SAlexei Starovoitov 			return PTR_ERR(prog);
5853b1d18a75SAlexei Starovoitov 
5854b1d18a75SAlexei Starovoitov 		if (attr->test.ctx_size_in < prog->aux->max_ctx_offset ||
5855b1d18a75SAlexei Starovoitov 		    attr->test.ctx_size_in > U16_MAX) {
5856b1d18a75SAlexei Starovoitov 			bpf_prog_put(prog);
5857b1d18a75SAlexei Starovoitov 			return -EINVAL;
5858b1d18a75SAlexei Starovoitov 		}
5859b1d18a75SAlexei Starovoitov 
5860e384c7b7SKui-Feng Lee 		run_ctx.bpf_cookie = 0;
5861271de525SMartin KaFai Lau 		if (!__bpf_prog_enter_sleepable_recur(prog, &run_ctx)) {
5862b1d18a75SAlexei Starovoitov 			/* recursion detected */
58637645629fSSebastian Andrzej Siewior 			__bpf_prog_exit_sleepable_recur(prog, 0, &run_ctx);
5864b1d18a75SAlexei Starovoitov 			bpf_prog_put(prog);
5865b1d18a75SAlexei Starovoitov 			return -EBUSY;
5866b1d18a75SAlexei Starovoitov 		}
5867b1d18a75SAlexei Starovoitov 		attr->test.retval = bpf_prog_run(prog, (void *) (long) attr->test.ctx_in);
5868271de525SMartin KaFai Lau 		__bpf_prog_exit_sleepable_recur(prog, 0 /* bpf_prog_run does runtime stats */,
5869271de525SMartin KaFai Lau 						&run_ctx);
5870b1d18a75SAlexei Starovoitov 		bpf_prog_put(prog);
5871b1d18a75SAlexei Starovoitov 		return 0;
5872b1d18a75SAlexei Starovoitov #endif
5873af2ac3e1SAlexei Starovoitov 	default:
587486f44fceSAlexei Starovoitov 		return ____bpf_sys_bpf(cmd, attr, size);
587579a7f8bdSAlexei Starovoitov 	}
5876af2ac3e1SAlexei Starovoitov }
587786f44fceSAlexei Starovoitov EXPORT_SYMBOL(kern_sys_bpf);
587879a7f8bdSAlexei Starovoitov 
58793a2daa72SPu Lehui static const struct bpf_func_proto bpf_sys_bpf_proto = {
588079a7f8bdSAlexei Starovoitov 	.func		= bpf_sys_bpf,
588179a7f8bdSAlexei Starovoitov 	.gpl_only	= false,
588279a7f8bdSAlexei Starovoitov 	.ret_type	= RET_INTEGER,
588379a7f8bdSAlexei Starovoitov 	.arg1_type	= ARG_ANYTHING,
5884216e3cd2SHao Luo 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
588579a7f8bdSAlexei Starovoitov 	.arg3_type	= ARG_CONST_SIZE,
588679a7f8bdSAlexei Starovoitov };
588779a7f8bdSAlexei Starovoitov 
588879a7f8bdSAlexei Starovoitov const struct bpf_func_proto * __weak
588979a7f8bdSAlexei Starovoitov tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
589079a7f8bdSAlexei Starovoitov {
5891bbc1d247SAndrii Nakryiko 	return bpf_base_func_proto(func_id, prog);
589279a7f8bdSAlexei Starovoitov }
589379a7f8bdSAlexei Starovoitov 
58943abea089SAlexei Starovoitov BPF_CALL_1(bpf_sys_close, u32, fd)
58953abea089SAlexei Starovoitov {
58963abea089SAlexei Starovoitov 	/* When bpf program calls this helper there should not be
58973abea089SAlexei Starovoitov 	 * an fdget() without matching completed fdput().
58983abea089SAlexei Starovoitov 	 * This helper is allowed in the following callchain only:
58993abea089SAlexei Starovoitov 	 * sys_bpf->prog_test_run->bpf_prog->bpf_sys_close
59003abea089SAlexei Starovoitov 	 */
59013abea089SAlexei Starovoitov 	return close_fd(fd);
59023abea089SAlexei Starovoitov }
59033abea089SAlexei Starovoitov 
59043a2daa72SPu Lehui static const struct bpf_func_proto bpf_sys_close_proto = {
59053abea089SAlexei Starovoitov 	.func		= bpf_sys_close,
59063abea089SAlexei Starovoitov 	.gpl_only	= false,
59073abea089SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
59083abea089SAlexei Starovoitov 	.arg1_type	= ARG_ANYTHING,
59093abea089SAlexei Starovoitov };
59103abea089SAlexei Starovoitov 
5911d6aef08aSKumar Kartikeya Dwivedi BPF_CALL_4(bpf_kallsyms_lookup_name, const char *, name, int, name_sz, int, flags, u64 *, res)
5912d6aef08aSKumar Kartikeya Dwivedi {
5913d6aef08aSKumar Kartikeya Dwivedi 	if (flags)
5914d6aef08aSKumar Kartikeya Dwivedi 		return -EINVAL;
5915d6aef08aSKumar Kartikeya Dwivedi 
5916d6aef08aSKumar Kartikeya Dwivedi 	if (name_sz <= 1 || name[name_sz - 1])
5917d6aef08aSKumar Kartikeya Dwivedi 		return -EINVAL;
5918d6aef08aSKumar Kartikeya Dwivedi 
5919d6aef08aSKumar Kartikeya Dwivedi 	if (!bpf_dump_raw_ok(current_cred()))
5920d6aef08aSKumar Kartikeya Dwivedi 		return -EPERM;
5921d6aef08aSKumar Kartikeya Dwivedi 
5922d6aef08aSKumar Kartikeya Dwivedi 	*res = kallsyms_lookup_name(name);
5923d6aef08aSKumar Kartikeya Dwivedi 	return *res ? 0 : -ENOENT;
5924d6aef08aSKumar Kartikeya Dwivedi }
5925d6aef08aSKumar Kartikeya Dwivedi 
5926dc368e1cSJoanne Koong static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
5927d6aef08aSKumar Kartikeya Dwivedi 	.func		= bpf_kallsyms_lookup_name,
5928d6aef08aSKumar Kartikeya Dwivedi 	.gpl_only	= false,
5929d6aef08aSKumar Kartikeya Dwivedi 	.ret_type	= RET_INTEGER,
5930d6aef08aSKumar Kartikeya Dwivedi 	.arg1_type	= ARG_PTR_TO_MEM,
5931d4efb170SKumar Kartikeya Dwivedi 	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
5932d6aef08aSKumar Kartikeya Dwivedi 	.arg3_type	= ARG_ANYTHING,
5933d6aef08aSKumar Kartikeya Dwivedi 	.arg4_type	= ARG_PTR_TO_LONG,
5934d6aef08aSKumar Kartikeya Dwivedi };
5935d6aef08aSKumar Kartikeya Dwivedi 
593679a7f8bdSAlexei Starovoitov static const struct bpf_func_proto *
593779a7f8bdSAlexei Starovoitov syscall_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
593879a7f8bdSAlexei Starovoitov {
593979a7f8bdSAlexei Starovoitov 	switch (func_id) {
594079a7f8bdSAlexei Starovoitov 	case BPF_FUNC_sys_bpf:
5941bbc1d247SAndrii Nakryiko 		return !bpf_token_capable(prog->aux->token, CAP_PERFMON)
5942bbc1d247SAndrii Nakryiko 		       ? NULL : &bpf_sys_bpf_proto;
59433d78417bSAlexei Starovoitov 	case BPF_FUNC_btf_find_by_name_kind:
59443d78417bSAlexei Starovoitov 		return &bpf_btf_find_by_name_kind_proto;
59453abea089SAlexei Starovoitov 	case BPF_FUNC_sys_close:
59463abea089SAlexei Starovoitov 		return &bpf_sys_close_proto;
5947d6aef08aSKumar Kartikeya Dwivedi 	case BPF_FUNC_kallsyms_lookup_name:
5948d6aef08aSKumar Kartikeya Dwivedi 		return &bpf_kallsyms_lookup_name_proto;
594979a7f8bdSAlexei Starovoitov 	default:
595079a7f8bdSAlexei Starovoitov 		return tracing_prog_func_proto(func_id, prog);
595179a7f8bdSAlexei Starovoitov 	}
595279a7f8bdSAlexei Starovoitov }
595379a7f8bdSAlexei Starovoitov 
595479a7f8bdSAlexei Starovoitov const struct bpf_verifier_ops bpf_syscall_verifier_ops = {
595579a7f8bdSAlexei Starovoitov 	.get_func_proto  = syscall_prog_func_proto,
595679a7f8bdSAlexei Starovoitov 	.is_valid_access = syscall_prog_is_valid_access,
595779a7f8bdSAlexei Starovoitov };
595879a7f8bdSAlexei Starovoitov 
595979a7f8bdSAlexei Starovoitov const struct bpf_prog_ops bpf_syscall_prog_ops = {
596079a7f8bdSAlexei Starovoitov 	.test_run = bpf_prog_test_run_syscall,
596179a7f8bdSAlexei Starovoitov };
59622900005eSYan Zhu 
59632900005eSYan Zhu #ifdef CONFIG_SYSCTL
59642900005eSYan Zhu static int bpf_stats_handler(struct ctl_table *table, int write,
59652900005eSYan Zhu 			     void *buffer, size_t *lenp, loff_t *ppos)
59662900005eSYan Zhu {
59672900005eSYan Zhu 	struct static_key *key = (struct static_key *)table->data;
59682900005eSYan Zhu 	static int saved_val;
59692900005eSYan Zhu 	int val, ret;
59702900005eSYan Zhu 	struct ctl_table tmp = {
59712900005eSYan Zhu 		.data   = &val,
59722900005eSYan Zhu 		.maxlen = sizeof(val),
59732900005eSYan Zhu 		.mode   = table->mode,
59742900005eSYan Zhu 		.extra1 = SYSCTL_ZERO,
59752900005eSYan Zhu 		.extra2 = SYSCTL_ONE,
59762900005eSYan Zhu 	};
59772900005eSYan Zhu 
59782900005eSYan Zhu 	if (write && !capable(CAP_SYS_ADMIN))
59792900005eSYan Zhu 		return -EPERM;
59802900005eSYan Zhu 
59812900005eSYan Zhu 	mutex_lock(&bpf_stats_enabled_mutex);
59822900005eSYan Zhu 	val = saved_val;
59832900005eSYan Zhu 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
59842900005eSYan Zhu 	if (write && !ret && val != saved_val) {
59852900005eSYan Zhu 		if (val)
59862900005eSYan Zhu 			static_key_slow_inc(key);
59872900005eSYan Zhu 		else
59882900005eSYan Zhu 			static_key_slow_dec(key);
59892900005eSYan Zhu 		saved_val = val;
59902900005eSYan Zhu 	}
59912900005eSYan Zhu 	mutex_unlock(&bpf_stats_enabled_mutex);
59922900005eSYan Zhu 	return ret;
59932900005eSYan Zhu }
59942900005eSYan Zhu 
59952900005eSYan Zhu void __weak unpriv_ebpf_notify(int new_state)
59962900005eSYan Zhu {
59972900005eSYan Zhu }
59982900005eSYan Zhu 
59992900005eSYan Zhu static int bpf_unpriv_handler(struct ctl_table *table, int write,
60002900005eSYan Zhu 			      void *buffer, size_t *lenp, loff_t *ppos)
60012900005eSYan Zhu {
60022900005eSYan Zhu 	int ret, unpriv_enable = *(int *)table->data;
60032900005eSYan Zhu 	bool locked_state = unpriv_enable == 1;
60042900005eSYan Zhu 	struct ctl_table tmp = *table;
60052900005eSYan Zhu 
60062900005eSYan Zhu 	if (write && !capable(CAP_SYS_ADMIN))
60072900005eSYan Zhu 		return -EPERM;
60082900005eSYan Zhu 
60092900005eSYan Zhu 	tmp.data = &unpriv_enable;
60102900005eSYan Zhu 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
60112900005eSYan Zhu 	if (write && !ret) {
60122900005eSYan Zhu 		if (locked_state && unpriv_enable != 1)
60132900005eSYan Zhu 			return -EPERM;
60142900005eSYan Zhu 		*(int *)table->data = unpriv_enable;
60152900005eSYan Zhu 	}
60162900005eSYan Zhu 
6017fedf9920SKui-Feng Lee 	if (write)
60182900005eSYan Zhu 		unpriv_ebpf_notify(unpriv_enable);
60192900005eSYan Zhu 
60202900005eSYan Zhu 	return ret;
60212900005eSYan Zhu }
60222900005eSYan Zhu 
60232900005eSYan Zhu static struct ctl_table bpf_syscall_table[] = {
60242900005eSYan Zhu 	{
60252900005eSYan Zhu 		.procname	= "unprivileged_bpf_disabled",
60262900005eSYan Zhu 		.data		= &sysctl_unprivileged_bpf_disabled,
60272900005eSYan Zhu 		.maxlen		= sizeof(sysctl_unprivileged_bpf_disabled),
60282900005eSYan Zhu 		.mode		= 0644,
60292900005eSYan Zhu 		.proc_handler	= bpf_unpriv_handler,
60302900005eSYan Zhu 		.extra1		= SYSCTL_ZERO,
60312900005eSYan Zhu 		.extra2		= SYSCTL_TWO,
60322900005eSYan Zhu 	},
60332900005eSYan Zhu 	{
60342900005eSYan Zhu 		.procname	= "bpf_stats_enabled",
60352900005eSYan Zhu 		.data		= &bpf_stats_enabled_key.key,
60362900005eSYan Zhu 		.mode		= 0644,
60372900005eSYan Zhu 		.proc_handler	= bpf_stats_handler,
60382900005eSYan Zhu 	},
60392900005eSYan Zhu };
60402900005eSYan Zhu 
60412900005eSYan Zhu static int __init bpf_syscall_sysctl_init(void)
60422900005eSYan Zhu {
60432900005eSYan Zhu 	register_sysctl_init("kernel", bpf_syscall_table);
60442900005eSYan Zhu 	return 0;
60452900005eSYan Zhu }
60462900005eSYan Zhu late_initcall(bpf_syscall_sysctl_init);
60472900005eSYan Zhu #endif /* CONFIG_SYSCTL */
6048